From d87f69563ff276ebef71d5bea7f401d51bba9130 Mon Sep 17 00:00:00 2001 From: jacobshandling <61553566+jacobshandling@users.noreply.github.com> Date: Mon, 1 Dec 2025 13:17:42 -0800 Subject: [PATCH] Fix and improve handling of "installed" software scenarios (#36516) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **Related issue:** Resolves #31973 Addresses a few closely related issues around determining the appropriate UI to display for installed software - Pass the inherited host's `softwareUpdatedAt` to the handler responsible for determining the software's "UI display status" so it can calculate whether it is "recently installed", as intended. - In the scenario where the above is _not_ passed in for some reason, default to "installed" ui display status any time the software's status is "installed" - Add a check that ensures the above default "installed" ui status is captured even when `installed_versions` is `null`. This scenario previously returned an "uninstalled" ui display status, which caused this bug initially Screenshot 2025-12-01 at 12 02
29 PM - [x] Changes file added for user-visible changes in `changes/ - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually --- changes/31973-improve-installed-ui-status | 2 ++ .../HostSoftwareLibrary.tsx | 4 ++-- .../details/cards/Software/helpers.tests.ts | 7 +++++++ .../hosts/details/cards/Software/helpers.tsx | 19 +++++++++---------- 4 files changed, 20 insertions(+), 12 deletions(-) create mode 100644 changes/31973-improve-installed-ui-status diff --git a/changes/31973-improve-installed-ui-status b/changes/31973-improve-installed-ui-status new file mode 100644 index 0000000000..1b78189fa3 --- /dev/null +++ b/changes/31973-improve-installed-ui-status @@ -0,0 +1,2 @@ +- Improved handling of softawre install statuses in the UI, fixing a bug where "installed" software + sometimes showed up as "uninstalled" when certain other pieces of data were not also present diff --git a/frontend/pages/hosts/details/cards/HostSoftwareLibrary/HostSoftwareLibrary.tsx b/frontend/pages/hosts/details/cards/HostSoftwareLibrary/HostSoftwareLibrary.tsx index fcfb37d60c..64d269184b 100644 --- a/frontend/pages/hosts/details/cards/HostSoftwareLibrary/HostSoftwareLibrary.tsx +++ b/frontend/pages/hosts/details/cards/HostSoftwareLibrary/HostSoftwareLibrary.tsx @@ -174,9 +174,9 @@ const HostSoftwareLibrary = ({ if (!hostSoftwareLibraryRes) return []; return hostSoftwareLibraryRes.software.map((software) => ({ ...software, - ui_status: getUiStatus(software, isHostOnline), + ui_status: getUiStatus(software, isHostOnline, softwareUpdatedAt), })); - }, [hostSoftwareLibraryRes, isHostOnline]); + }, [hostSoftwareLibraryRes, isHostOnline, softwareUpdatedAt]); const pendingSoftwareSetRef = useRef>(new Set()); // Track for polling const pollingTimeoutIdRef = useRef(null); diff --git a/frontend/pages/hosts/details/cards/Software/helpers.tests.ts b/frontend/pages/hosts/details/cards/Software/helpers.tests.ts index 585a9f2c57..a1cf60010b 100644 --- a/frontend/pages/hosts/details/cards/Software/helpers.tests.ts +++ b/frontend/pages/hosts/details/cards/Software/helpers.tests.ts @@ -309,6 +309,13 @@ describe("getUiStatus", () => { }); expect(getUiStatus(sw, true)).toBe("installed"); }); + it("returns 'installed' for regular package, no installed versions present", () => { + const sw = createMockHostSoftware({ + status: "installed", + installed_versions: null, + }); + expect(getUiStatus(sw, true)).toBe("installed"); + }); it("returns 'installed' for regular package, installed version higher than library version", () => { const sw = createMockHostSoftware({ diff --git a/frontend/pages/hosts/details/cards/Software/helpers.tsx b/frontend/pages/hosts/details/cards/Software/helpers.tsx index e53e39ed1a..a780219b48 100644 --- a/frontend/pages/hosts/details/cards/Software/helpers.tsx +++ b/frontend/pages/hosts/details/cards/Software/helpers.tsx @@ -249,7 +249,7 @@ export const getUiStatus = ( } // **Recently_uninstalled check comes BEFORE update_available** - if (software.status === null && lastUninstallDate && hostSoftwareUpdatedAt) { + if (status === null && lastUninstallDate && hostSoftwareUpdatedAt) { const newerDate = getNewerDate(hostSoftwareUpdatedAt, lastUninstallDate); if (newerDate === lastUninstallDate || recentUserActionDetected) { return "recently_uninstalled"; @@ -276,19 +276,18 @@ export const getUiStatus = ( } // 6. Recently installed (not an update) - if ( - software.status === "installed" && - lastInstallDate && - hostSoftwareUpdatedAt - ) { - const newerDate = getNewerDate(hostSoftwareUpdatedAt, lastInstallDate); - if (newerDate === lastInstallDate || recentUserActionDetected) { - return "recently_installed"; + if (status === "installed") { + if (lastInstallDate && hostSoftwareUpdatedAt) { + const newerDate = getNewerDate(hostSoftwareUpdatedAt, lastInstallDate); + if (newerDate === lastInstallDate || recentUserActionDetected) { + return "recently_installed"; + } } + return "installed"; } // 7. Tarballs edge case - if (software.source === "tgz_packages" && software.status === "installed") { + if (source === "tgz_packages" && status === "installed") { return "installed"; }