From 93f436fdf36e32d3ed085039efc3d1e5875e233e Mon Sep 17 00:00:00 2001 From: Bartek Szopka Date: Fri, 25 Apr 2025 15:32:57 +0200 Subject: [PATCH 1/7] POC: quick prototype of showing snap CVE data in a table with select input for revisions --- .../js/publisher/pages/SnapCves/SnapCves.tsx | 138 ++++++++++++++++++ static/js/publisher/pages/SnapCves/index.ts | 1 + static/js/publisher/publisher.tsx | 7 + webapp/publisher/snaps/views.py | 5 + 4 files changed, 151 insertions(+) create mode 100644 static/js/publisher/pages/SnapCves/SnapCves.tsx create mode 100644 static/js/publisher/pages/SnapCves/index.ts diff --git a/static/js/publisher/pages/SnapCves/SnapCves.tsx b/static/js/publisher/pages/SnapCves/SnapCves.tsx new file mode 100644 index 0000000000..6c5d97f425 --- /dev/null +++ b/static/js/publisher/pages/SnapCves/SnapCves.tsx @@ -0,0 +1,138 @@ +import { useParams } from "react-router-dom"; + +// import { setPageTitle } from "../../utils"; +import { useQuery } from "react-query"; +import { MainTable, Strip, Select } from "@canonical/react-components"; +import { useEffect, useState } from "react"; + +interface ICve { + id: string; + description: string; + cvss_score: number | null; + cvss_severity: string | null; + ubuntu_priority: string | null; +} + +function SnapCves(): JSX.Element { + const { snapId } = useParams(); + const [currentRevision, setCurrentRevision] = useState(null); + const { data: revisionsData, isLoading: isRevisionsLoading } = useQuery({ + queryKey: ["snapRevisions", snapId], + queryFn: async () => { + const response = await fetch(`/api/${snapId}/cves`); + if (!response.ok) { + throw new Error("There was a problem fetching listing data"); + } + const data = await response.json(); + if (!data.success) { + throw new Error(data.message); + } + + return data.data; + }, + staleTime: 1000 * 60 * 60 * 12, // 12 hours + cacheTime: 1000 * 60 * 60 * 12, // 12 hours + refetchOnWindowFocus: false, + }); + + useEffect(() => { + if (!currentRevision && revisionsData?.revisions?.length) { + setCurrentRevision(revisionsData.revisions[0]); + } + }, [currentRevision, revisionsData]); + + const { data, isLoading: isCvesLoading } = useQuery({ + queryKey: ["cves", snapId, currentRevision], + queryFn: async () => { + const response = await fetch(`/api/${snapId}/${currentRevision}/cves`); + + if (!response.ok) { + throw new Error("There was a problem fetching listing data"); + } + const data = await response.json(); + + if (!data.success) { + throw new Error(data.message); + } + + return data.data; + }, + enabled: !!currentRevision, + staleTime: 1000 * 60 * 60 * 12, // 12 hours + cacheTime: 1000 * 60 * 60 * 12, // 12 hours + refetchOnWindowFocus: false, + }); + + const getData = () => { + return data.map((cve: ICve) => ({ + columns: [ + { content: cve.id }, + { content: cve.cvss_score }, + { content: cve.cvss_severity }, + { content: cve.ubuntu_priority }, + { content: cve.description }, + ], + })); + }; + + console.table(data); + // setPageTitle(`Listing data for ${snapId}`); + + const isLoading = isCvesLoading || isRevisionsLoading; + + const revisionSelectOptions = revisionsData?.revisions.map( + (revision: string) => ({ + label: revision, + value: revision, + }) + ); + + return ( + <> +

+ My snaps / {snapId} / + CVEs +

+ + {isLoading && ( + +

+  Loading{" "} + {snapId} CVE data +

+
+ )} + + {data && ( + <> +
+ { - const selectedRevision = event.target.value; - // Handle the revision change here - console.log("Selected revision:", selectedRevision); - setCurrentRevision(parseInt(selectedRevision)); - }} - options={revisionSelectOptions} - /> +
+
-
+