From ecb21e78df7e30dd264b8ae6f12849ba629298a8 Mon Sep 17 00:00:00 2001 From: Hubtrick-Git Date: Thu, 29 Jan 2026 15:47:55 +0100 Subject: [PATCH 1/7] first prototype for minimum requirements --- .gitignore | 1 + .../reachability-analysis.tsx | 80 +++++++++++++++++++ .../reachability-types.tsx | 63 +++++++++++++++ .../reachabilityAnalysis/renderData.tsx | 29 +++++++ src/pages/_meta.ts | 13 +++ src/pages/reachability-analysis.mdx | 7 ++ 6 files changed, 193 insertions(+) create mode 100644 src/components/reachabilityAnalysis/reachability-analysis.tsx create mode 100644 src/components/reachabilityAnalysis/reachability-types.tsx create mode 100644 src/components/reachabilityAnalysis/renderData.tsx create mode 100644 src/pages/reachability-analysis.mdx diff --git a/.gitignore b/.gitignore index 2a0870e..b5e08c2 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ # misc .DS_Store *.pem +.vscode/* # debug npm-debug.log* diff --git a/src/components/reachabilityAnalysis/reachability-analysis.tsx b/src/components/reachabilityAnalysis/reachability-analysis.tsx new file mode 100644 index 0000000..6760806 --- /dev/null +++ b/src/components/reachabilityAnalysis/reachability-analysis.tsx @@ -0,0 +1,80 @@ +import React, { FormEventHandler, useState } from "react" +import { ReachabilityAnalysisResponse} from "./reachability-types" +import AnalysisResultsTable from "./renderData" + +const apiBaseURL = 'http://localhost:8080/api/v1/' + +export function ReachabilityAnalysisHero() { + return ( +
+
+

+ Reachability Analysis +

+

+ This page enables you to search for a npm package and get a list of all CVEs associated with it. + Additionally you get information about whether the CVE is actually affecting this package or not. +

+
+

