From 07c992c1781ab3d2b23705a757c965cfc22478dd Mon Sep 17 00:00:00 2001 From: Sarah Gillespie <73313222+gillespi314@users.noreply.github.com> Date: Tue, 21 May 2024 11:49:37 -0500 Subject: [PATCH] Fix unreleased UI bugs in device details software tab (#19178) --- .../DeviceUserPage/DeviceUserPage.tests.tsx | 4 +-- .../details/DeviceUserPage/DeviceUserPage.tsx | 35 ++++++++++++------- .../Software/DeviceSoftwareTableConfig.tsx | 2 -- .../HostSoftwareTable/HostSoftwareTable.tsx | 12 ++++--- .../hosts/details/cards/Software/Software.tsx | 6 ++-- frontend/utilities/endpoints.ts | 2 +- 6 files changed, 36 insertions(+), 25 deletions(-) diff --git a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tests.tsx b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tests.tsx index facfb4b2c1..f1f581bd90 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tests.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tests.tsx @@ -33,7 +33,7 @@ const mockLocation = { }; describe("Device User Page", () => { - it("renders the software empty message if the device has no software", async () => { + it("hides the software tab if the device has no software", async () => { const render = createCustomRenderer({ withBackendMock: true, }); @@ -50,7 +50,7 @@ describe("Device User Page", () => { // waiting for the device data to render await screen.findByText("About"); - await user.click(screen.getByRole("tab", { name: "Software" })); + expect(screen.queryByText(/Software/)).not.toBeInTheDocument(); // TODO: Fix this to the new copy // expect(screen.getByText("No software detected")).toBeInTheDocument(); diff --git a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx index c86d059d4d..f92209b82e 100644 --- a/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx +++ b/frontend/pages/hosts/details/DeviceUserPage/DeviceUserPage.tsx @@ -333,6 +333,14 @@ const DeviceUserPage = ({ const findSelectedTab = (pathname: string) => findIndex(tabPaths, (x) => x.startsWith(pathname.split("?")[0])); + // TODO: This is a temporary fix that conditionally shows the new software tab depending on + // whether software items returned in the device details response (legacy endpoint). + // If the tab is selected, we call the new host software endpoint and display those results. + // Software in the legacy response is only being used as a proxy for `iseSoftwareEnabled`. + // Ideally we should be checking the config for whether software is enabled to show/hide the tab, + // but it isn't available via device token authenticated API. And we need better specified empty states. + const isSoftwareEnabled = !!host?.software.length; + return (
{!host || isLoadingHost ? ( @@ -386,7 +394,7 @@ const DeviceUserPage = ({ > Details - Software + {isSoftwareEnabled && Software} {isPremiumTier && (
@@ -405,17 +413,20 @@ const DeviceUserPage = ({ munki={deviceMacAdminsData?.munki} /> - - - + {isSoftwareEnabled && ( + + + + )} {isPremiumTier && ( { return DICT[source] || "Unknown"; }; -// interface ISoftwareTableHeadersProps {} - export const generateSoftwareTableData = ( software: IHostSoftware[] ): IHostSoftware[] => { diff --git a/frontend/pages/hosts/details/cards/Software/HostSoftwareTable/HostSoftwareTable.tsx b/frontend/pages/hosts/details/cards/Software/HostSoftwareTable/HostSoftwareTable.tsx index caccee69b5..91a504ba66 100644 --- a/frontend/pages/hosts/details/cards/Software/HostSoftwareTable/HostSoftwareTable.tsx +++ b/frontend/pages/hosts/details/cards/Software/HostSoftwareTable/HostSoftwareTable.tsx @@ -16,7 +16,7 @@ const baseClass = "host-software-table"; interface IHostSoftwareTableProps { tableConfig: any; // TODO: type - data: IGetHostSoftwareResponse | IGetDeviceSoftwareResponse; + data?: IGetHostSoftwareResponse | IGetDeviceSoftwareResponse; isLoading: boolean; router: InjectedRouter; sortHeader: string; @@ -26,7 +26,7 @@ interface IHostSoftwareTableProps { pagePath: string; } -const SoftwareCount = (count: number) => { +const SoftwareCount = ({ count }: { count: number }) => { return (
@@ -107,8 +107,9 @@ const HostSoftwareTable = ({ ); const memoizedSoftwareCount = useCallback(() => { - return SoftwareCount(data.count || data.software.length || 0); - }, [data.count, data.software.length]); + const count = data?.count || data?.software.length || 0; + return ; + }, [data?.count, data?.software.length]); const memoizedEmptyComponent = useCallback(() => { return ; @@ -120,12 +121,13 @@ const HostSoftwareTable = ({ renderCount={memoizedSoftwareCount} resultsTitle="software items" columnConfigs={tableConfig} - data={data.software} + data={data?.software || []} isLoading={isLoading} defaultSortHeader={sortHeader} defaultSortDirection={sortDirection} defaultSearchQuery={searchQuery} defaultPageIndex={page} + disableNextPage={data?.meta.has_next_results === false} pageSize={DEFAULT_PAGE_SIZE} inputPlaceHolder="Search by name" onQueryChange={onQueryChange} diff --git a/frontend/pages/hosts/details/cards/Software/Software.tsx b/frontend/pages/hosts/details/cards/Software/Software.tsx index 1b92a1b6fa..df562a3dda 100644 --- a/frontend/pages/hosts/details/cards/Software/Software.tsx +++ b/frontend/pages/hosts/details/cards/Software/Software.tsx @@ -122,7 +122,7 @@ const SoftwareCard = ({ }, { ...DEFAULT_USE_QUERY_OPTIONS, - enabled: isSoftwareEnabled && !isMyDevicePage, + enabled: isSoftwareEnabled && !isMyDevicePage, // if disabled, we'll always show a generic "No software detected" message keepPreviousData: true, staleTime: 7000, } @@ -250,8 +250,8 @@ const SoftwareCard = ({ ) : ( <> - {(isError || !data) && } - {!isError && data && ( + {isError && } + {!isError && ( - `/${API_VERSION}/fleet/devices/${token}/software`, + `/${API_VERSION}/fleet/device/${token}/software`, DEVICE_USER_RESET_ENCRYPTION_KEY: (token: string): string => { return `/${API_VERSION}/fleet/device/${token}/rotate_encryption_key`; },