fix(security): fix Security page table layouts and exploit-risk pagination (#1434)

Image scan sheet: make the finding table the single bounded scroll region
(SystemSheet noScroll + flex-fill) so it no longer clips at the bottom on
shorter viewports, and give the tables a phone min-width so they scroll
horizontally instead of cutting off the right-hand columns.

Scan history table: add the same horizontal scroll on phones.

Overview "Top exploit-risk findings": render as a paginated table with column
headers and top-right pagination, modeled on the dashboard stack-health table.
Key the rows by rank position so recurring CVE/scan pairs no longer collide and
duplicate rows when paging through.

Overview severity-by-exploitability chart: label the axes (EPSS exploitability
and CVSS severity) and stop the card from stretching to a taller neighbour,
removing the dead space beneath the chart.
This commit is contained in:
Anso
2026-06-24 20:06:04 -04:00
committed by GitHub
parent 6527bc971b
commit 330f9f1acd
5 changed files with 199 additions and 73 deletions
@@ -579,6 +579,7 @@ export function VulnerabilityScanSheet({
onTabChange={(id) => setTab(id as FindingTab)}
footerContext={footerContext}
size="lg"
noScroll
>
{loading && !scan && (
<div className="flex items-center justify-center py-12">
@@ -587,8 +588,11 @@ export function VulnerabilityScanSheet({
)}
{scan && (
<>
<SheetSection title="Summary">
// noScroll skips SystemSheet's default px-6 py-5 wrapper, so supply it
// here; SheetSection's -mx-6 bleed depends on this px-6. The column lets
// the active finding section flex to fill the sheet (single scroll box).
<div className="flex min-h-0 flex-1 flex-col px-6 py-5">
<SheetSection title="Summary" className="shrink-0">
{scan.policy_evaluation?.violated && (
<div
role="alert"
@@ -717,7 +721,7 @@ export function VulnerabilityScanSheet({
</SheetSection>
{tab === 'vulns' && (
<SheetSection title={`Vulnerabilities · ${totalDetails}`}>
<SheetSection title={`Vulnerabilities · ${totalDetails}`} className="flex min-h-0 flex-1 flex-col">
<div className="flex items-center gap-1 flex-wrap mb-3">
{(['ALL', 'CRITICAL', 'HIGH', 'MEDIUM', 'LOW'] as SeverityFilter[]).map((s) => (
<Button
@@ -766,7 +770,7 @@ export function VulnerabilityScanSheet({
</div>
)}
<ScrollArea block className="max-h-[60vh]">
<ScrollArea block className="flex-1 min-h-0">
{pageItems.length === 0 ? (
<div className="text-center text-sm text-muted-foreground py-12">
{details.length === 0
@@ -774,7 +778,7 @@ export function VulnerabilityScanSheet({
: 'No vulnerabilities match the selected filter.'}
</div>
) : (
<Table>
<Table className="max-md:min-w-[720px]">
<TableHeader>
<TableRow>
<TableHead className="w-[180px] text-[10px] uppercase tracking-[0.18em] font-mono text-stat-subtitle">CVE</TableHead>
@@ -866,7 +870,7 @@ export function VulnerabilityScanSheet({
)}
{tab === 'secrets' && (
<SheetSection title={`Secrets · ${scan.secret_count ?? secrets.length}`}>
<SheetSection title={`Secrets · ${scan.secret_count ?? secrets.length}`} className="flex min-h-0 flex-1 flex-col">
{secretsNeedsPagination && (
<div className="flex items-center gap-1 mb-3">
<div className="flex items-center gap-1 ml-auto">
@@ -896,13 +900,13 @@ export function VulnerabilityScanSheet({
</div>
</div>
)}
<ScrollArea block className="max-h-[60vh]">
<ScrollArea block className="flex-1 min-h-0">
{secrets.length === 0 ? (
<div className="text-center text-sm text-muted-foreground py-12">
No secrets detected.
</div>
) : (
<Table>
<Table className="max-md:min-w-[720px]">
<TableHeader>
<TableRow>
<TableHead className="w-[100px] text-[10px] uppercase tracking-[0.18em] font-mono text-stat-subtitle">Severity</TableHead>
@@ -954,7 +958,7 @@ export function VulnerabilityScanSheet({
)}
{tab === 'misconfigs' && (
<SheetSection title={`Misconfigs · ${scan.misconfig_count ?? misconfigs.length}`}>
<SheetSection title={`Misconfigs · ${scan.misconfig_count ?? misconfigs.length}`} className="flex min-h-0 flex-1 flex-col">
{misconfigsNeedsPagination && (
<div className="flex items-center gap-1 mb-3">
<div className="flex items-center gap-1 ml-auto">
@@ -986,13 +990,13 @@ export function VulnerabilityScanSheet({
</div>
</div>
)}
<ScrollArea block className="max-h-[60vh]">
<ScrollArea block className="flex-1 min-h-0">
{misconfigs.length === 0 ? (
<div className="text-center text-sm text-muted-foreground py-12">
No misconfigurations detected.
</div>
) : (
<Table>
<Table className="max-md:min-w-[720px]">
<TableHeader>
<TableRow>
<TableHead className="w-[100px] text-[10px] uppercase tracking-[0.18em] font-mono text-stat-subtitle">Severity</TableHead>
@@ -1080,7 +1084,7 @@ export function VulnerabilityScanSheet({
</ScrollArea>
</SheetSection>
)}
</>
</div>
)}
</SystemSheet>