import React from "react"; import { CellProps, Column } from "react-table"; import { InjectedRouter } from "react-router"; import { ISoftwareTitle, NO_VERSION_OR_HOST_DATA_SOURCES, formatSoftwareType, isIpadOrIphoneSoftwareSource, } from "interfaces/software"; import PATHS from "router/paths"; import { getPathWithQueryParams } from "utilities/url"; import { getAutomaticInstallPoliciesCount } from "pages/SoftwarePage/helpers"; import { IHeaderProps, IStringCellProps } from "interfaces/datatable_config"; import HeaderCell from "components/TableContainer/DataTable/HeaderCell"; import TextCell from "components/TableContainer/DataTable/TextCell"; import ViewAllHostsLink from "components/ViewAllHostsLink"; import SoftwareNameCell from "components/TableContainer/DataTable/SoftwareNameCell"; import VersionCell from "../../components/tables/VersionCell"; import VulnerabilitiesCell from "../../components/tables/VulnerabilitiesCell"; import { getVulnerabilities } from "./helpers"; // NOTE: cellProps come from react-table // more info here https://react-table.tanstack.com/docs/api/useTable#cell-properties type ISoftwareTitlesTableConfig = Column; type ITableStringCellProps = IStringCellProps; type IVersionsCellProps = CellProps; type IVulnerabilitiesCellProps = IVersionsCellProps; type IHostCountCellProps = CellProps< ISoftwareTitle, ISoftwareTitle["hosts_count"] >; type IViewAllHostsLinkProps = CellProps; type ITableHeaderProps = IHeaderProps; /** * Gets the data needed to render the software name cell. */ const getSoftwareNameCellData = ( softwareTitle: ISoftwareTitle, teamId?: number ) => { const softwareTitleDetailsPath = getPathWithQueryParams( PATHS.SOFTWARE_TITLE_DETAILS(softwareTitle.id.toString()), { team_id: teamId } ); const { software_package, app_store_app } = softwareTitle; let hasInstaller = false; let isSelfService = false; let installType: "manual" | "automatic" | undefined; let iconUrl: string | null = null; if (software_package) { hasInstaller = true; isSelfService = software_package.self_service; installType = software_package.automatic_install_policies && software_package.automatic_install_policies.length > 0 ? "automatic" : "manual"; } else if (app_store_app) { hasInstaller = true; isSelfService = app_store_app.self_service; iconUrl = app_store_app.icon_url; installType = app_store_app.automatic_install_policies && app_store_app.automatic_install_policies.length > 0 ? "automatic" : "manual"; } if (softwareTitle.icon_url) { iconUrl = softwareTitle.icon_url; } const automaticInstallPoliciesCount = getAutomaticInstallPoliciesCount( softwareTitle ); const isAllTeams = teamId === undefined; return { name: softwareTitle.name, displayName: softwareTitle.display_name, source: softwareTitle.source, path: softwareTitleDetailsPath, hasInstaller: hasInstaller && !isAllTeams, isSelfService, installType, iconUrl, automaticInstallPoliciesCount, }; }; const generateTableHeaders = ( router: InjectedRouter, teamId?: number ): ISoftwareTitlesTableConfig[] => { const softwareTableHeaders: ISoftwareTitlesTableConfig[] = [ { Header: (cellProps: ITableHeaderProps) => ( ), disableSortBy: false, accessor: "name", Cell: (cellProps: ITableStringCellProps) => { const nameCellData = getSoftwareNameCellData( cellProps.row.original, teamId ); const isAndroidPlayStoreApp = !!cellProps.row.original.app_store_app && cellProps.row.original.source === "android_apps"; return ( ); }, sortType: "caseInsensitive", }, { Header: "Version", disableSortBy: true, accessor: "versions", Cell: (cellProps: IVersionsCellProps) => ( ), }, { Header: "Type", disableSortBy: true, accessor: "source", Cell: (cellProps: ITableStringCellProps) => ( ), }, // the "vulnerabilities" accessor is used but the data is actually coming // from the version attribute. We do this as we already have a "versions" // attribute used for the "Version" column and we cannot reuse. This is a // limitation of react-table. // With the versions data, we can sum up the vulnerabilities to get the // total number of vulnerabilities for the software title { Header: "Vulnerabilities", disableSortBy: true, Cell: (cellProps: IVulnerabilitiesCellProps) => { const vulnDetectionNotSupported = isIpadOrIphoneSoftwareSource(cellProps.row.original.source) || cellProps.row.original.source === "tgz_packages"; if (vulnDetectionNotSupported) { return ; } const vulnerabilities = getVulnerabilities( cellProps.row.original.versions ?? [] ); return ; }, }, { Header: (cellProps: ITableHeaderProps) => ( ), disableSortBy: false, accessor: "hosts_count", Cell: (cellProps: IHostCountCellProps) => ( ), }, { Header: "", id: "view-all-hosts", disableSortBy: true, Cell: (cellProps: IViewAllHostsLinkProps) => { const { source } = cellProps.row.original; const hostCountNotSupported = NO_VERSION_OR_HOST_DATA_SOURCES.includes( source ); if (hostCountNotSupported) return null; return ( ); }, }, ]; return softwareTableHeaders; }; export default generateTableHeaders;