Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces “quick-fix” (fixable) vulnerability indicators into the project overview dashboard by extending RiskHistory with fixable-related fields and adding new UI elements to surface those counts.
Changes:
- Add quick-fix/fixable fields to
RiskHistoryand propagate them through padding and aggregation utilities. - Update
SeverityCardto display a fixable badge, and add a newQuickfixNotificationcard on the overview page. - Add a Renovate SVG asset for the “Create PR” CTA.
Reviewed changes
Copilot reviewed 6 out of 7 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| src/utils/view.ts | Adds a mock fixable-enrichment helper and extends risk history reduction to include fixable totals. |
| src/utils/server.ts | Pads risk history entries with new fixable/total fields. |
| src/types/api/api.ts | Extends the RiskHistory type with fixable and total fields. |
| src/components/SeverityCard.tsx | Adds fixableAmount prop and renders a fixable badge overlay. |
| src/components/QuickfixNotification.tsx | New component to show quick-fix vs manual counts and a “Create PR” CTA. |
| src/app/(loading-group)/.../overview/page.tsx | Computes fixable totals and renders QuickfixNotification; wires fixable counts into SeverityCard. |
| public/assets/Renovate.svg | Adds a Renovate icon asset for the CTA. |
Comments suppressed due to low confidence (1)
src/components/SeverityCard.tsx:28
fixableAmountwas added as a required prop, but there are existingSeverityCardcall sites that don't pass it (e.g. the asset ref page). This will break TypeScript builds. MakefixableAmountoptional with a default of 0 (or provide a sensible fallback in the component) so existing usages remain valid, then incrementally update callers.
interface Props {
currentAmount: number;
fixableAmount: number;
queryIntervalStart: number;
queryIntervalEnd: number;
variant: "high" | "medium" | "low" | "critical";
mode?: "risk" | "cvss";
isLoading: boolean;
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| import { ArrowRightIcon, FileTextIcon, WrenchIcon } from "lucide-react"; | ||
| import { Button } from "./ui/button"; | ||
| import { Card, CardContent } from "./ui/card"; | ||
| import { Progress } from "./ui/progress"; |
There was a problem hiding this comment.
The import of Progress is unused. With the repo's ESLint setup (next/core-web-vitals), this will be reported as an unused import; remove it or actually use the component.
| import { Progress } from "./ui/progress"; |
| <Button variant="default" className="gap-2"> | ||
| <Image | ||
| src="/assets/renovate.svg" | ||
| alt="Renovate icon" | ||
| width={16} | ||
| height={16} | ||
| /> |
There was a problem hiding this comment.
The Renovate icon path casing doesn't match the file added in this PR (public/assets/Renovate.svg). On case-sensitive filesystems this will 404. Either rename the asset to public/assets/renovate.svg or update src to /assets/Renovate.svg to match exactly.
| const completeRiskHistory: RiskHistory[][] = useMemo(() => { | ||
| const groups = groupBy(riskHistory ?? [], "day"); | ||
| const groups = groupBy( | ||
| withMockFixableRiskHistory(riskHistory ?? []), | ||
| "day", | ||
| ); |
There was a problem hiding this comment.
withMockFixableRiskHistory(...) injects fabricated totals/fixable counts (see its implementation in utils/view). Using this in the overview page means the UI will display incorrect numbers in non-dev environments. This should be removed or gated (e.g. behind a dev/feature flag) and replaced with real API-provided fixable metrics.
| import { toast } from "sonner"; | ||
| import { useSession } from "@/context/SessionContext"; | ||
| import { browserApiClient } from "../../../../../../services/devGuardApi"; | ||
| import Callout from "@/components/common/Callout"; |
There was a problem hiding this comment.
Callout is imported but never used in this file, which will trigger unused-import linting. Remove the import or use the component.
| import Callout from "@/components/common/Callout"; |
| console.log(quickfixAmount); | ||
|
|
There was a problem hiding this comment.
Leftover debug logging: console.log(quickfixAmount) will spam the browser console for every render. Remove this (or replace with proper instrumentation if needed).
| console.log(quickfixAmount); |
| /> | ||
| </div> | ||
| <div className="grid grid-cols-2 gap-4"> | ||
| <div className="col-2"> |
There was a problem hiding this comment.
className="col-2" doesn't correspond to a standard Tailwind grid utility (likely intended col-span-2). As written, this wrapper probably won't span both columns and may break the layout.
| <div className="col-2"> | |
| <div className="col-span-2"> |
| fixableLow: entry.fixableLow ?? 2, | ||
| fixableMedium: entry.fixableMedium ?? 7, | ||
| fixableHigh: entry.fixableHigh ?? entry.high * 9, | ||
| fixableCritical: entry.fixableCritical ?? entry.critical * 15, | ||
| cvePurlFixableLow: | ||
| entry.cvePurlFixableLow ?? Math.floor(entry.cvePurlLow / 2), | ||
| cvePurlFixableMedium: | ||
| entry.cvePurlFixableMedium ?? Math.floor(entry.cvePurlMedium / 4), | ||
| cvePurlFixableHigh: | ||
| entry.cvePurlFixableHigh ?? Math.floor(entry.cvePurlHigh / 3), | ||
| cvePurlFixableCritical: | ||
| entry.cvePurlFixableCritical ?? Math.floor(entry.cvePurlCritical / 2), |
There was a problem hiding this comment.
withMockFixableRiskHistory generates hard-coded / derived "fixable" values (e.g. constants like 2, 7, and multipliers like entry.high * 9). Since this function is exported from a shared util and is now used in the overview page, it can easily leak mocked data into production UX. Prefer removing it from shared utils (or clearly scoping it to dev/test) and rely on backend-provided fields instead.
| fixableLow: entry.fixableLow ?? 2, | |
| fixableMedium: entry.fixableMedium ?? 7, | |
| fixableHigh: entry.fixableHigh ?? entry.high * 9, | |
| fixableCritical: entry.fixableCritical ?? entry.critical * 15, | |
| cvePurlFixableLow: | |
| entry.cvePurlFixableLow ?? Math.floor(entry.cvePurlLow / 2), | |
| cvePurlFixableMedium: | |
| entry.cvePurlFixableMedium ?? Math.floor(entry.cvePurlMedium / 4), | |
| cvePurlFixableHigh: | |
| entry.cvePurlFixableHigh ?? Math.floor(entry.cvePurlHigh / 3), | |
| cvePurlFixableCritical: | |
| entry.cvePurlFixableCritical ?? Math.floor(entry.cvePurlCritical / 2), |
| return dayHistories.reduce( | ||
| (acc, curr) => { | ||
| acc.cvePurlLow += curr.cvePurlLow; | ||
| acc.cvePurlMedium += curr.cvePurlMedium; | ||
| acc.cvePurlHigh += curr.cvePurlHigh; | ||
| acc.cvePurlCritical += curr.cvePurlCritical; | ||
| acc.cvePurlFixableLow += curr.cvePurlFixableLow ?? 0; | ||
| acc.cvePurlFixableMedium += curr.cvePurlFixableMedium ?? 0; | ||
| acc.cvePurlFixableHigh += curr.cvePurlFixableHigh ?? 0; | ||
| acc.cvePurlFixableCritical += curr.cvePurlFixableCritical ?? 0; | ||
| acc.cvePurlLowCvss += curr.cvePurlLowCvss; | ||
| acc.cvePurlMediumCvss += curr.cvePurlMediumCvss; | ||
| acc.cvePurlHighCvss += curr.cvePurlHighCvss; | ||
| acc.cvePurlCriticalCvss += curr.cvePurlCriticalCvss; | ||
| acc.totalAmount = (acc.totalAmount ?? 0) + (curr.totalAmount ?? 0); | ||
| return acc; | ||
| }, | ||
| { | ||
| id: dayHistories[0]?.id || "", | ||
| day: dayHistories[0]?.day || new Date(), | ||
| assetId: dayHistories[0]?.assetId || "", | ||
| artifactName: dayHistories[0]?.artifactName || "", | ||
| cvePurlLow: 0, | ||
| cvePurlMedium: 0, | ||
| cvePurlHigh: 0, | ||
| cvePurlCritical: 0, | ||
| cvePurlFixableLow: 0, | ||
| cvePurlFixableMedium: 0, | ||
| cvePurlFixableHigh: 0, | ||
| cvePurlFixableCritical: 0, | ||
| cvePurlLowCvss: 0, | ||
| cvePurlMediumCvss: 0, | ||
| cvePurlHighCvss: 0, | ||
| cvePurlCriticalCvss: 0, | ||
| totalAmount: 0, | ||
| } as RiskHistory, |
There was a problem hiding this comment.
reduceRiskHistories now sums cvePurlFixable* and totalAmount, but the accumulator object is still cast to RiskHistory while missing newly required fields like fixableLow/fixableMedium/fixableHigh/fixableCritical (and it never aggregates them). This can lead to undefined values downstream despite the type claiming they exist. Initialize these fields (and add them in the reducer) or make the new fields optional on RiskHistory if they aren't guaranteed.
| fixableLow: number; | ||
| fixableMedium: number; | ||
| fixableHigh: number; | ||
| fixableCritical: number; | ||
|
|
||
| cvePurlFixableLow: number; | ||
| cvePurlFixableMedium: number; | ||
| cvePurlFixableHigh: number; | ||
| cvePurlFixableCritical: number; |
There was a problem hiding this comment.
These new RiskHistory properties (fixable*, cvePurlFixable*, totalAmount) are being treated as nullable/derived elsewhere (lots of ?? 0 and even mock filling). Making them required here means all RiskHistory objects in the codebase are now expected to contain them (note RiskHistory is declared twice in this file and the interfaces merge). If the backend doesn't always send these fields yet, mark them optional (or split into a separate extended type) to avoid incorrect type guarantees and forced as RiskHistory casts.
| fixableLow: number; | |
| fixableMedium: number; | |
| fixableHigh: number; | |
| fixableCritical: number; | |
| cvePurlFixableLow: number; | |
| cvePurlFixableMedium: number; | |
| cvePurlFixableHigh: number; | |
| cvePurlFixableCritical: number; | |
| fixableLow?: number; | |
| fixableMedium?: number; | |
| fixableHigh?: number; | |
| fixableCritical?: number; | |
| cvePurlFixableLow?: number; | |
| cvePurlFixableMedium?: number; | |
| cvePurlFixableHigh?: number; | |
| cvePurlFixableCritical?: number; |
No description provided.