Add last used column to host details software table (#5681)

This commit is contained in:
Luke Heath 2022-05-12 11:34:46 -05:00 committed by GitHub
parent ba820384f9
commit a6b2d2413a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 120 additions and 55 deletions

View file

@ -0,0 +1 @@
- Add last used column to host details' software table for Mac OS hosts

View file

@ -596,6 +596,7 @@ const HostDetailsPage = ({
isLoading={isLoadingHost}
software={hostSoftware}
softwareInventoryEnabled={hostSettings?.enable_software_inventory}
deviceType={host?.platform === "darwin" ? "macos" : ""}
/>
</TabPanel>
<TabPanel>

View file

@ -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 && (
<TableContainer
columns={tableHeaders}
data={tableSoftware}
filters={filters}
isLoading={isLoading}
defaultSortHeader={"name"}
defaultSortDirection={"asc"}
inputPlaceHolder={
"Search software by name or vulnerabilities (CVEs)"
}
onQueryChange={onQueryChange}
resultsTitle={"software items"}
emptyComponent={EmptySoftwareSearch}
showMarkAllPages={false}
isAllPagesSelected={false}
searchable
customControl={renderVulnFilterDropdown}
isClientSidePagination
isClientSideFilter
highlightOnHover
/>
<div className={deviceType || ""}>
<TableContainer
columns={tableHeaders}
data={tableSoftware}
filters={filters}
isLoading={isLoading}
defaultSortHeader={"name"}
defaultSortDirection={"asc"}
inputPlaceHolder={
"Search software by name or vulnerabilities ( CVEs)"
}
onQueryChange={onQueryChange}
resultsTitle={"software items"}
emptyComponent={EmptySoftwareSearch}
showMarkAllPages={false}
isAllPagesSelected={false}
searchable
customControl={renderVulnFilterDropdown}
isClientSidePagination
isClientSideFilter
highlightOnHover
/>
</div>
)}
</>
) : (

View file

@ -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) => (
// <HeaderCell
// value={cellProps.column.title}
// isSortedDesc={cellProps.column.isSortedDesc}
// />
// ),
// accessor: "last_opened_at",
// Cell: (cellProps) => {
// const lastUsed = isNaN(Date.parse(cellProps.cell.value))
// ? "Unavailable"
// : `${distanceInWordsToNow(Date.parse(cellProps.cell.value))} ago`;
// return (
// <span
// className={
// lastUsed === "Unavailable"
// ? "software-last-used-muted"
// : "software-last-used"
// }
// >
// {lastUsed}
// </span>
// );
// },
// sortType: "dateStrings",
// },
{
title: "Last used",
Header: (cellProps) => (
<HeaderCell
value={cellProps.column.title}
isSortedDesc={cellProps.column.isSortedDesc}
/>
),
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 (
<>
<span
className={`last-used ${
lastUsed === "Unavailable" ? "text-muted" : ""
}`}
data-tip
data-for={`last_used__${cellProps.row.index}`}
data-tip-disable={hasLastUsed}
>
{lastUsed}
</span>
<ReactTooltip
place="top"
type="dark"
effect="solid"
backgroundColor="#3e4771"
id={`last_used__${cellProps.row.index}`}
className="last_used_tooltip"
data-tip-disable={hasLastUsed}
data-html
>
<span className={`last_used tooltip__tooltip-text`}>
Last used information <br />
is only available for the <br />
Application (macOS) <br />
software type.
</span>
</ReactTooltip>
</>
);
},
sortType: "dateStrings",
},
{
title: "",
Header: "",

View file

@ -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;
}
}
}
}
}

View file

@ -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)