diff --git a/changes/issue-3399-last-used-column b/changes/issue-3399-last-used-column new file mode 100644 index 0000000000..52f12251e7 --- /dev/null +++ b/changes/issue-3399-last-used-column @@ -0,0 +1 @@ +- Add last used column to host details' software table for Mac OS hosts diff --git a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx index ed4846ad9f..2930f12228 100644 --- a/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx +++ b/frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx @@ -596,6 +596,7 @@ const HostDetailsPage = ({ isLoading={isLoadingHost} software={hostSoftware} softwareInventoryEnabled={hostSettings?.enable_software_inventory} + deviceType={host?.platform === "darwin" ? "macos" : ""} /> diff --git a/frontend/pages/hosts/details/cards/Software/Software.tsx b/frontend/pages/hosts/details/cards/Software/Software.tsx index 8256d3c296..9229c9516b 100644 --- a/frontend/pages/hosts/details/cards/Software/Software.tsx +++ b/frontend/pages/hosts/details/cards/Software/Software.tsx @@ -23,6 +23,7 @@ interface ISoftwareTableProps { isLoading: boolean; software: ISoftware[]; deviceUser?: boolean; + deviceType?: string; softwareInventoryEnabled?: boolean; } @@ -30,6 +31,7 @@ const SoftwareTable = ({ isLoading, software, deviceUser, + deviceType, softwareInventoryEnabled, }: ISoftwareTableProps): JSX.Element => { const tableSoftware: ITableSoftware[] = software.map((s) => { @@ -104,27 +106,29 @@ const SoftwareTable = ({ /> )} {software && ( - +
+ +
)} ) : ( diff --git a/frontend/pages/hosts/details/cards/Software/SoftwareTableConfig.tsx b/frontend/pages/hosts/details/cards/Software/SoftwareTableConfig.tsx index 3a7fb2f11d..995d3614d7 100644 --- a/frontend/pages/hosts/details/cards/Software/SoftwareTableConfig.tsx +++ b/frontend/pages/hosts/details/cards/Software/SoftwareTableConfig.tsx @@ -2,8 +2,7 @@ import React from "react"; import { Link } from "react-router"; import ReactTooltip from "react-tooltip"; -// TODO: Enable after backend has been updated to provide last_opened_at -// import distanceInWordsToNow from "date-fns/distance_in_words_to_now"; +import { formatDistanceToNow } from "date-fns"; import { ISoftware } from "interfaces/software"; @@ -25,6 +24,7 @@ interface ICellProps { }; row: { original: ISoftware; + index: number; }; } @@ -40,6 +40,12 @@ interface IVulnCellProps extends ICellProps { }; } +interface ILastUsedCellProps extends ICellProps { + cell: { + value: string; + }; +} + interface IDataColumn { title: string; Header: ((props: IHeaderProps) => JSX.Element) | string; @@ -207,34 +213,54 @@ const generateSoftwareTableHeaders = (deviceUser = false): IDataColumn[] => { ); }, }, - // TODO: Enable after backend has been updated to provide last_opened_at - // { - // title: "Last used", - // Header: (cellProps) => ( - // - // ), - // accessor: "last_opened_at", - // Cell: (cellProps) => { - // const lastUsed = isNaN(Date.parse(cellProps.cell.value)) - // ? "Unavailable" - // : `${distanceInWordsToNow(Date.parse(cellProps.cell.value))} ago`; - // return ( - // - // {lastUsed} - // - // ); - // }, - // sortType: "dateStrings", - // }, + { + title: "Last used", + Header: (cellProps) => ( + + ), + accessor: "last_opened_at", + Cell: (cellProps: ILastUsedCellProps): JSX.Element => { + const lastUsed = cellProps.cell.value + ? `${formatDistanceToNow(Date.parse(cellProps.cell.value))} ago` + : "Unavailable"; + const hasLastUsed = lastUsed !== "Unavailable"; + return ( + <> + + {lastUsed} + + + + Last used information
+ is only available for the
+ Application (macOS)
+ software type. +
+
+ + ); + }, + sortType: "dateStrings", + }, { title: "", Header: "", diff --git a/frontend/pages/hosts/details/cards/Software/_styles.scss b/frontend/pages/hosts/details/cards/Software/_styles.scss index a191990a24..8da70f3558 100644 --- a/frontend/pages/hosts/details/cards/Software/_styles.scss +++ b/frontend/pages/hosts/details/cards/Software/_styles.scss @@ -1,4 +1,7 @@ .section--software { + .text-muted { + color: $ui-fleet-black-50; + } .table-container__header-left { .controls { // vulnerable software dropdown filter @@ -36,13 +39,16 @@ } .data-table-block { + .last_used_tooltip { + text-align: center; + } .data-table__table { thead { .name__header { width: $col-md; } .version__header { - width: 0px; + width: $col-sm; } .source__header { display: none; @@ -51,6 +57,9 @@ .hosts_count__header { border-right: 0; } + .last_opened_at__header { + display: none; + } @media (min-width: $break-990) { .version__header { width: $col-md; @@ -86,6 +95,9 @@ } } } + .last_opened_at__cell { + display: none; + } @media (min-width: $break-1400) { .source__cell { display: table-cell; @@ -131,7 +143,28 @@ } } } - .text-muted { - color: $ui-fleet-black-50; + + // Only show this column to macos users + .macos .data-table-block .data-table__table { + @media (min-width: $break-990) { + thead .version__header { + width: $col-sm; + } + } + @media (min-width: $break-1400) { + thead { + .vulnerabilities__header { + width: $col-md; + } + .last_opened_at__header { + display: table-cell; + } + } + tbody { + .last_opened_at__cell { + display: table-cell; + } + } + } } } diff --git a/frontend/styles/var/tables.scss b/frontend/styles/var/tables.scss index 22a3e61eaf..c03d8de21f 100644 --- a/frontend/styles/var/tables.scss +++ b/frontend/styles/var/tables.scss @@ -1,3 +1,3 @@ -$col-sm: 0px; // column size will "hug" its contents +$col-sm: 62px; // column size will "hug" its contents $col-md: 202px; // column size not including 24px padding on left and right (total width is 250px) $col-lg: 352px; // column size not including 24px padding on left and right (total width is 250px)