From 4f32ba32357d3fc5361b147a2c880123cfad22bb Mon Sep 17 00:00:00 2001 From: RachelElysia <71795832+RachelElysia@users.noreply.github.com> Date: Tue, 13 Feb 2024 13:24:57 -0500 Subject: [PATCH] Vuln FE Iteration: Free columns, clickable rows, export host call update (#16749) --- .../SoftwareOSTable/SoftwareOSTable.tsx | 2 ++ .../SoftwareOSDetailsPage.tsx | 14 +++++--- .../SoftwareTitleDetailsPage.tsx | 2 ++ .../SoftwareTitleDetailsTable.tsx | 28 +++++++++++++++- .../SoftwareTable/SoftwareTable.tsx | 5 +++ .../SoftwareTitles/SoftwareTitles.tsx | 5 +++ .../SoftwareVersionDetailsPage.tsx | 21 ++++++++---- .../SoftwareVulnerabilities.tsx | 2 ++ .../SoftwareVulnerabilitiesTable.tsx | 2 ++ .../SoftwareVulnOSVersions.tsx | 2 ++ .../SoftwareVulnSoftwareVersions.tsx | 2 ++ .../SoftwareVulnSummary.tsx | 2 ++ .../SoftwareVulnerabilityDetailsPage.tsx | 2 ++ .../SoftwareDetailsSummary.tsx | 6 ++++ .../SoftwareVulnerabilitiesTable.tsx | 33 +++++++++++++++++++ .../SoftwareVulnerabilitiesTableConfig.tsx | 13 +++++--- frontend/services/entities/hosts.ts | 2 ++ frontend/utilities/url/index.ts | 2 +- 18 files changed, 128 insertions(+), 17 deletions(-) diff --git a/frontend/pages/SoftwarePage/SoftwareOS/SoftwareOSTable/SoftwareOSTable.tsx b/frontend/pages/SoftwarePage/SoftwareOS/SoftwareOSTable/SoftwareOSTable.tsx index 4d24e10f88..064d9b75ea 100644 --- a/frontend/pages/SoftwarePage/SoftwareOS/SoftwareOSTable/SoftwareOSTable.tsx +++ b/frontend/pages/SoftwarePage/SoftwareOS/SoftwareOSTable/SoftwareOSTable.tsx @@ -1,3 +1,5 @@ +/** software/os OS tab */ + import React, { useCallback, useContext, useMemo } from "react"; import { InjectedRouter } from "react-router"; import { Row } from "react-table"; diff --git a/frontend/pages/SoftwarePage/SoftwareOSDetailsPage/SoftwareOSDetailsPage.tsx b/frontend/pages/SoftwarePage/SoftwareOSDetailsPage/SoftwareOSDetailsPage.tsx index 45182ead53..02266622ef 100644 --- a/frontend/pages/SoftwarePage/SoftwareOSDetailsPage/SoftwareOSDetailsPage.tsx +++ b/frontend/pages/SoftwarePage/SoftwareOSDetailsPage/SoftwareOSDetailsPage.tsx @@ -1,6 +1,8 @@ +/** software/os/:id */ + import React from "react"; import { useQuery } from "react-query"; -import { RouteComponentProps } from "react-router/lib/Router"; +import { InjectedRouter } from "react-router"; import osVersionsAPI, { IOSVersionResponse, @@ -42,13 +44,14 @@ interface ISoftwareOSDetailsRouteParams { id: string; } -type ISoftwareOSDetailsPageProps = RouteComponentProps< - undefined, - ISoftwareOSDetailsRouteParams ->; +interface ISoftwareOSDetailsPageProps { + routeParams: ISoftwareOSDetailsRouteParams; + router: InjectedRouter; +} const SoftwareOSDetailsPage = ({ routeParams, + router, }: ISoftwareOSDetailsPageProps) => { const osVersionIdFromURL = parseInt(routeParams.id, 10); @@ -82,6 +85,7 @@ const SoftwareOSDetailsPage = ({ data={osVersionDetails.vulnerabilities} itemName="version" isLoading={isLoading} + router={router} /> ); }; diff --git a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareTitleDetailsPage.tsx b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareTitleDetailsPage.tsx index 578ca8428f..231cb316bc 100644 --- a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareTitleDetailsPage.tsx +++ b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareTitleDetailsPage.tsx @@ -1,3 +1,5 @@ +/** software/titles/:id */ + import React from "react"; import { RouteComponentProps } from "react-router"; import { useQuery } from "react-query"; diff --git a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareTitleDetailsTable/SoftwareTitleDetailsTable.tsx b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareTitleDetailsTable/SoftwareTitleDetailsTable.tsx index 5f8933fa8a..d79e5964a2 100644 --- a/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareTitleDetailsTable/SoftwareTitleDetailsTable.tsx +++ b/frontend/pages/SoftwarePage/SoftwareTitleDetailsPage/SoftwareTitleDetailsTable/SoftwareTitleDetailsTable.tsx @@ -1,8 +1,13 @@ +/** software/titles/:id > Versions section */ + import React, { useMemo } from "react"; import { InjectedRouter } from "react-router"; +import { Row } from "react-table"; +import PATHS from "router/paths"; import { ISoftwareTitleVersion } from "interfaces/software"; import { GITHUB_NEW_ISSUE_LINK } from "utilities/constants"; +import { buildQueryStringFromParams } from "utilities/url"; import TableContainer from "components/TableContainer"; import EmptyTable from "components/EmptyTable"; @@ -39,11 +44,31 @@ interface ISoftwareTitleDetailsTableProps { isLoading: boolean; } +interface IRowProps extends Row { + original: { + id?: number; + }; +} + const SoftwareTitleDetailsTable = ({ router, data, isLoading, }: ISoftwareTitleDetailsTableProps) => { + const handleRowSelect = (row: IRowProps) => { + const hostsBySoftwareParams = { + software_version_id: row.original.id, + }; + + const path = hostsBySoftwareParams + ? `${PATHS.MANAGE_HOSTS}?${buildQueryStringFromParams( + hostsBySoftwareParams + )}` + : PATHS.MANAGE_HOSTS; + + router.push(path); + }; + const softwareTableHeaders = useMemo( () => generateSoftwareTitleDetailsTableConfig(router), [router] @@ -62,7 +87,8 @@ const SoftwareTitleDetailsTable = ({ defaultSortHeader={DEFAULT_SORT_HEADER} defaultSortDirection={DEFAULT_SORT_DIRECTION} disablePagination - // TODO: add row click handler + disableMultiRowSelect + onSelectSingleRow={handleRowSelect} /> ); }; diff --git a/frontend/pages/SoftwarePage/SoftwareTitles/SoftwareTable/SoftwareTable.tsx b/frontend/pages/SoftwarePage/SoftwareTitles/SoftwareTable/SoftwareTable.tsx index 47686816f5..65abb340b6 100644 --- a/frontend/pages/SoftwarePage/SoftwareTitles/SoftwareTable/SoftwareTable.tsx +++ b/frontend/pages/SoftwarePage/SoftwareTitles/SoftwareTable/SoftwareTable.tsx @@ -1,3 +1,8 @@ +/** +software/titles Software tab > Table +software/versions Software tab > Table (version toggle on) +*/ + import React, { useCallback, useContext, useMemo } from "react"; import { InjectedRouter } from "react-router"; import { Row } from "react-table"; diff --git a/frontend/pages/SoftwarePage/SoftwareTitles/SoftwareTitles.tsx b/frontend/pages/SoftwarePage/SoftwareTitles/SoftwareTitles.tsx index 1e90194418..ee67530912 100644 --- a/frontend/pages/SoftwarePage/SoftwareTitles/SoftwareTitles.tsx +++ b/frontend/pages/SoftwarePage/SoftwareTitles/SoftwareTitles.tsx @@ -1,3 +1,8 @@ +/** + software/titles Software tab + software/versions Software tab (version toggle on) + */ + import React from "react"; import { InjectedRouter } from "react-router"; import { useQuery } from "react-query"; diff --git a/frontend/pages/SoftwarePage/SoftwareVersionDetailsPage/SoftwareVersionDetailsPage.tsx b/frontend/pages/SoftwarePage/SoftwareVersionDetailsPage/SoftwareVersionDetailsPage.tsx index afaa560b15..354bb4d6fd 100644 --- a/frontend/pages/SoftwarePage/SoftwareVersionDetailsPage/SoftwareVersionDetailsPage.tsx +++ b/frontend/pages/SoftwarePage/SoftwareVersionDetailsPage/SoftwareVersionDetailsPage.tsx @@ -1,6 +1,8 @@ +/** software/versions/:id */ + import React from "react"; import { useQuery } from "react-query"; -import { RouteComponentProps } from "react-router"; +import { InjectedRouter } from "react-router"; import softwareAPI, { ISoftwareVersionResponse, @@ -22,17 +24,22 @@ const baseClass = "software-version-details-page"; interface ISoftwareVersionDetailsRouteParams { id: string; + team_id?: string; } -type ISoftwareTitleDetailsPageProps = RouteComponentProps< - undefined, - ISoftwareVersionDetailsRouteParams ->; +interface ISoftwareOSDetailsPageProps { + routeParams: ISoftwareVersionDetailsRouteParams; + router: InjectedRouter; +} const SoftwareVersionDetailsPage = ({ routeParams, -}: ISoftwareTitleDetailsPageProps) => { + router, +}: ISoftwareOSDetailsPageProps) => { const versionId = parseInt(routeParams.id, 10); + const teamId = routeParams.team_id + ? parseInt(routeParams.team_id, 10) + : undefined; const { data: softwareVersion, @@ -90,6 +97,8 @@ const SoftwareVersionDetailsPage = ({ data={softwareVersion.vulnerabilities ?? []} itemName="software item" isLoading={isSoftwareVersionLoading} + router={router} + teamId={teamId} /> diff --git a/frontend/pages/SoftwarePage/SoftwareVulnerabilities/SoftwareVulnerabilities.tsx b/frontend/pages/SoftwarePage/SoftwareVulnerabilities/SoftwareVulnerabilities.tsx index e995ba8d5f..946e4fe1db 100644 --- a/frontend/pages/SoftwarePage/SoftwareVulnerabilities/SoftwareVulnerabilities.tsx +++ b/frontend/pages/SoftwarePage/SoftwareVulnerabilities/SoftwareVulnerabilities.tsx @@ -1,3 +1,5 @@ +/** software/vulnerabilities Vulnerabilities tab */ + import React from "react"; import { useQuery } from "react-query"; import { InjectedRouter } from "react-router"; diff --git a/frontend/pages/SoftwarePage/SoftwareVulnerabilities/SoftwareVulnerabilitiesTable/SoftwareVulnerabilitiesTable.tsx b/frontend/pages/SoftwarePage/SoftwareVulnerabilities/SoftwareVulnerabilitiesTable/SoftwareVulnerabilitiesTable.tsx index a7bd8f19b4..547a9b4a1d 100644 --- a/frontend/pages/SoftwarePage/SoftwareVulnerabilities/SoftwareVulnerabilitiesTable/SoftwareVulnerabilitiesTable.tsx +++ b/frontend/pages/SoftwarePage/SoftwareVulnerabilities/SoftwareVulnerabilitiesTable/SoftwareVulnerabilitiesTable.tsx @@ -1,3 +1,5 @@ +/** software/vulnerabilities Vulnerabilities tab > Table */ + import React, { useCallback, useContext, useMemo } from "react"; import { InjectedRouter } from "react-router"; import { Row } from "react-table"; diff --git a/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/SoftwareVulnOSVersions/SoftwareVulnOSVersions.tsx b/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/SoftwareVulnOSVersions/SoftwareVulnOSVersions.tsx index e18fe84096..599ab0f394 100644 --- a/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/SoftwareVulnOSVersions/SoftwareVulnOSVersions.tsx +++ b/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/SoftwareVulnOSVersions/SoftwareVulnOSVersions.tsx @@ -1,3 +1,5 @@ +/** software/vulnerabilities/:cve > Vulnerable OS section */ + import React, { useCallback, useMemo } from "react"; import { InjectedRouter } from "react-router"; diff --git a/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/SoftwareVulnSoftwareVersions/SoftwareVulnSoftwareVersions.tsx b/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/SoftwareVulnSoftwareVersions/SoftwareVulnSoftwareVersions.tsx index 3f4b0d36b1..ffef1aeff3 100644 --- a/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/SoftwareVulnSoftwareVersions/SoftwareVulnSoftwareVersions.tsx +++ b/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/SoftwareVulnSoftwareVersions/SoftwareVulnSoftwareVersions.tsx @@ -1,3 +1,5 @@ +/** software/vulnerabilities/:cve > Vulnerable software section */ + import React, { useCallback, useMemo } from "react"; import { InjectedRouter } from "react-router"; diff --git a/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/SoftwareVulnSummary/SoftwareVulnSummary.tsx b/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/SoftwareVulnSummary/SoftwareVulnSummary.tsx index 937bcdd075..cb7d2fe9db 100644 --- a/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/SoftwareVulnSummary/SoftwareVulnSummary.tsx +++ b/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/SoftwareVulnSummary/SoftwareVulnSummary.tsx @@ -1,3 +1,5 @@ +/** software/vulnerabilities/:cve > Summary section */ + import React from "react"; import { IVulnerability } from "interfaces/vulnerability"; diff --git a/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/SoftwareVulnerabilityDetailsPage.tsx b/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/SoftwareVulnerabilityDetailsPage.tsx index f47f06800a..f54576f42b 100644 --- a/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/SoftwareVulnerabilityDetailsPage.tsx +++ b/frontend/pages/SoftwarePage/SoftwareVulnerabilityDetailsPage/SoftwareVulnerabilityDetailsPage.tsx @@ -1,3 +1,5 @@ +/** software/vulnerabilities/:cve */ + import React, { useContext } from "react"; import { useQuery } from "react-query"; import { RouteComponentProps } from "react-router"; diff --git a/frontend/pages/SoftwarePage/components/SoftwareDetailsSummary/SoftwareDetailsSummary.tsx b/frontend/pages/SoftwarePage/components/SoftwareDetailsSummary/SoftwareDetailsSummary.tsx index 4c47dab21b..f35332c84a 100644 --- a/frontend/pages/SoftwarePage/components/SoftwareDetailsSummary/SoftwareDetailsSummary.tsx +++ b/frontend/pages/SoftwarePage/components/SoftwareDetailsSummary/SoftwareDetailsSummary.tsx @@ -1,3 +1,9 @@ +/** +software/titles/:id > Top section +software/versions/:id > Top section +software/os/:id > Top section +*/ + import React from "react"; import { QueryParams } from "utilities/url"; diff --git a/frontend/pages/SoftwarePage/components/SoftwareVulnerabilitiesTable/SoftwareVulnerabilitiesTable.tsx b/frontend/pages/SoftwarePage/components/SoftwareVulnerabilitiesTable/SoftwareVulnerabilitiesTable.tsx index 4f85a1bcff..44938f65ef 100644 --- a/frontend/pages/SoftwarePage/components/SoftwareVulnerabilitiesTable/SoftwareVulnerabilitiesTable.tsx +++ b/frontend/pages/SoftwarePage/components/SoftwareVulnerabilitiesTable/SoftwareVulnerabilitiesTable.tsx @@ -1,9 +1,18 @@ +/** +software/versions/:id > Vulnerabilities table +software/os/:id > Vulnerabilities table +*/ + import React, { useContext, useMemo } from "react"; import classnames from "classnames"; +import { InjectedRouter } from "react-router"; +import { Row } from "react-table"; +import PATHS from "router/paths"; import { AppContext } from "context/app"; import { ISoftwareVulnerability } from "interfaces/software"; import { GITHUB_NEW_ISSUE_LINK } from "utilities/constants"; +import { buildQueryStringFromParams } from "utilities/url"; import TableContainer from "components/TableContainer"; import EmptyTable from "components/EmptyTable"; @@ -41,6 +50,14 @@ interface ISoftwareVulnerabilitiesTableProps { itemName: string; isLoading: boolean; className?: string; + router: InjectedRouter; + teamId?: number; +} + +interface IRowProps extends Row { + original: { + cve?: string; + }; } const SoftwareVulnerabilitiesTable = ({ @@ -48,11 +65,25 @@ const SoftwareVulnerabilitiesTable = ({ itemName, isLoading, className, + router, + teamId, }: ISoftwareVulnerabilitiesTableProps) => { const { isPremiumTier, isSandboxMode } = useContext(AppContext); const classNames = classnames(baseClass, className); + const handleRowSelect = (row: IRowProps) => { + const hostsBySoftwareParams = { cve: row.original.cve, team_id: teamId }; + + const path = hostsBySoftwareParams + ? `${PATHS.MANAGE_HOSTS}?${buildQueryStringFromParams( + hostsBySoftwareParams + )}` + : PATHS.MANAGE_HOSTS; + + router.push(path); + }; + const tableHeaders = useMemo( () => generateTableConfig(Boolean(isPremiumTier), Boolean(isSandboxMode)), [isPremiumTier, isSandboxMode] @@ -71,6 +102,8 @@ const SoftwareVulnerabilitiesTable = ({ pageSize={20} resultsTitle={"vulnerabilities"} showMarkAllPages={false} + disableMultiRowSelect + onSelectSingleRow={handleRowSelect} /> ); diff --git a/frontend/pages/SoftwarePage/components/SoftwareVulnerabilitiesTable/SoftwareVulnerabilitiesTableConfig.tsx b/frontend/pages/SoftwarePage/components/SoftwareVulnerabilitiesTable/SoftwareVulnerabilitiesTableConfig.tsx index baf9a8d78a..c52be86c7e 100644 --- a/frontend/pages/SoftwarePage/components/SoftwareVulnerabilitiesTable/SoftwareVulnerabilitiesTableConfig.tsx +++ b/frontend/pages/SoftwarePage/components/SoftwareVulnerabilitiesTable/SoftwareVulnerabilitiesTableConfig.tsx @@ -65,9 +65,6 @@ const generateTableConfig = ( ); }, }, - ]; - - const premiumHeaders: IDataColumn[] = [ { title: "Severity", accessor: "cvss_score", @@ -221,7 +218,15 @@ const generateTableConfig = ( }, ]; - return isPremiumTier ? tableHeaders.concat(premiumHeaders) : tableHeaders; + if (!isPremiumTier) { + return tableHeaders.filter( + (header) => + header.accessor !== "epss_probability" && + header.accessor !== "cve_published" + ); + } + + return tableHeaders; }; export default generateTableConfig; diff --git a/frontend/services/entities/hosts.ts b/frontend/services/entities/hosts.ts index b718bd3c5a..2104fa2469 100644 --- a/frontend/services/entities/hosts.ts +++ b/frontend/services/entities/hosts.ts @@ -203,6 +203,7 @@ export default { const munkiIssueId = options?.munkiIssueId; const osSettings = options?.osSettings; const diskEncryptionStatus = options?.diskEncryptionStatus; + const vulnerability = options?.vulnerability; if (!sortBy.length) { throw Error("sortBy is a required field."); @@ -231,6 +232,7 @@ export default { lowDiskSpaceHosts, osSettings, diskEncryptionStatus, + vulnerability, }), status, label_id: label, diff --git a/frontend/utilities/url/index.ts b/frontend/utilities/url/index.ts index 8c4c0424a3..0d12e7071e 100644 --- a/frontend/utilities/url/index.ts +++ b/frontend/utilities/url/index.ts @@ -9,7 +9,6 @@ import { HOSTS_QUERY_PARAMS, MacSettingsStatusQueryParam, } from "services/entities/hosts"; -import vulnerability from "interfaces/vulnerability"; type QueryValues = string | number | boolean | undefined | null; export type QueryParams = Record; @@ -120,6 +119,7 @@ export const reconcileMutuallyExclusiveHostParams = ({ osName, osVersion, osSettings, + vulnerability, diskEncryptionStatus, bootstrapPackageStatus, }: IMutuallyExclusiveHostParams): Record => {