+
+
+ ) +} + +export const apiCall = ( baseURL: string,params: string,init?: RequestInit) => { + return fetch(baseURL + params,init) +} + +export function ReachabilityAnalysisSearchBar() { + const [input,setInput] = useState("") + const [data, setData] = useState(); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(false); + + const getData = async () => { + setIsLoading(true) + try{ + const response = await fetch(apiBaseURL+input) + const data = await response.json() + setIsLoading(false) + + if (!data || !response.ok) { + window.alert("error when trying to fetch data from api endpoint") + } + setData(data) + }catch{ + setError(true) + }finally{ + setIsLoading(false) + } + } + + const onSubmit: FormEventHandler = (e) => { + e.preventDefault() + getData() + } + + + return ( +
+
+ +
+ {setInput(e.target.value)}} + className="text-center block w-1/3 mx-auto focus:w-full text-xl rounded-full bg-white/5 px-5 py-2 text-white outline outline-1 -outline-offset-1 outline-white/50 focus:outline-3 focus:outline-white/70 placeholder:text-gray-500 focus:placeholder:opacity-0 transition-all duration-300 ease-in-out" + /> +
+
+ +
+ ) +} +/* */ \ No newline at end of file diff --git a/src/components/reachabilityAnalysis/reachability-types.tsx b/src/components/reachabilityAnalysis/reachability-types.tsx new file mode 100644 index 0000000..26e7e62 --- /dev/null +++ b/src/components/reachabilityAnalysis/reachability-types.tsx @@ -0,0 +1,63 @@ + +export interface ReachabilityAnalysisResponse{ + bomFormat : string + specVersion : string + serialNumber : string + version : number + metadata : Metadata + components : Component[] + vulnerabilities : Vulnerability[] +} + +interface Metadata{ + timestamp : string + tools : Tool[] +} + +interface Tool{ + vendor : string + name : string + version : string +} + +interface Component { + type : string + name : string + purl : string + "bom-ref" : string +} + +interface Vulnerability{ + "bom-ref" : string + id : string + description : string + affects : Affect[] + analysis : Analysis +} + +interface Affect{ + ref : string +} + +interface Analysis { + state : string + detail : string + evidence : Evidence[] +} + +interface Evidence { + path : PathElement[] +} + + +interface PathElement{ + id: number; + cve_id: string; + signature: string; + filename: string; + start_line: number; + end_line: number; + evidence: string; + purl: string; + calls_id: number | null; +} \ No newline at end of file diff --git a/src/components/reachabilityAnalysis/renderData.tsx b/src/components/reachabilityAnalysis/renderData.tsx new file mode 100644 index 0000000..68d8e89 --- /dev/null +++ b/src/components/reachabilityAnalysis/renderData.tsx @@ -0,0 +1,29 @@ +import React from "react"; +import { ReachabilityAnalysisResponse } from "./reachability-types"; +import { d } from "nextra/dist/types-BhjhW0gX"; + +interface fetchResults{ + loading: boolean + error : boolean + data? : ReachabilityAnalysisResponse +} + +const AnalysisResultsTable: React.FC = ({loading,error,data}) => { + if (loading && !error) { + return
Loading
+ } + if (!loading && error){ + return
Error occurred
+ } + if (!data){ + return
No data in response
+ } + + if (!loading && !error && data){ + console.log(data) + return
Received data and rendering: {data.version}
+ } + return
undefined behavior
+} + +export default AnalysisResultsTable \ No newline at end of file diff --git a/src/pages/_meta.ts b/src/pages/_meta.ts index ce5c0af..1902498 100644 --- a/src/pages/_meta.ts +++ b/src/pages/_meta.ts @@ -1,3 +1,5 @@ +import { title } from "process"; + export default { index: { theme: { @@ -11,6 +13,12 @@ export default { }, display: 'hidden', }, + "reachability-analysis": { + theme: { + layout: 'raw' + }, + display: 'hidden', + }, 'terms-of-use': { display: 'hidden', }, @@ -37,6 +45,11 @@ export default { type: 'page', href: '/introduction', }, + 'header-reachability':{ + title: 'Reachability', + type: 'page', + href: '/reachability-analysis' + }, '404': { theme: { layout: 'raw', diff --git a/src/pages/reachability-analysis.mdx b/src/pages/reachability-analysis.mdx new file mode 100644 index 0000000..4151b3a --- /dev/null +++ b/src/pages/reachability-analysis.mdx @@ -0,0 +1,7 @@ +import { + ReachabilityAnalysisHero, + ReachabilityAnalysisSearchBar, +} from '../components/reachabilityAnalysis/reachability-analysis' + + + From 7add69d1a5f8974341b5312229babcbf35e3fed6 Mon Sep 17 00:00:00 2001 From: Hubtrick-Git Date: Fri, 30 Jan 2026 14:23:47 +0100 Subject: [PATCH 2/7] built a prototype table to display results --- .../reachabilityAnalysis/renderData.tsx | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/components/reachabilityAnalysis/renderData.tsx b/src/components/reachabilityAnalysis/renderData.tsx index 68d8e89..3daab62 100644 --- a/src/components/reachabilityAnalysis/renderData.tsx +++ b/src/components/reachabilityAnalysis/renderData.tsx @@ -8,6 +8,12 @@ interface fetchResults{ data? : ReachabilityAnalysisResponse } +interface tableEntry { + component : string + type : string + count : string +} + const AnalysisResultsTable: React.FC = ({loading,error,data}) => { if (loading && !error) { return
Loading
@@ -20,10 +26,28 @@ const AnalysisResultsTable: React.FC = ({loading,error,data}) => { } if (!loading && !error && data){ - console.log(data) - return
Received data and rendering: {data.version}
+ return ( +
+ + + + + + + + + {data.components.map((component, index) => ( + + + + + ))} + +
ComponentType
{component.purl}{component.type}
+
+ ) } - return
undefined behavior
+ return
undefined behavior
} export default AnalysisResultsTable \ No newline at end of file From ee7431b8e0eeb3fc93617033f745ecca4d8600d9 Mon Sep 17 00:00:00 2001 From: Hubtrick-Git Date: Thu, 12 Feb 2026 19:45:29 +0100 Subject: [PATCH 3/7] adjusted structure and design ti match other frontend designs --- package-lock.json | 65 ++++++++++++++- package.json | 3 + .../reachability-analysis.tsx | 80 ------------------- src/pages/reachability-analysis.mdx | 10 +-- 4 files changed, 69 insertions(+), 89 deletions(-) delete mode 100644 src/components/reachabilityAnalysis/reachability-analysis.tsx diff --git a/package-lock.json b/package-lock.json index dd190df..07eb174 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,8 +17,10 @@ "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-tooltip": "^1.2.8", + "@tanstack/react-table": "^8.21.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "date-fns": "^4.1.0", "dotenv": "^16.5.0", "eslint-config-prettier": "^9.1.2", "framer-motion": "^12.17.3", @@ -43,6 +45,7 @@ "sass": "^1.89.2", "sharp": "^0.34.5", "swagger-ui-react": "^5.31.0", + "swr": "^2.4.0", "tailwind-merge": "^3.3.1", "tailwindcss-animate": "^1.0.7", "three": "^0.181.2", @@ -5308,6 +5311,26 @@ "tslib": "^2.8.0" } }, + "node_modules/@tanstack/react-table": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/react-table/-/react-table-8.21.3.tgz", + "integrity": "sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.21.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, "node_modules/@tanstack/react-virtual": { "version": "3.13.10", "resolved": "https://registry.npmjs.org/@tanstack/react-virtual/-/react-virtual-3.13.10.tgz", @@ -5325,6 +5348,19 @@ "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/@tanstack/table-core": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.21.3.tgz", + "integrity": "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@tanstack/virtual-core": { "version": "3.13.10", "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.13.10.tgz", @@ -8324,6 +8360,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/dayjs": { "version": "1.11.19", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz", @@ -18419,6 +18465,19 @@ "immutable": "^3.8.1 || ^4.0.0-rc.1" } }, + "node_modules/swr": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.4.0.tgz", + "integrity": "sha512-sUlC20T8EOt1pHmDiqueUWMmRRX03W7w5YxovWX7VR2KHEPCTMly85x05vpkP5i6Bu4h44ePSMD9Tc+G2MItFw==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3", + "use-sync-external-store": "^1.6.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -19453,9 +19512,9 @@ } }, "node_modules/use-sync-external-store": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz", - "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", "license": "MIT", "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" diff --git a/package.json b/package.json index 3eb20a1..0eeaad0 100644 --- a/package.json +++ b/package.json @@ -42,8 +42,10 @@ "@radix-ui/react-slot": "^1.2.4", "@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-tooltip": "^1.2.8", + "@tanstack/react-table": "^8.21.3", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "date-fns": "^4.1.0", "dotenv": "^16.5.0", "eslint-config-prettier": "^9.1.2", "framer-motion": "^12.17.3", @@ -68,6 +70,7 @@ "sass": "^1.89.2", "sharp": "^0.34.5", "swagger-ui-react": "^5.31.0", + "swr": "^2.4.0", "tailwind-merge": "^3.3.1", "tailwindcss-animate": "^1.0.7", "three": "^0.181.2", diff --git a/src/components/reachabilityAnalysis/reachability-analysis.tsx b/src/components/reachabilityAnalysis/reachability-analysis.tsx deleted file mode 100644 index 6760806..0000000 --- a/src/components/reachabilityAnalysis/reachability-analysis.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import React, { FormEventHandler, useState } from "react" -import { ReachabilityAnalysisResponse} from "./reachability-types" -import AnalysisResultsTable from "./renderData" - -const apiBaseURL = 'http://localhost:8080/api/v1/' - -export function ReachabilityAnalysisHero() { - return ( -
-
-

- Reachability Analysis -

-

- This page enables you to search for a npm package and get a list of all CVEs associated with it. - Additionally you get information about whether the CVE is actually affecting this package or not. -

-
-

-
-
- ) -} - -export const apiCall = ( baseURL: string,params: string,init?: RequestInit) => { - return fetch(baseURL + params,init) -} - -export function ReachabilityAnalysisSearchBar() { - const [input,setInput] = useState("") - const [data, setData] = useState(); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(false); - - const getData = async () => { - setIsLoading(true) - try{ - const response = await fetch(apiBaseURL+input) - const data = await response.json() - setIsLoading(false) - - if (!data || !response.ok) { - window.alert("error when trying to fetch data from api endpoint") - } - setData(data) - }catch{ - setError(true) - }finally{ - setIsLoading(false) - } - } - - const onSubmit: FormEventHandler = (e) => { - e.preventDefault() - getData() - } - - - return ( -
-
- -
- {setInput(e.target.value)}} - className="text-center block w-1/3 mx-auto focus:w-full text-xl rounded-full bg-white/5 px-5 py-2 text-white outline outline-1 -outline-offset-1 outline-white/50 focus:outline-3 focus:outline-white/70 placeholder:text-gray-500 focus:placeholder:opacity-0 transition-all duration-300 ease-in-out" - /> -
-
- -
- ) -} -/* */ \ No newline at end of file diff --git a/src/pages/reachability-analysis.mdx b/src/pages/reachability-analysis.mdx index 4151b3a..1f58361 100644 --- a/src/pages/reachability-analysis.mdx +++ b/src/pages/reachability-analysis.mdx @@ -1,7 +1,5 @@ -import { - ReachabilityAnalysisHero, - ReachabilityAnalysisSearchBar, -} from '../components/reachabilityAnalysis/reachability-analysis' +import ReachabilityAnalysisPage from 'src/components/reachabilityAnalysis/reachability-analysis-page' + + + - - From 00e71fc042fb4ec577dc4a359ba661f2eb77509a Mon Sep 17 00:00:00 2001 From: Hubtrick-Git Date: Fri, 13 Feb 2026 12:19:32 +0100 Subject: [PATCH 4/7] first working version for reachability main page with data fetching, skeleton load and proper display in a table --- .../reachabilityAnalysis/columns.tsx | 56 +++++++ .../reachability-analysis-hero.tsx | 43 +++++ .../reachability-analysis-page.tsx | 150 +++++++++++++++++ .../reachability-analysis-results-table.tsx | 156 ++++++++++++++++++ src/components/ui/input.tsx | 22 +++ src/components/ui/skeleton.tsx | 15 ++ src/components/ui/table.tsx | 117 +++++++++++++ src/lib/fetcher.js | 1 + 8 files changed, 560 insertions(+) create mode 100644 src/components/reachabilityAnalysis/columns.tsx create mode 100644 src/components/reachabilityAnalysis/reachability-analysis-hero.tsx create mode 100644 src/components/reachabilityAnalysis/reachability-analysis-page.tsx create mode 100644 src/components/reachabilityAnalysis/reachability-analysis-results-table.tsx create mode 100644 src/components/ui/input.tsx create mode 100644 src/components/ui/skeleton.tsx create mode 100644 src/components/ui/table.tsx create mode 100644 src/lib/fetcher.js diff --git a/src/components/reachabilityAnalysis/columns.tsx b/src/components/reachabilityAnalysis/columns.tsx new file mode 100644 index 0000000..80728b3 --- /dev/null +++ b/src/components/reachabilityAnalysis/columns.tsx @@ -0,0 +1,56 @@ +import { ColumnDef } from '@tanstack/react-table' +import { ArrowUpDown } from 'lucide-react' +import Link from 'next/link' +import { formatDistanceToNow, format } from 'date-fns' + +export type Package = { + purl: string + type: string + name: string +} + +export const columns: ColumnDef[] = [ + { + accessorKey: 'purl', + header: 'Package URL', + size: 150, + cell: ({ row }) => { + const purl = row.getValue('purl') as string + return ( + +
{purl}
+ + ) + }, + }, + { + accessorKey: 'type', + header: 'Package Type', + size: 600, + cell: ({ row }) => { + const description = row.getValue('type') as string + return
{description}
+ }, + }, + { + accessorKey: 'name', + size: 150, + header: ({ column }) => { + return ( +
+ column.toggleSorting(column.getIsSorted() === 'asc') + } + > + Package Name + +
+ ) + }, + cell: ({ row }) => { + const purl = row.getValue('name') as string + return
{purl}
+ }, + }, +] \ No newline at end of file diff --git a/src/components/reachabilityAnalysis/reachability-analysis-hero.tsx b/src/components/reachabilityAnalysis/reachability-analysis-hero.tsx new file mode 100644 index 0000000..28e1e3b --- /dev/null +++ b/src/components/reachabilityAnalysis/reachability-analysis-hero.tsx @@ -0,0 +1,43 @@ +import { Input } from 'src/components/ui/input' + + +interface HeroProps { + searchTerm: string + setSearchTerm: (value: string) => void + onSearch: () => void +} + +export default function ReachabilityAnalysisHero({searchTerm,setSearchTerm,onSearch}: HeroProps){ + return ( + <> +
+
+
+
+

+ Reachability Analysis +

+

+ Find out if your packages are affected +

+
{ + e.preventDefault() + onSearch() + }} + > + + setSearchTerm(e.target.value) + } + /> +
+
+
+
+
+ + ) +} diff --git a/src/components/reachabilityAnalysis/reachability-analysis-page.tsx b/src/components/reachabilityAnalysis/reachability-analysis-page.tsx new file mode 100644 index 0000000..b3f2ed1 --- /dev/null +++ b/src/components/reachabilityAnalysis/reachability-analysis-page.tsx @@ -0,0 +1,150 @@ +import ReachabilityAnalysisHero from 'src/components/reachabilityAnalysis/reachability-analysis-hero' + +import { DataTable } from 'src/components/reachabilityAnalysis/reachability-analysis-results-table' +import { columns } from 'src/components/reachabilityAnalysis/columns' +import { Container } from 'src/components/top-level-pages/container' + +import { useState, useEffect, useRef } from 'react' +import { useRouter } from 'next/router' +import { fetcher } from 'src/lib/fetcher' +import useSWR from 'swr' + +const apiBaseURL = 'http://localhost:8080/api/v1/vulndb/reachability/' + +export default function ReachabilityAnalysisPage() { + const router = useRouter() + const queryParam = router.query.query + const pageParam = router.query.page + const [searchTerm, setSearchTerm] = useState((queryParam as string) ?? '') + const tableRef = useRef(null) + + const query = (queryParam as string)?.toUpperCase() ?? '' + const page = pageParam as string + + let url = null + if (router.isReady && pageParam) { + url = `http://localhost:8080/api/v1/vulndb/reachability/test?pageSize=10&page=${page}` + if (query) { + url += `&filterQuery[npm][like]=%25${query}%25` + } + } + + const { data: apiResponse, error, isLoading } = useSWR(url, fetcher) + + const data = apiResponse?.data ?? [] + const total = apiResponse?.total ?? 0 + + useEffect(() => { + if (router.isReady && router.query.query) { + setSearchTerm(router.query.query as string) + } + }, [router.isReady, router.query.query]) + + useEffect(() => { + if (apiResponse?.data && apiResponse.data.length > 0) { + tableRef.current?.scrollIntoView({ behavior: 'smooth' }) + } + }, [apiResponse]) + + const handleSearch = () => { + router.push({ query: { query: searchTerm, page: 1 } }, undefined, { + scroll: false, + }) + } + + return ( + + +
+ + router.push( + { query: { ...router.query, page } }, + undefined, + { scroll: false }, + ) + } + /> +
+
+ ) +} + +// export function ReachabilityAnalysisHero() { +// return ( +//
+//
+//

