Conversation
|
Looks nice 😊 - like that small micro animation when typing away..... |
timbastin
left a comment
There was a problem hiding this comment.
Overall, this looks really great! I love the splitting in table and hero. I think we can improve this further by extracting the whole logic into a container component which just renders some presentational components while providing state and mutation functions.
…skeleton load and proper display in a table
…g merged with other frontends
revert gitignore
There was a problem hiding this comment.
Pull request overview
This PR introduces a new reachability analysis feature to the frontend, adding search functionality and visualization for vulnerability reachability data. The feature includes a main search page, detail pages for individual packages, and supporting UI components. The implementation uses placeholder API endpoints since the backend is not yet finalized, as noted in the PR description.
Changes:
- Added new reachability analysis pages with search and display functionality
- Integrated new dependencies (SWR for data fetching, TanStack Table for data tables, Recharts for future visualizations)
- Created reusable UI components (table, skeleton, input) following shadcn/ui patterns
Reviewed changes
Copilot reviewed 14 out of 16 changed files in this pull request and generated 26 comments.
Show a summary per file
| File | Description |
|---|---|
| src/pages/reachability-analysis.mdx | Main entry point for reachability analysis page |
| src/pages/reachability-analysis/[purl].mdx | Dynamic route for package-specific details with custom styling |
| src/pages/_meta.ts | Navigation configuration for new reachability page |
| src/lib/fetcher.js | Simple fetcher utility for SWR data fetching |
| src/components/ui/table.tsx | Reusable table component following shadcn/ui patterns |
| src/components/ui/skeleton.tsx | Loading skeleton component for better UX |
| src/components/ui/input.tsx | Form input component with consistent styling |
| src/components/reachabilityAnalysis/reachability-types.tsx | TypeScript type definitions for API responses |
| src/components/reachabilityAnalysis/reachability-analysis-results-table.tsx | Table component displaying search results with pagination |
| src/components/reachabilityAnalysis/reachability-analysis-page.tsx | Main page component managing search state and API calls |
| src/components/reachabilityAnalysis/reachability-analysis-package-details.tsx | Detail view for individual packages with collapsible sections |
| src/components/reachabilityAnalysis/reachability-analysis-hero.tsx | Hero section with search input |
| src/components/reachabilityAnalysis/columns.tsx | Column definitions for data table |
| package.json | Added dependencies for SWR, TanStack Table, Recharts, and date-fns |
| package-lock.json | Lockfile updates for new dependencies |
| .gitignore | Minor cleanup and reorganization |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import { fetcher } from 'src/lib/fetcher' | ||
| import useSWR from 'swr' | ||
|
|
||
| const apiBaseURL = 'http://localhost:8080/api/v1/vulndb/reachability/' |
There was a problem hiding this comment.
The unused constant 'apiBaseURL' is declared but never used. Consider removing it or using it instead of the hardcoded URL on line 26.
|
|
||
|
|
||
|
|
||
| export default function CVEDetailComponent({ purl }: { purl?: string }) { |
There was a problem hiding this comment.
The function is named 'CVEDetailComponent' but it displays package details for reachability analysis, not CVE details. The name should be updated to 'PackageDetailComponent' or 'ReachabilityAnalysisPackageDetails' to accurately reflect its purpose.
| export default function CVEDetailComponent({ purl }: { purl?: string }) { | |
| export default function ReachabilityAnalysisPackageDetails({ purl }: { purl?: string }) { |
| <Skeleton className="h-6 w-48" | ||
| /> |
There was a problem hiding this comment.
There's a missing closing tag for the Skeleton component. The line should end with '/>' instead of just '/>'. This will cause a syntax error.
| <Skeleton className="h-6 w-48" | |
| /> | |
| <Skeleton className="h-6 w-48" /> |
| <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> |
There was a problem hiding this comment.
Missing key prop in the map function. Each element in the list should have a unique 'key' prop for React to efficiently update the list. Add a unique key based on vulnerability data.
| <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> | |
| <div> | |
| {data.vulnerabilities.map((vuln) => ( | |
| <div className="flex" key={vuln.id}> | |
| <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> |
| <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> |
There was a problem hiding this comment.
Similar to the Components section, this collapsible Vulnerabilities button lacks proper ARIA attributes. Add aria-expanded={isVulnerabilitiesOpen} to indicate its state to screen reader users.
| const description = row.getValue('type') as string | ||
| return <div className="w-108">{description}</div> |
There was a problem hiding this comment.
The variable 'description' is misleading since it's actually holding the 'type' value, not a description. Rename to 'type' or 'packageType' for clarity.
| const description = row.getValue('type') as string | |
| return <div className="w-108">{description}</div> | |
| const packageType = row.getValue('type') as string | |
| return <div className="w-108">{packageType}</div> |
| 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' |
There was a problem hiding this comment.
The imports 'Label', 'Pie', and 'PieChart' from 'recharts' are unused and should be removed.
| import { Label, Pie, PieChart } from 'recharts' |
| {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> | ||
| ))} |
There was a problem hiding this comment.
Missing key prop in the map function. Each element in the list should have a unique 'key' prop for React to efficiently update the list. Add a unique key based on component data.
| 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 |
There was a problem hiding this comment.
The interface properties are using inline type definitions with spaces around the colon (e.g., 'bomFormat : string'). TypeScript convention is to have no space before the colon and one space after (e.g., 'bomFormat: string') for consistency with the rest of the codebase.
|
|
||
| if (!isLoading && data.length == 0) { | ||
| return ( | ||
| <div className='my-40'> |
There was a problem hiding this comment.
When there's no data and not loading, an empty div is returned with no user feedback. Consider displaying a message like "No packages found. Try searching for a package." to improve user experience.
| <div className='my-40'> | |
| <div className="my-40 flex items-center justify-center text-sm text-muted-foreground"> | |
| No packages found. Try searching for a package. |
Minimal requirements:
Functional Requirements:
Stylistic Requirements:
Finalized status