style(viewer): move false-positive controls below finding details

This commit is contained in:
bearsyankees 2026-09-16 19:02:53 -04:00
parent 23fb424239
commit 65188b28fb
7 changed files with 149 additions and 152 deletions

View file

@ -42,7 +42,7 @@ The UI ships prebuilt with Strix, so there is no extra install and no JavaScript
## Marking False Positives
Open a finding and choose **Mark as false positive** when it is incorrect or does not apply to your target. Choose an optional reason, add an optional note of up to 2,000 characters for future review, and select **Close issue**. The finding shows **Closed · False positive**. Use **Undo** or **Reopen** to reverse the decision.
At the bottom of a finding, choose **Mark as false positive** when it is incorrect or does not apply to your target. Choose an optional reason, add an optional note of up to 2,000 characters for future review, and select **Close issue**. The finding shows **Closed · False positive**. Use **Undo** or **Reopen** to reverse the decision.
The **Open / Closed / All** filters keep closed findings available with their original severity and evidence. Counts distinguish open findings from false positives and the total detected. Closing an issue does not mean it was fixed.

View file

@ -77,7 +77,7 @@ export function TriageControls({ finding, onSave }: { finding: Vulnerability; on
ref={triggerRef}
type="button"
disabled={!finding.can_triage || pending}
className={buttonClass}
className="cursor-pointer rounded px-1 py-1.5 text-xs text-[#888] transition-colors hover:text-white focus-visible:outline focus-visible:outline-offset-4 focus-visible:outline-[#666] disabled:cursor-not-allowed disabled:opacity-50"
onClick={() => {
setError(null);
setMessage(null);
@ -88,16 +88,16 @@ export function TriageControls({ finding, onSave }: { finding: Vulnerability; on
{pending ? "Saving…" : finding.status === "closed" ? "Reopen" : "Mark as false positive"}
</button>
{!finding.can_triage && <span className="text-xs text-[#999]">Triage is unavailable for this finding or run.</span>}
{message && <span className="text-sm text-[#aaa]" role="status">{message}</span>}
{message && <span className="text-xs text-[#aaa]" role="status">{message}</span>}
{undo && (
<button type="button" className="text-sm text-white underline disabled:opacity-50" disabled={pending}
<button type="button" className="text-xs text-[#aaa] underline hover:text-white disabled:opacity-50" disabled={pending}
onClick={() => void save(undo.finding, undo.update, true)}>Undo</button>
)}
</div>
{error && <p role="alert" className="text-sm text-red-300">{error}</p>}
{reviewed && (
<form
className="max-w-2xl space-y-4 rounded-xl border border-[#444] bg-[#111] p-4 sm:p-5"
className="max-w-xl space-y-3 rounded-lg border border-[#2a2a2a] bg-[#111] p-4"
aria-labelledby="triage-title"
onSubmit={(event) => {
event.preventDefault();
@ -108,9 +108,8 @@ export function TriageControls({ finding, onSave }: { finding: Vulnerability; on
}}
>
<div>
<h2 id="triage-title" className="text-base font-semibold text-white">Mark as false positive</h2>
<p className="mt-1 text-sm text-[#aaa]">This finding is incorrect or does not apply to your target.</p>
<p className="mt-1 text-xs text-[#888]">Applies to this finding in this run. A later scan may report it again.</p>
<h2 id="triage-title" className="text-sm font-medium text-white">Mark as false positive</h2>
<p className="mt-1 text-xs text-[#888]">Applies to this finding in this run. You can reopen it anytime.</p>
</div>
<label className="block text-sm text-[#bbb]">
Reason (optional)
@ -123,17 +122,14 @@ export function TriageControls({ finding, onSave }: { finding: Vulnerability; on
<label className="block text-sm text-[#bbb]">
Note (optional)
<textarea value={note} onChange={(event) => setNote(event.target.value)} maxLength={2000}
disabled={pending} rows={3} placeholder="Add context for your future review"
disabled={pending} rows={2} placeholder="Add context for your future review"
className="mt-1.5 block w-full resize-y rounded-lg border border-[#444] bg-[#161616] px-3 py-2 text-sm text-white" />
</label>
{changed && <p role="alert" className="text-sm text-amber-300">This finding changed while the form was open. Cancel and review its current evidence before marking it again.</p>}
<div className="flex flex-wrap items-center justify-between gap-3">
<button type="button" onClick={closeForm} disabled={pending} className="text-sm text-[#aaa] hover:text-white disabled:opacity-50">Not sure? Keep open for review</button>
<div className="flex gap-2">
<button type="button" onClick={closeForm} disabled={pending} className={buttonClass}>Cancel</button>
<button type="submit" disabled={pending || !!changed || !finding.can_triage}
className="rounded-lg bg-white px-3 py-1.5 text-sm font-semibold text-black disabled:opacity-50">{pending ? "Saving…" : "Close issue"}</button>
</div>
<div className="flex justify-end gap-2">
<button type="button" onClick={closeForm} disabled={pending} className={buttonClass}>Cancel</button>
<button type="submit" disabled={pending || !!changed || !finding.can_triage}
className="rounded-lg bg-white px-3 py-1.5 text-sm font-semibold text-black disabled:opacity-50">{pending ? "Saving…" : "Close issue"}</button>
</div>
</form>
)}

View file

@ -124,8 +124,6 @@ export default function VulnerabilityDetail({ vulnerability, onTriage }: Vulnera
</div>
</div>
<TriageControls finding={vulnerability} onSave={onTriage} />
{vulnerability.review_stale && (
<p className="rounded-lg border border-amber-500/30 bg-amber-500/5 p-4 text-sm text-amber-200" role="status">
Evidence changed since the previous false-positive decision. This finding is open for review.
@ -275,6 +273,9 @@ export default function VulnerabilityDetail({ vulnerability, onTriage }: Vulnera
</div>
</div>
<div className="border-t border-[#222] pt-4">
<TriageControls finding={vulnerability} onSave={onTriage} />
</div>
</div>
);
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -6,8 +6,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="color-scheme" content="dark" />
<title>Strix Results</title>
<script type="module" crossorigin src="./assets/index-CY2QniKa.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-CBqNY5AA.css">
<script type="module" crossorigin src="./assets/index-CMYkx6m6.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-DNOJaOMX.css">
</head>
<body>
<div id="root"></div>