+// Reachability Analysis +//

+//

+// This page enables you to search for a npm package and get a list of all CVEs associated with it. +// Additionally you get information about whether the CVE is actually affecting this package or not. +//

+//
+//

+//
+//
+// ) +// } + +// export const apiCall = ( baseURL: string,params: string,init?: RequestInit) => { +// return fetch(baseURL + params,init) +// } + +// export function ReachabilityAnalysisSearchBar() { +// const [input,setInput] = useState("") +// const [data, setData] = useState(); +// const [isLoading, setIsLoading] = useState(false); +// const [error, setError] = useState(false); + +// const getData = async () => { +// setIsLoading(true) +// try{ +// const response = await fetch(apiBaseURL+input) +// const data = await response.json() +// setIsLoading(false) + +// if (!data || !response.ok) { +// window.alert("error when trying to fetch data from api endpoint") +// } +// setData(data) +// }catch{ +// setError(true) +// }finally{ +// setIsLoading(false) +// } +// } + +// const onSubmit: FormEventHandler = (e) => { +// e.preventDefault() +// getData() +// } + + +// return ( +//
+//
+// +//
+// {setInput(e.target.value)}} +// className="text-center block w-1/3 mx-auto focus:w-full text-xl rounded-full bg-white/5 px-5 py-2 text-white outline outline-1 -outline-offset-1 outline-white/50 focus:outline-3 focus:outline-white/70 placeholder:text-gray-500 focus:placeholder:opacity-0 transition-all duration-300 ease-in-out" +// /> +//
+//
+// +//
+// ) +// } diff --git a/src/components/reachabilityAnalysis/reachability-analysis-results-table.tsx b/src/components/reachabilityAnalysis/reachability-analysis-results-table.tsx new file mode 100644 index 0000000..9314d1c --- /dev/null +++ b/src/components/reachabilityAnalysis/reachability-analysis-results-table.tsx @@ -0,0 +1,156 @@ + +import { Button } from 'src/components/ui/button' +import { Skeleton } from 'src/components/ui/skeleton' +import {Table,TableBody,TableCell,TableHead,TableHeader,TableRow} from 'src/components/ui/table' +import {ColumnDef,SortingState,flexRender,getCoreRowModel,getSortedRowModel,useReactTable} from '@tanstack/react-table' + +import * as React from 'react' +import { useRouter } from 'next/navigation' +import { Package } from './columns' + +const PAGE_SIZE = 10 + +interface DataTableProps { + columns: ColumnDef[] + data: TData[] + isLoading?: boolean + total?: number + page?: number + onPageChange?: (page: number) => void +} + +export function DataTable({ + columns, + data, + isLoading = false, + total = 0, + page = 1, + onPageChange, +}: DataTableProps) { + const router = useRouter() + + const [sorting, setSorting] = React.useState([ + { + id: 'purl', + desc: true, + }, + ]) + + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + onSortingChange: setSorting, + getSortedRowModel: getSortedRowModel(), + state: { + sorting, + }, + }) + + return ( +
+
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef + .header, + header.getContext(), + )} + + ) + })} + + ))} + + + {isLoading ? ( + Array(1) + .fill(0) + .map((_, rowIndex) => ( + + {columns.map((column, cellIndex) => ( + + + + ))} + + )) + ) : table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + router.push( + `/reachability-analysis/${(row.original as Package).purl}`, + ) + } + className="cursor-pointer hover:bg-muted/50" + > + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext(), + )} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
+
+
+
+ Showing {Math.min((page - 1) * PAGE_SIZE + 1, total)}– + {Math.min(page * PAGE_SIZE, total)} of {total} results +
+
+ + +
+
+
+ ) +} \ No newline at end of file diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx new file mode 100644 index 0000000..68551b9 --- /dev/null +++ b/src/components/ui/input.tsx @@ -0,0 +1,22 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Input = React.forwardRef>( + ({ className, type, ...props }, ref) => { + return ( + + ) + } +) +Input.displayName = "Input" + +export { Input } diff --git a/src/components/ui/skeleton.tsx b/src/components/ui/skeleton.tsx new file mode 100644 index 0000000..01b8b6d --- /dev/null +++ b/src/components/ui/skeleton.tsx @@ -0,0 +1,15 @@ +import { cn } from "@/lib/utils" + +function Skeleton({ + className, + ...props +}: React.HTMLAttributes) { + return ( +
+ ) +} + +export { Skeleton } diff --git a/src/components/ui/table.tsx b/src/components/ui/table.tsx new file mode 100644 index 0000000..7f3502f --- /dev/null +++ b/src/components/ui/table.tsx @@ -0,0 +1,117 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Table = React.forwardRef< + HTMLTableElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+ + +)) +Table.displayName = "Table" + +const TableHeader = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableHeader.displayName = "TableHeader" + +const TableBody = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableBody.displayName = "TableBody" + +const TableFooter = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + tr]:last:border-b-0", + className + )} + {...props} + /> +)) +TableFooter.displayName = "TableFooter" + +const TableRow = React.forwardRef< + HTMLTableRowElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableRow.displayName = "TableRow" + +const TableHead = React.forwardRef< + HTMLTableCellElement, + React.ThHTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +TableHead.displayName = "TableHead" + +const TableCell = React.forwardRef< + HTMLTableCellElement, + React.TdHTMLAttributes +>(({ className, ...props }, ref) => ( + +)) +TableCell.displayName = "TableCell" + +const TableCaption = React.forwardRef< + HTMLTableCaptionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +TableCaption.displayName = "TableCaption" + +export { + Table, + TableHeader, + TableBody, + TableFooter, + TableHead, + TableRow, + TableCell, + TableCaption, +} diff --git a/src/lib/fetcher.js b/src/lib/fetcher.js new file mode 100644 index 0000000..609d2d9 --- /dev/null +++ b/src/lib/fetcher.js @@ -0,0 +1 @@ +export const fetcher = (url) => fetch(url).then((res) => res.json()) \ No newline at end of file From 68bd76815d2b356e5db817a51bd0f497b8e1aabc Mon Sep 17 00:00:00 2001 From: Hubtrick-Git Date: Fri, 13 Feb 2026 13:24:25 +0100 Subject: [PATCH 5/7] saving before checkout --- package-lock.json | 151 ++++++- package.json | 1 + .../reachabilityAnalysis/columns.tsx | 2 +- .../reachability-analysis-package-details.tsx | 368 ++++++++++++++++++ .../reachability-analysis-results-table.tsx | 2 +- src/pages/reachability-analysis/[purl].mdx | 35 ++ 6 files changed, 556 insertions(+), 3 deletions(-) create mode 100644 src/components/reachabilityAnalysis/reachability-analysis-package-details.tsx create mode 100644 src/pages/reachability-analysis/[purl].mdx diff --git a/package-lock.json b/package-lock.json index 07eb174..0f15e29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,6 +39,7 @@ "react-hook-form": "^7.57.0", "react-markdown": "^9.0.3", "react-use-measure": "^2.1.7", + "recharts": "^3.7.0", "remark-gemoji": "^8.0.0", "remark-gfm": "^4.0.1", "remark-mdx-disable-explicit-jsx": "^0.1.0", @@ -4564,6 +4565,42 @@ "react": "^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0-rc.1" } }, + "node_modules/@reduxjs/toolkit": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.2.tgz", + "integrity": "sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@standard-schema/utils": "^0.3.0", + "immer": "^11.0.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@reduxjs/toolkit/node_modules/immer": { + "version": "11.1.4", + "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.4.tgz", + "integrity": "sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -4674,6 +4711,18 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, "node_modules/@swagger-api/apidom-ast": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@swagger-api/apidom-ast/-/apidom-ast-1.1.0.tgz", @@ -8400,6 +8449,12 @@ "dev": true, "license": "MIT" }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, "node_modules/decode-named-character-reference": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", @@ -8897,6 +8952,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-toolkit": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.44.0.tgz", + "integrity": "sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, "node_modules/esast-util-from-estree": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/esast-util-from-estree/-/esast-util-from-estree-2.0.0.tgz", @@ -9599,6 +9664,12 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -10892,6 +10963,16 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", + "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/immutable": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.2.tgz", @@ -16339,7 +16420,8 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/react-markdown": { "version": "9.0.3", @@ -16551,6 +16633,36 @@ "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==", "license": "MIT" }, + "node_modules/recharts": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.7.0.tgz", + "integrity": "sha512-l2VCsy3XXeraxIID9fx23eCb6iCBsxUQDnE8tWm6DFdszVAO7WVY/ChAD9wVit01y6B2PMupYiMmQwhgPHc9Ew==", + "license": "MIT", + "workspaces": [ + "www" + ], + "dependencies": { + "@reduxjs/toolkit": "1.x.x || 2.x.x", + "clsx": "^2.1.1", + "decimal.js-light": "^2.5.1", + "es-toolkit": "^1.39.3", + "eventemitter3": "^5.0.1", + "immer": "^10.1.1", + "react-redux": "8.x.x || 9.x.x", + "reselect": "5.1.1", + "tiny-invariant": "^1.3.3", + "use-sync-external-store": "^1.2.2", + "victory-vendor": "^37.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/recma-build-jsx": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/recma-build-jsx/-/recma-build-jsx-1.0.0.tgz", @@ -16622,6 +16734,15 @@ "license": "MIT", "peer": true }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -18663,6 +18784,12 @@ "license": "MIT", "peer": true }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, "node_modules/tinyexec": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", @@ -19614,6 +19741,28 @@ "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "license": "MIT" }, + "node_modules/victory-vendor": { + "version": "37.3.6", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", + "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, "node_modules/vscode-jsonrpc": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", diff --git a/package.json b/package.json index 0eeaad0..ad5536b 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "react-hook-form": "^7.57.0", "react-markdown": "^9.0.3", "react-use-measure": "^2.1.7", + "recharts": "^3.7.0", "remark-gemoji": "^8.0.0", "remark-gfm": "^4.0.1", "remark-mdx-disable-explicit-jsx": "^0.1.0", diff --git a/src/components/reachabilityAnalysis/columns.tsx b/src/components/reachabilityAnalysis/columns.tsx index 80728b3..6f5abf0 100644 --- a/src/components/reachabilityAnalysis/columns.tsx +++ b/src/components/reachabilityAnalysis/columns.tsx @@ -17,7 +17,7 @@ export const columns: ColumnDef[] = [ cell: ({ row }) => { const purl = row.getValue('purl') as string return ( - +
{purl}
) diff --git a/src/components/reachabilityAnalysis/reachability-analysis-package-details.tsx b/src/components/reachabilityAnalysis/reachability-analysis-package-details.tsx new file mode 100644 index 0000000..518d1c5 --- /dev/null +++ b/src/components/reachabilityAnalysis/reachability-analysis-package-details.tsx @@ -0,0 +1,368 @@ +import { useState } from 'react' +import { Container } from '../top-level-pages/container' +import { ReachabilityAnalysisResponse } from 'src/components/reachabilityAnalysis/reachability-types' +import { Label, Pie, PieChart } from 'recharts' +import { Skeleton } from '@/components/ui/skeleton' +import { Button } from '@/components/ui/button' +import Link from 'next/link' +import { ExternalLink } from 'lucide-react' +import { fetcher } from '@/lib/fetcher' +import useSWR from 'swr' + + + +export default function CVEDetailComponent({ purl }: { purl?: string }) { + const { data, error, isLoading } = useSWR( + purl ? `http://localhost:8080/api/v1/vulndb/reachability/${purl}` : null, + fetcher, + ) + + const [isDescriptionOpen, setIsDescriptionOpen] = useState(true) + const [isComponentsOpen, setIsComponentsOpen] = useState(false) + + const options: Intl.DateTimeFormatOptions = { + weekday: 'long', + year: 'numeric', + month: 'long', + day: 'numeric', + } + + if (isLoading) { + return ( + +
+
+
+
+
+
+ + + +
+ +
+
+
+ +
+
+
+ +
+ + + + +
+
+
+
+ +
+
+
+ + + + +
+
+ +
+
+
+ +
+ {[...Array(6)].map((_, i) => ( + + ))} +
+
+
+ + ) + } + + if (error || !data) { + return
No Package data found
+ } + + return ( + +
+
+
+
+
+
+

+ {data.serialNumber} +

+
+
+
+ + + + + + +
+
+
+
+
+
+ +
+
+
+

+ Risk Scores +

+
+
+ + BaseScore: + + + {data.risk?.baseScore.toFixed(1) ?? 'N/A'} + +
+ {data.risk?.withEnvironment && ( +
+ + With Environment: + + + {data.risk.withEnvironment.toFixed(1)} + +
+ )} + {data.risk?.withThreatIntelligence && ( +
+ + With Threat Intelligence: + + + {data.risk.withThreatIntelligence.toFixed( + 1, + )} + +
+ )} +
+ + EPSS: + + + {data.epss + ? `${(data.epss * 100).toFixed(2)}%` + : 'N/A'} + +
+
+
+
+
+
+ +
+
+
+ + {isDescriptionOpen && ( +
+

+ {data.description} +

+
+ )} +
+
+
+ +
+
+
+ + {isComponentsOpen && ( +
+
+ {data.affectedComponents.map((ac) => ( +
+

+ {ac.name} +

+ {ac.version && ( +

+ {ac.version} +

+ )} +

+ Ecosystem: {ac.ecosystem} +

+

+ {} +
Fix:{' '} + {ac.versionFixed + ? `${ac.versionFixed}%` + : 'N/A'} +

+
+ ))} +
+
+ )} +
+
+
+
+
+ +
+ +
+ + ) +} \ No newline at end of file diff --git a/src/components/reachabilityAnalysis/reachability-analysis-results-table.tsx b/src/components/reachabilityAnalysis/reachability-analysis-results-table.tsx index 9314d1c..c70bd18 100644 --- a/src/components/reachabilityAnalysis/reachability-analysis-results-table.tsx +++ b/src/components/reachabilityAnalysis/reachability-analysis-results-table.tsx @@ -96,7 +96,7 @@ export function DataTable({ } onClick={() => router.push( - `/reachability-analysis/${(row.original as Package).purl}`, + `/reachability-analysis/${encodeURIComponent((row.original as Package).purl)}`, ) } className="cursor-pointer hover:bg-muted/50" diff --git a/src/pages/reachability-analysis/[purl].mdx b/src/pages/reachability-analysis/[purl].mdx new file mode 100644 index 0000000..76838e8 --- /dev/null +++ b/src/pages/reachability-analysis/[purl].mdx @@ -0,0 +1,35 @@ +import PackageDetailComponent from 'src/components/reachabilityAnalysis/reachability-analysis-package-details' +import { useRouter } from 'next/router' + +export const PackageDetails = () => { + const router = useRouter() + const { purl } = router.query + const packageURL = Array.isArray(purl) ? purl[0] : purl + return ( + <> + + + + ) +} + + \ No newline at end of file From 3b0dd397631f8b13edd9958020dff2a533aed9fa Mon Sep 17 00:00:00 2001 From: Hubtrick-Git Date: Fri, 13 Feb 2026 19:52:50 +0100 Subject: [PATCH 6/7] functional version of frontend, visuals will be finalized when getting merged with other frontends --- .../reachabilityAnalysis/columns.tsx | 1 - .../reachability-analysis-hero.tsx | 12 +- .../reachability-analysis-package-details.tsx | 260 +++--------------- .../reachability-analysis-page.tsx | 80 +----- .../reachability-analysis-results-table.tsx | 8 + .../reachabilityAnalysis/renderData.tsx | 53 ---- 6 files changed, 56 insertions(+), 358 deletions(-) delete mode 100644 src/components/reachabilityAnalysis/renderData.tsx diff --git a/src/components/reachabilityAnalysis/columns.tsx b/src/components/reachabilityAnalysis/columns.tsx index 6f5abf0..237bd73 100644 --- a/src/components/reachabilityAnalysis/columns.tsx +++ b/src/components/reachabilityAnalysis/columns.tsx @@ -1,7 +1,6 @@ import { ColumnDef } from '@tanstack/react-table' import { ArrowUpDown } from 'lucide-react' import Link from 'next/link' -import { formatDistanceToNow, format } from 'date-fns' export type Package = { purl: string diff --git a/src/components/reachabilityAnalysis/reachability-analysis-hero.tsx b/src/components/reachabilityAnalysis/reachability-analysis-hero.tsx index 28e1e3b..ebace19 100644 --- a/src/components/reachabilityAnalysis/reachability-analysis-hero.tsx +++ b/src/components/reachabilityAnalysis/reachability-analysis-hero.tsx @@ -10,15 +10,15 @@ interface HeroProps { export default function ReachabilityAnalysisHero({searchTerm,setSearchTerm,onSearch}: HeroProps){ return ( <> -
-
+
+
-

+

Reachability Analysis

-

- Find out if your packages are affected +

+ Lorem Ipsum

{ @@ -27,7 +27,7 @@ export default function ReachabilityAnalysisHero({searchTerm,setSearchTerm,onSea }} > setSearchTerm(e.target.value) diff --git a/src/components/reachabilityAnalysis/reachability-analysis-package-details.tsx b/src/components/reachabilityAnalysis/reachability-analysis-package-details.tsx index 518d1c5..a6510ea 100644 --- a/src/components/reachabilityAnalysis/reachability-analysis-package-details.tsx +++ b/src/components/reachabilityAnalysis/reachability-analysis-package-details.tsx @@ -17,7 +17,7 @@ export default function CVEDetailComponent({ purl }: { purl?: string }) { fetcher, ) - const [isDescriptionOpen, setIsDescriptionOpen] = useState(true) + const [isVulnerabilitiesOpen, setIsVulnerabilitiesOpen] = useState(false) const [isComponentsOpen, setIsComponentsOpen] = useState(false) const options: Intl.DateTimeFormatOptions = { @@ -36,24 +36,8 @@ export default function CVEDetailComponent({ purl }: { purl?: string }) {
- - - +
- -
-
-
- -
-
-
- -
- - - -
@@ -61,26 +45,16 @@ export default function CVEDetailComponent({ purl }: { purl?: string }) {
-
- - - - +
+
-
+
-
- -
- {[...Array(6)].map((_, i) => ( - - ))} -
+
+
@@ -93,174 +67,33 @@ export default function CVEDetailComponent({ purl }: { purl?: string }) { return ( -
+

- {data.serialNumber} + {purl}

-
-
- - - - - - -
-
-
-
- -
-
-
-

- Risk Scores -

-
-
- - BaseScore: - - - {data.risk?.baseScore.toFixed(1) ?? 'N/A'} - -
- {data.risk?.withEnvironment && ( -
- - With Environment: - - - {data.risk.withEnvironment.toFixed(1)} - -
- )} - {data.risk?.withThreatIntelligence && ( -
- - With Threat Intelligence: - - - {data.risk.withThreatIntelligence.toFixed( - 1, - )} - -
- )} -
- - EPSS: - - - {data.epss - ? `${(data.epss * 100).toFixed(2)}%` - : 'N/A'} - -
-
-
-
- -
+
- {isDescriptionOpen && ( + {isComponentsOpen && (
-

- {data.description} -

+
+ {data.components.map((comp) => ( +
+

{comp.name}

+

{comp.type}

+
+ ))} +
)}
- -
+
- {isComponentsOpen && ( + {isVulnerabilitiesOpen && (
-
- {data.affectedComponents.map((ac) => ( -
-

- {ac.name} -

- {ac.version && ( -

- {ac.version} -

- )} -

- Ecosystem: {ac.ecosystem} -

-

- {} -
Fix:{' '} - {ac.versionFixed - ? `${ac.versionFixed}%` - : 'N/A'} -

+
+ {data.vulnerabilities.map((vuln) => ( +
+

{vuln.id}

+

{vuln['bom-ref']}

))}
@@ -343,10 +161,10 @@ export default function CVEDetailComponent({ purl }: { purl?: string }) {
-
+
diff --git a/src/components/reachabilityAnalysis/reachability-analysis-page.tsx b/src/components/reachabilityAnalysis/reachability-analysis-page.tsx index b3f2ed1..69302de 100644 --- a/src/components/reachabilityAnalysis/reachability-analysis-page.tsx +++ b/src/components/reachabilityAnalysis/reachability-analysis-page.tsx @@ -23,7 +23,7 @@ export default function ReachabilityAnalysisPage() { let url = null if (router.isReady && pageParam) { - url = `http://localhost:8080/api/v1/vulndb/reachability/test?pageSize=10&page=${page}` + url = `http://localhost:8080/api/v1/vulndb/reachability?pageSize=10&page=${page}` if (query) { url += `&filterQuery[npm][like]=%25${query}%25` } @@ -55,7 +55,7 @@ export default function ReachabilityAnalysisPage() { return ( -
+
) -} - -// export function ReachabilityAnalysisHero() { -// return ( -//
-//
-//

-// Reachability Analysis -//

-//

-// This page enables you to search for a npm package and get a list of all CVEs associated with it. -// Additionally you get information about whether the CVE is actually affecting this package or not. -//

-//
-//

-//
-//
-// ) -// } - -// export const apiCall = ( baseURL: string,params: string,init?: RequestInit) => { -// return fetch(baseURL + params,init) -// } - -// export function ReachabilityAnalysisSearchBar() { -// const [input,setInput] = useState("") -// const [data, setData] = useState(); -// const [isLoading, setIsLoading] = useState(false); -// const [error, setError] = useState(false); - -// const getData = async () => { -// setIsLoading(true) -// try{ -// const response = await fetch(apiBaseURL+input) -// const data = await response.json() -// setIsLoading(false) - -// if (!data || !response.ok) { -// window.alert("error when trying to fetch data from api endpoint") -// } -// setData(data) -// }catch{ -// setError(true) -// }finally{ -// setIsLoading(false) -// } -// } - -// const onSubmit: FormEventHandler = (e) => { -// e.preventDefault() -// getData() -// } - - -// return ( -//
-// -// -//
-// {setInput(e.target.value)}} -// className="text-center block w-1/3 mx-auto focus:w-full text-xl rounded-full bg-white/5 px-5 py-2 text-white outline outline-1 -outline-offset-1 outline-white/50 focus:outline-3 focus:outline-white/70 placeholder:text-gray-500 focus:placeholder:opacity-0 transition-all duration-300 ease-in-out" -// /> -//
-// -// -//
-// ) -// } +} \ No newline at end of file diff --git a/src/components/reachabilityAnalysis/reachability-analysis-results-table.tsx b/src/components/reachabilityAnalysis/reachability-analysis-results-table.tsx index c70bd18..978cfce 100644 --- a/src/components/reachabilityAnalysis/reachability-analysis-results-table.tsx +++ b/src/components/reachabilityAnalysis/reachability-analysis-results-table.tsx @@ -7,6 +7,7 @@ import {ColumnDef,SortingState,flexRender,getCoreRowModel,getSortedRowModel,useR import * as React from 'react' import { useRouter } from 'next/navigation' import { Package } from './columns' +import { Island_Moments } from 'next/font/google' const PAGE_SIZE = 10 @@ -47,6 +48,13 @@ export function DataTable({ }, }) + if (!isLoading && data.length == 0) { + return ( +
+
+ ) + } + return (
diff --git a/src/components/reachabilityAnalysis/renderData.tsx b/src/components/reachabilityAnalysis/renderData.tsx deleted file mode 100644 index 3daab62..0000000 --- a/src/components/reachabilityAnalysis/renderData.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import React from "react"; -import { ReachabilityAnalysisResponse } from "./reachability-types"; -import { d } from "nextra/dist/types-BhjhW0gX"; - -interface fetchResults{ - loading: boolean - error : boolean - data? : ReachabilityAnalysisResponse -} - -interface tableEntry { - component : string - type : string - count : string -} - -const AnalysisResultsTable: React.FC = ({loading,error,data}) => { - if (loading && !error) { - return
Loading
- } - if (!loading && error){ - return
Error occurred
- } - if (!data){ - return
No data in response
- } - - if (!loading && !error && data){ - return ( -
- - - - - - - - - {data.components.map((component, index) => ( - - - - - ))} - -
ComponentType
{component.purl}{component.type}
-
- ) - } - return
undefined behavior
-} - -export default AnalysisResultsTable \ No newline at end of file From c3ca7d83bcda9e39517e781e3aa5a499940857d0 Mon Sep 17 00:00:00 2001 From: Patrick Date: Fri, 13 Feb 2026 19:55:40 +0100 Subject: [PATCH 7/7] Update .gitignore to include .env and Sentry files revert gitignore --- .gitignore | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index b5e08c2..376aff4 100644 --- a/.gitignore +++ b/.gitignore @@ -18,22 +18,25 @@ # misc .DS_Store *.pem -.vscode/* # debug npm-debug.log* yarn-debug.log* yarn-error.log* -.pnpm-debug.log* # local env files .env*.local +.env + # vercel .vercel -.env +# typescript +*.tsbuildinfo +next-env.d.ts + -/public/robots.txt -/public/sitemap.xml -/public/sitemap-0.xml \ No newline at end of file +image.tar +# Sentry Config File +.env.sentry-build-plugin