-
Notifications
You must be signed in to change notification settings - Fork 2
Build Reachability Frontend #72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
ecb21e7
7add69d
ee7431b
00e71fc
68bd768
3b0dd39
c3ca7d8
0672ffd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -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", | ||||
|
|
@@ -62,12 +64,14 @@ | |||
| "react-hook-form": "^7.57.0", | ||||
| "react-markdown": "^9.0.3", | ||||
| "react-use-measure": "^2.1.7", | ||||
| "recharts": "^3.7.0", | ||||
|
||||
| "recharts": "^3.7.0", |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import { ColumnDef } from '@tanstack/react-table' | ||
| import { ArrowUpDown } from 'lucide-react' | ||
| import Link from 'next/link' | ||
|
|
||
| export type Package = { | ||
| purl: string | ||
| type: string | ||
| name: string | ||
| } | ||
|
|
||
| export const columns: ColumnDef<Package>[] = [ | ||
| { | ||
| accessorKey: 'purl', | ||
| header: 'Package URL', | ||
| size: 150, | ||
| cell: ({ row }) => { | ||
| const purl = row.getValue('purl') as string | ||
| return ( | ||
| <Link href={`/reachability-analysis/${encodeURIComponent(purl)}`}> | ||
| <div className="w-32">{purl}</div> | ||
| </Link> | ||
| ) | ||
| }, | ||
| }, | ||
| { | ||
| accessorKey: 'type', | ||
| header: 'Package Type', | ||
| size: 600, | ||
| cell: ({ row }) => { | ||
| const type = row.getValue('type') as string | ||
| return <div className="w-108">{type}</div> | ||
| }, | ||
| }, | ||
| { | ||
| accessorKey: 'name', | ||
| size: 150, | ||
| header: ({ column }) => { | ||
| return ( | ||
| <div | ||
| className="flex cursor-pointer items-center hover:text-accent-foreground" | ||
| onClick={() => | ||
| column.toggleSorting(column.getIsSorted() === 'asc') | ||
| } | ||
| > | ||
| Package Name | ||
| <ArrowUpDown className="ml-2 h-4 w-4" /> | ||
| </div> | ||
| ) | ||
| }, | ||
| cell: ({ row }) => { | ||
| const name = row.getValue('name') as string | ||
| return <div className="w-32">{name}</div> | ||
| }, | ||
| }, | ||
| ] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 ( | ||
| <> | ||
| <div className="mx-auto max-w-7xl ml-16 pb-40 pt-32"> | ||
| <div className="px-6"> | ||
| <div className="mx-auto max-w-2xl"> | ||
| <div className="max-w-lg"> | ||
| <h1 className="mt-10 text-pretty text-5xl text-center font-semibold tracking-tight text-white sm:text-7xl"> | ||
| Reachability Analysis | ||
| </h1> | ||
| <p className="mt-4 text-pretty text-center text-lg font-large text-gray-400 sm:text-xl/8"> | ||
| Lorem Ipsum | ||
Hubtrick-Git marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| </p> | ||
| <form | ||
| onSubmit={(e) => { | ||
| e.preventDefault() | ||
| onSearch() | ||
| }} | ||
| > | ||
| <Input | ||
| className="mt-8 !text-2xl py-6 text-center rounded-full" | ||
| value={searchTerm} | ||
| onChange={(e) => | ||
| setSearchTerm(e.target.value) | ||
| } | ||
| /> | ||
Hubtrick-Git marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| </form> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </> | ||
| ) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,177 @@ | ||
| import { useState } from 'react' | ||
| import { Container } from '../top-level-pages/container' | ||
| import { ReachabilityAnalysisResponse } from 'src/components/reachabilityAnalysis/reachability-types' | ||
| 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 'src/lib/fetcher' | ||
| import useSWR from 'swr' | ||
|
|
||
|
|
||
|
|
||
| export default function ReachabilityAnalysisPackageDetails({ purl }: { purl?: string }) { | ||
| const { data, error, isLoading } = useSWR<ReachabilityAnalysisResponse>( | ||
| purl ? `http://localhost:8080/api/v1/vulndb/reachability/${purl}` : null, | ||
Hubtrick-Git marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| fetcher, | ||
| ) | ||
|
|
||
| const [isVulnerabilitiesOpen, setIsVulnerabilitiesOpen] = useState(false) | ||
| const [isComponentsOpen, setIsComponentsOpen] = useState(false) | ||
|
|
||
| if (isLoading) { | ||
| return ( | ||
| <Container> | ||
| <div className="mb-6 grid gap-4 lg:grid-cols-3"> | ||
| <div className="relative lg:col-span-2"> | ||
| <div className="absolute inset-px rounded-lg bg-white dark:bg-gray-800" /> | ||
| <div className="relative flex flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)] p-8"> | ||
| <div className="flex items-start justify-between"> | ||
| <div className="space-y-3"> | ||
| <Skeleton className="h-9 w-96" /> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div className="relative mb-6"> | ||
| <div className="absolute inset-px rounded-lg bg-white dark:bg-gray-800" /> | ||
| <div className="relative flex flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)] p-7"> | ||
| <Skeleton className="h-6 w-40" /> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div className="relative mb-4"> | ||
| <div className="absolute inset-px rounded-lg bg-white dark:bg-gray-800" /> | ||
| <div className="relative flex flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)] p-7"> | ||
| <Skeleton className="h-6 w-48"/> | ||
| </div> | ||
| </div> | ||
| </Container> | ||
| ) | ||
| } | ||
|
|
||
| if (error || !data) { | ||
| return <div>No Package data found</div> | ||
| } | ||
|
|
||
| return ( | ||
| <Container> | ||
| <div className="mb-6 grid gap-4 lg:grid-cols-3 w-3/4"> | ||
| <div className="relative lg:col-span-2"> | ||
| <div className="absolute inset-px rounded-lg bg-white dark:bg-gray-800" /> | ||
| <div className="relative flex flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)] p-8"> | ||
| <div className="flex items-start justify-between"> | ||
| <div> | ||
| <h1 className="text-3xl font-bold text-gray-950 dark:text-white"> | ||
| {purl} | ||
| </h1> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div className="relative mt-6"> | ||
| <div className="absolute inset-px rounded-lg bg-white dark:bg-gray-800" /> | ||
| <div className="relative flex flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)]"> | ||
| <button | ||
| onClick={() => setIsComponentsOpen(!isComponentsOpen)} | ||
| className="flex w-full items-center justify-between p-6 text-left transition-colors hover:bg-gray-50 dark:hover:bg-gray-700/50" | ||
| > | ||
| <h2 className="text-lg font-medium text-gray-950 dark:text-white"> | ||
| Components ( | ||
| {data.components.length}) | ||
| </h2> | ||
| <svg | ||
| className={`h-5 w-5 transition-transform ${isComponentsOpen ? 'rotate-180' : ''}`} | ||
| fill="none" | ||
| stroke="currentColor" | ||
| viewBox="0 0 24 24" | ||
| > | ||
| <path | ||
| strokeLinecap="round" | ||
| strokeLinejoin="round" | ||
| strokeWidth={2} | ||
| d="M19 9l-7 7-7-7" | ||
| /> | ||
| </svg> | ||
| </button> | ||
Hubtrick-Git marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| {isComponentsOpen && ( | ||
| <div className="px-8 pb-8"> | ||
| <div> | ||
| {data.components.map((comp) => ( | ||
| <div className='flex'> | ||
| <p className='px-4 mx-8 my-4 py-4 rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900/50'>{comp.name}</p> | ||
| <p className='px-4 mx-8 my-4 py-4 rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900/50'>{comp.type}</p> | ||
| </div> | ||
| ))} | ||
Hubtrick-Git marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| </div> | ||
| </div> | ||
| )} | ||
| </div> | ||
| <div className="pointer-events-none absolute inset-px rounded-lg shadow outline outline-1 outline-black/5 dark:outline-white/15" /> | ||
| </div> | ||
| <div className="relative mt-6"> | ||
| <div className="absolute inset-px rounded-lg bg-white dark:bg-gray-800" /> | ||
| <div className="relative flex flex-col overflow-hidden rounded-[calc(theme(borderRadius.lg)+1px)]"> | ||
| <button | ||
| onClick={() => setIsVulnerabilitiesOpen(!isVulnerabilitiesOpen)} | ||
| className="flex w-full items-center justify-between p-6 text-left transition-colors hover:bg-gray-50 dark:hover:bg-gray-700/50" | ||
| > | ||
| <h2 className="text-lg font-medium text-gray-950 dark:text-white"> | ||
| Vulnerabilities ( | ||
| {data.vulnerabilities.length}) | ||
| </h2> | ||
| <svg | ||
| className={`h-5 w-5 transition-transform ${isVulnerabilitiesOpen ? 'rotate-180' : ''}`} | ||
| fill="none" | ||
| stroke="currentColor" | ||
| viewBox="0 0 24 24" | ||
| > | ||
| <path | ||
| strokeLinecap="round" | ||
| strokeLinejoin="round" | ||
| strokeWidth={2} | ||
| d="M19 9l-7 7-7-7" | ||
| /> | ||
| </svg> | ||
| </button> | ||
Hubtrick-Git marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| {isVulnerabilitiesOpen && ( | ||
| <div className="px-8 pb-8"> | ||
| <div> | ||
| {data.vulnerabilities.map((vuln) => ( | ||
| <div className='flex'> | ||
| <p className='px-4 mx-8 my-4 py-4 rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900/50'>{vuln.id}</p> | ||
| <p className='px-4 mx-8 my-4 py-4 rounded-lg border border-gray-200 bg-gray-50 p-4 dark:border-gray-700 dark:bg-gray-900/50'>{vuln['bom-ref']}</p> | ||
| </div> | ||
| ))} | ||
| </div> | ||
| </div> | ||
Hubtrick-Git marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| )} | ||
| </div> | ||
| <div className="pointer-events-none absolute inset-px rounded-lg shadow outline outline-1 outline-black/5 dark:outline-white/15" /> | ||
| </div> | ||
| <div className="mt-8 flex gap-3"> | ||
| <div> | ||
| <Button> | ||
| <Link href="/reachability-analysis/">Get Back</Link> | ||
| </Button> | ||
| </div> | ||
| <div> | ||
| <Button> | ||
| <a | ||
| target="_blank" | ||
| href="https://main.devguard.org/" | ||
| rel="noopener noreferrer" | ||
| className="flex items-center gap-2" | ||
| > | ||
| Try DevGuard | ||
| <ExternalLink size={16} /> | ||
| </a> | ||
| </Button> | ||
| </div> | ||
| </div> | ||
| </Container> | ||
| ) | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.