diff --git a/client/src/app/api/rest.ts b/client/src/app/api/rest.ts index 2c288e6c..7c49b066 100644 --- a/client/src/app/api/rest.ts +++ b/client/src/app/api/rest.ts @@ -137,10 +137,11 @@ export const downloadSBOMById = (id: number | string) => { }); }; -export const getPackagesBySbomId = (id: string | number) => { - return axios - .get(`${SBOMS}/${id}/packages`) - .then((response) => response.data); +export const getPackagesBySbomId = ( + id: number | string, + params: HubRequestParams = {} +) => { + return getHubPaginatedResult(`${SBOMS}/${id}/packages`, params); }; export const getVulnerabilitiesBySbomId = (id: string | number) => { diff --git a/client/src/app/common/types.ts b/client/src/app/common/types.ts index 2f6e5bcd..4bbf6791 100644 --- a/client/src/app/common/types.ts +++ b/client/src/app/common/types.ts @@ -5,5 +5,5 @@ export interface Page { export interface SortBy { index: number; - direction: 'asc' | 'desc'; + direction: "asc" | "desc"; } diff --git a/client/src/app/hooks/table-controls/active-item/useActiveItemState.ts b/client/src/app/hooks/table-controls/active-item/useActiveItemState.ts index f0e3f362..fb49ded8 100644 --- a/client/src/app/hooks/table-controls/active-item/useActiveItemState.ts +++ b/client/src/app/hooks/table-controls/active-item/useActiveItemState.ts @@ -72,11 +72,11 @@ export const useActiveItemState = < deserialize: ({ activeItem }) => parseMaybeNumericString(activeItem), } : persistTo === "localStorage" || persistTo === "sessionStorage" - ? { - persistTo, - key: "activeItem", - } - : { persistTo }), + ? { + persistTo, + key: "activeItem", + } + : { persistTo }), }); return { activeItemId, setActiveItemId }; }; diff --git a/client/src/app/hooks/table-controls/expansion/useExpansionState.ts b/client/src/app/hooks/table-controls/expansion/useExpansionState.ts index ac3a873b..bb30edb0 100644 --- a/client/src/app/hooks/table-controls/expansion/useExpansionState.ts +++ b/client/src/app/hooks/table-controls/expansion/useExpansionState.ts @@ -107,11 +107,11 @@ export const useExpansionState = < }, } : persistTo === "localStorage" || persistTo === "sessionStorage" - ? { - persistTo, - key: "expandedCells", - } - : { persistTo }), + ? { + persistTo, + key: "expandedCells", + } + : { persistTo }), }); return { expandedCells, setExpandedCells }; }; diff --git a/client/src/app/hooks/table-controls/filtering/useFilterState.ts b/client/src/app/hooks/table-controls/filtering/useFilterState.ts index 2de43e1f..8a56e252 100644 --- a/client/src/app/hooks/table-controls/filtering/useFilterState.ts +++ b/client/src/app/hooks/table-controls/filtering/useFilterState.ts @@ -103,8 +103,8 @@ export const useFilterState = < deserialize: deserializeFilterUrlParams, } : persistTo === "localStorage" || persistTo === "sessionStorage" - ? { persistTo, key: "filters" } - : { persistTo }), + ? { persistTo, key: "filters" } + : { persistTo }), }); return { filterValues, setFilterValues }; }; diff --git a/client/src/app/hooks/table-controls/pagination/usePaginationState.ts b/client/src/app/hooks/table-controls/pagination/usePaginationState.ts index 6fd87c84..7c56b248 100644 --- a/client/src/app/hooks/table-controls/pagination/usePaginationState.ts +++ b/client/src/app/hooks/table-controls/pagination/usePaginationState.ts @@ -112,11 +112,11 @@ export const usePaginationState = < }, } : persistTo === "localStorage" || persistTo === "sessionStorage" - ? { - persistTo, - key: "pagination", - } - : { persistTo }), + ? { + persistTo, + key: "pagination", + } + : { persistTo }), }); const { pageNumber, itemsPerPage } = paginationState || defaultValue; const setPageNumber = (num: number) => diff --git a/client/src/app/hooks/table-controls/sorting/useSortState.ts b/client/src/app/hooks/table-controls/sorting/useSortState.ts index 87fc6190..78851eb7 100644 --- a/client/src/app/hooks/table-controls/sorting/useSortState.ts +++ b/client/src/app/hooks/table-controls/sorting/useSortState.ts @@ -107,11 +107,11 @@ export const useSortState = < : null, } : persistTo === "localStorage" || persistTo === "sessionStorage" - ? { - persistTo, - key: "sort", - } - : { persistTo }), + ? { + persistTo, + key: "sort", + } + : { persistTo }), }); return { activeSort, setActiveSort }; }; diff --git a/client/src/app/hooks/table-controls/types.ts b/client/src/app/hooks/table-controls/types.ts index daa4a891..e070990c 100644 --- a/client/src/app/hooks/table-controls/types.ts +++ b/client/src/app/hooks/table-controls/types.ts @@ -1,5 +1,8 @@ import { TableProps, TdProps, ThProps, TrProps } from "@patternfly/react-table"; -import { ISelectionStateArgs, useSelectionState } from "@app/hooks/useSelectionState"; +import { + ISelectionStateArgs, + useSelectionState, +} from "@app/hooks/useSelectionState"; import { DisallowCharacters, DiscriminatedArgs } from "@app/utils/type-utils"; import { IFilterStateArgs, diff --git a/client/src/app/pages/advisory-details/vulnerabilities.tsx b/client/src/app/pages/advisory-details/vulnerabilities.tsx index 1de62c9d..ed230c69 100644 --- a/client/src/app/pages/advisory-details/vulnerabilities.tsx +++ b/client/src/app/pages/advisory-details/vulnerabilities.tsx @@ -16,7 +16,7 @@ import { Tr, } from "@patternfly/react-table"; -import { Severity, VulnerabilityBase } from "@app/api/models"; +import { VulnerabilityBase } from "@app/api/models"; import { FilterToolbar, FilterType } from "@app/components/FilterToolbar"; import { SimplePagination } from "@app/components/SimplePagination"; import { @@ -25,7 +25,6 @@ import { TableRowContentWithControls, } from "@app/components/TableControls"; import { useLocalTableControls } from "@app/hooks/table-controls"; -import { RENDER_DATE_FORMAT } from "@app/Constants"; import { SeverityShieldAndText } from "@app/components/SeverityShieldAndText"; interface VulnerabilitiesProps { diff --git a/client/src/app/pages/advisory-list/components/VulnerabilitiesGaleryCount.tsx b/client/src/app/pages/advisory-list/components/VulnerabilitiesGaleryCount.tsx index db69a46e..e198851b 100644 --- a/client/src/app/pages/advisory-list/components/VulnerabilitiesGaleryCount.tsx +++ b/client/src/app/pages/advisory-list/components/VulnerabilitiesGaleryCount.tsx @@ -1,6 +1,6 @@ import React from "react"; -import { VulnerabilityBase, Severity } from "@app/api/models"; +import { Severity } from "@app/api/models"; import { VulnerabilityGallery } from "@app/components/VulnerabilityGallery"; type SeverityCount = { [key in Severity]: number }; diff --git a/client/src/app/pages/importer-list/components/importer-form.tsx b/client/src/app/pages/importer-list/components/importer-form.tsx index 3abd3fbb..c072d75b 100644 --- a/client/src/app/pages/importer-list/components/importer-form.tsx +++ b/client/src/app/pages/importer-list/components/importer-form.tsx @@ -2,7 +2,7 @@ import React, { useContext } from "react"; import { yupResolver } from "@hookform/resolvers/yup"; import { AxiosError } from "axios"; -import { Control, Controller, useFieldArray, useForm } from "react-hook-form"; +import { useFieldArray, useForm } from "react-hook-form"; import { array, boolean, number, object, string } from "yup"; import { @@ -15,8 +15,6 @@ import { FormGroup, FormSelect, FormSelectOption, - Level, - LevelItem, NumberInput, Popover, PopoverPosition, @@ -358,6 +356,7 @@ export const ImporterForm: React.FC = ({ fieldId="periodUnit" renderInput={({ field: { value, onChange, onBlur } }) => ( { const { pushNotification } = React.useContext(NotificationsContext); @@ -117,7 +117,6 @@ export const ImporterList: React.FC = () => { name: item.name, }), isPaginationEnabled: true, - initialItemsPerPage: 10, isExpansionEnabled: true, expandableVariant: "single", isFilterEnabled: true, diff --git a/client/src/app/pages/package-details/package-details.tsx b/client/src/app/pages/package-details/package-details.tsx index 91291527..8bd2dbb7 100644 --- a/client/src/app/pages/package-details/package-details.tsx +++ b/client/src/app/pages/package-details/package-details.tsx @@ -15,7 +15,6 @@ import { PathParam, useRouteParams } from "@app/Routes"; import { useFetchPackageById } from "@app/queries/packages"; import { LoadingWrapper } from "@app/components/LoadingWrapper"; -import { RelatedCVEs } from "./related-cves"; import { RelatedSBOMs } from "./related-sboms"; export const PackageDetails: React.FC = () => { diff --git a/client/src/app/pages/package-list/package-list.tsx b/client/src/app/pages/package-list/package-list.tsx index 8e3b73f2..ebe9b023 100644 --- a/client/src/app/pages/package-list/package-list.tsx +++ b/client/src/app/pages/package-list/package-list.tsx @@ -43,9 +43,9 @@ export const PackageList: React.FC = () => { qualifiers: "Qualifiers", cve: "CVEs", }, + isPaginationEnabled: true, isSortEnabled: true, sortableColumns: [], - initialItemsPerPage: 10, isFilterEnabled: true, filterCategories: [ { diff --git a/client/src/app/pages/sbom-details/overview.tsx b/client/src/app/pages/sbom-details/overview.tsx index 4c175548..1dadbfd3 100644 --- a/client/src/app/pages/sbom-details/overview.tsx +++ b/client/src/app/pages/sbom-details/overview.tsx @@ -36,7 +36,9 @@ export const Overview: React.FC = ({ sbom }) => { > Name - {sbom.title} + + {sbom.title} + Version diff --git a/client/src/app/pages/sbom-details/packages.tsx b/client/src/app/pages/sbom-details/packages.tsx index 59c591e7..83d762e3 100644 --- a/client/src/app/pages/sbom-details/packages.tsx +++ b/client/src/app/pages/sbom-details/packages.tsx @@ -32,7 +32,11 @@ interface PackagesProps { } export const Packages: React.FC = ({ sbomId }) => { - const { packages, isFetching, fetchError } = useFetchPackagesBySbomId(sbomId); + const { + result: { data: packages }, + isFetching, + fetchError, + } = useFetchPackagesBySbomId(sbomId); const tableControls = useLocalTableControls({ tableName: "packages-table", diff --git a/client/src/app/pages/sbom-list/components/packages-count.tsx b/client/src/app/pages/sbom-list/components/packages-count.tsx new file mode 100644 index 00000000..85c7a0ec --- /dev/null +++ b/client/src/app/pages/sbom-list/components/packages-count.tsx @@ -0,0 +1,17 @@ +import React from "react"; + +import { useFetchPackagesBySbomId } from "@app/queries/sboms"; + +export interface IPackagesCountProps { + sbomId: string | number; +} + +export const PackagesCount: React.FC = ({ sbomId }) => { + const { + result: { total }, + } = useFetchPackagesBySbomId(sbomId, { + page: { pageNumber: 1, itemsPerPage: 1 }, + }); + + return <>{total}; +}; diff --git a/client/src/app/pages/sbom-list/sbom-list.tsx b/client/src/app/pages/sbom-list/sbom-list.tsx index 8a213107..f0aa21f3 100644 --- a/client/src/app/pages/sbom-list/sbom-list.tsx +++ b/client/src/app/pages/sbom-list/sbom-list.tsx @@ -4,7 +4,6 @@ import { NavLink } from "react-router-dom"; import dayjs from "dayjs"; import { - Button, PageSection, PageSectionVariants, Text, @@ -13,14 +12,12 @@ import { ToolbarContent, ToolbarItem, } from "@patternfly/react-core"; -import DownloadIcon from "@patternfly/react-icons/dist/esm/icons/download-icon"; import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table"; import { RENDER_DATE_FORMAT, TablePersistenceKeyPrefixes, } from "@app/Constants"; -import { VulnerabilityGallery } from "@app/components/VulnerabilityGallery"; import { FilterToolbar, FilterType } from "@app/components/FilterToolbar"; import { SimplePagination } from "@app/components/SimplePagination"; import { @@ -35,6 +32,7 @@ import { import { useDownload } from "@app/hooks/useDownload"; import { useSelectionState } from "@app/hooks/useSelectionState"; import { useFetchSBOMs } from "@app/queries/sboms"; +import { PackagesCount } from "./components/packages-count"; export const SbomList: React.FC = () => { const tableControlState = useTableControlState({ @@ -48,6 +46,7 @@ export const SbomList: React.FC = () => { packages: "Packages", vulnerabilities: "Vulnerabilities", }, + isPaginationEnabled: true, isSortEnabled: true, sortableColumns: ["published"], initialItemsPerPage: 10, @@ -179,10 +178,12 @@ export const SbomList: React.FC = () => { {dayjs(item.published).format(RENDER_DATE_FORMAT)} - {/* {item.related_packages.count} */} -

Count packages

+ - + {/* */}

issue-285

diff --git a/client/src/app/pages/vulnerability-details/related-advisories.tsx b/client/src/app/pages/vulnerability-details/related-advisories.tsx index acc6875e..3b4f51ec 100644 --- a/client/src/app/pages/vulnerability-details/related-advisories.tsx +++ b/client/src/app/pages/vulnerability-details/related-advisories.tsx @@ -6,7 +6,6 @@ import dayjs from "dayjs"; import { RENDER_DATE_FORMAT } from "@app/Constants"; import { AdvisoryBase } from "@app/api/models"; import { FilterToolbar } from "@app/components/FilterToolbar"; -import { SeverityShieldAndText } from "@app/components/SeverityShieldAndText"; import { SimplePagination } from "@app/components/SimplePagination"; import { ConditionalTableBody, diff --git a/client/src/app/pages/vulnerability-details/source.tsx b/client/src/app/pages/vulnerability-details/source.tsx index 25f9be46..75bdc671 100644 --- a/client/src/app/pages/vulnerability-details/source.tsx +++ b/client/src/app/pages/vulnerability-details/source.tsx @@ -10,7 +10,8 @@ interface SourceProps { } export const Source: React.FC = ({ cveId }) => { - const { source, isFetching, fetchError } = useFetchVulnerabilitySourceById(cveId); + const { source, isFetching, fetchError } = + useFetchVulnerabilitySourceById(cveId); return ( <> diff --git a/client/src/app/pages/vulnerability-details/vulnerability-details.tsx b/client/src/app/pages/vulnerability-details/vulnerability-details.tsx index afdcf467..9db0f4a0 100644 --- a/client/src/app/pages/vulnerability-details/vulnerability-details.tsx +++ b/client/src/app/pages/vulnerability-details/vulnerability-details.tsx @@ -20,7 +20,6 @@ import { Tabs, Text, TextContent, - Truncate, } from "@patternfly/react-core"; import DownloadIcon from "@patternfly/react-icons/dist/esm/icons/download-icon"; @@ -30,13 +29,10 @@ import { RENDER_DATE_FORMAT } from "@app/Constants"; import { PathParam, useRouteParams } from "@app/Routes"; import { LoadingWrapper } from "@app/components/LoadingWrapper"; -import { SeverityShieldAndText } from "@app/components/SeverityShieldAndText"; import { useDownload } from "@app/hooks/useDownload"; import { useFetchVulnerabilityById } from "@app/queries/vulnerabilities"; import { RelatedAdvisories } from "./related-advisories"; -import { RelatedSBOMs } from "./related-sboms"; -import { Source } from "./source"; export const CveDetails: React.FC = () => { const vulnerabilityId = useRouteParams(PathParam.VULNERABILITY_ID); diff --git a/client/src/app/pages/vulnerability-list/vulnerability-list.tsx b/client/src/app/pages/vulnerability-list/vulnerability-list.tsx index de9243e6..36226fb0 100644 --- a/client/src/app/pages/vulnerability-list/vulnerability-list.tsx +++ b/client/src/app/pages/vulnerability-list/vulnerability-list.tsx @@ -1,8 +1,6 @@ import React from "react"; import { NavLink } from "react-router-dom"; -import dayjs from "dayjs"; - import { PageSection, PageSectionVariants, @@ -14,12 +12,8 @@ import { } from "@patternfly/react-core"; import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table"; -import { - RENDER_DATE_FORMAT, - TablePersistenceKeyPrefixes, -} from "@app/Constants"; +import { TablePersistenceKeyPrefixes } from "@app/Constants"; import { FilterToolbar, FilterType } from "@app/components/FilterToolbar"; -import { SeverityShieldAndText } from "@app/components/SeverityShieldAndText"; import { SimplePagination } from "@app/components/SimplePagination"; import { ConditionalTableBody, @@ -30,7 +24,6 @@ import { useTableControlProps, useTableControlState, } from "@app/hooks/table-controls"; -import { useDownload } from "@app/hooks/useDownload"; import { useSelectionState } from "@app/hooks/useSelectionState"; import { useFetchVulnerabilities } from "@app/queries/vulnerabilities"; @@ -46,9 +39,9 @@ export const VulnerabilityList: React.FC = () => { modified: "Modified", relatedSBOMs: "Related SBOMs", }, + isPaginationEnabled: true, isSortEnabled: true, sortableColumns: ["severity", "published", "modified"], - initialItemsPerPage: 10, isFilterEnabled: true, filterCategories: [ { diff --git a/client/src/app/queries/sboms.ts b/client/src/app/queries/sboms.ts index cbf6600a..d4f7c208 100644 --- a/client/src/app/queries/sboms.ts +++ b/client/src/app/queries/sboms.ts @@ -63,20 +63,25 @@ export const useFetchSBOMSourceById = (id?: number | string) => { }; }; -export const useFetchPackagesBySbomId = (sbomId: string | number) => { - const { data, isLoading, error } = useQuery({ - queryKey: [SBOMsQueryKey, sbomId, "packages"], - queryFn: () => - sbomId === undefined - ? Promise.resolve(undefined) - : getPackagesBySbomId(sbomId), +export const useFetchPackagesBySbomId = ( + sbomId: string | number, + params: HubRequestParams = {} +) => { + const { data, isLoading, error, refetch } = useQuery({ + queryKey: [SBOMsQueryKey, sbomId, "packages", params], + queryFn: () => getPackagesBySbomId(sbomId, params), enabled: sbomId !== undefined, }); return { - packages: data || [], + result: { + data: data?.data || [], + total: data?.total ?? 0, + params: data?.params ?? params, + }, isFetching: isLoading, fetchError: error as AxiosError, + refetch, }; };