feat(frontend): SystemSheet §9.11 — security and scheduled sheets (PR 2/3) (#961)

* feat(frontend): add SystemSheet primitive and migrate mesh sheets to §9.11 chrome

DESIGN.md §9.11 codifies one canonical right-side detail-sheet shell (cyan
rail, mono crumb, italic serif name, mono meta, ESC chip + close glyph,
fixed three-slot toolbar, cyan-underline tabs, ScrollArea body, footer
freshness band). Today the 16 sheet consumers each render their own
header chrome with stock shadcn SheetHeader/SheetTitle.

Introduce <SystemSheet> + <SheetSection> in
frontend/src/components/ui/system-sheet.tsx, composing the existing
<Sheet>/<SheetContent> primitive. Add a backward-compatible showClose
prop to SheetContent so SystemSheet can render its own ESC chip + close
glyph instead of the stock cyan square close.

Migrate the four mesh sheets as the first batch:
* MeshActivitySheet: crumb Fleet › Mesh › Activity, footer freshness from
  most-recent event timestamp.
* MeshOptInSheet: crumb Fleet › Mesh › {nodeName}, meta of opted-in
  count, drops the redundant bottom Close button (ESC chip dismisses).
* MeshDiagnosticsSheet: removes the icon-prefixed title (forbidden by
  §9.11), lifts Refresh/Restart buttons from the body into the toolbar
  band, three SheetSection blocks for sidecar status, streams, cache.
* MeshRouteDetailSheet: adds Overview/Events/Raw tabs, lifts Test probe
  into the toolbar primary slot, footer surfaces last probe latency.

* feat(frontend): migrate security and scheduled sheets to §9.11 chrome

PR 2 of the System Sheet (§9.11) rollout, stacked on the SystemSheet
primitive PR. Migrates six more sheet consumers and merges the Stack
alert + auto-heal sheets into a single tabbed sheet per audit §17.

Sheets migrated:
* NodeUpdatesSheet: crumb Fleet > Updates, Recheck primary, Update-all
  secondary when applicable. Stat tiles and node rows lose their
  card-in-sheet wrapping (forbidden by §9.11) for flat dividers.
* StackAlertSheet (now the merged stack monitor): tabs Alerts /
  Auto-heal, crumb Stack > {name} > Monitor. New initialTab prop lets
  callers open directly to either tab. Auto-heal tab is hidden entirely
  for Community-tier users (matches the existing tier-gating on the
  context menu trigger and keyboard shortcut).
* StackAutoHealSheet.tsx: deleted. Its body became the Auto-heal tab
  inside the merged sheet.
* VulnerabilityScanSheet: removed the icon-prefixed title (forbidden by
  §9.11). Re-scan, Compare, CSV, SARIF lifted from body cards into the
  toolbar band. Tabs Vulnerabilities | Secrets | Misconfigs (counts on
  the tab labels). SBOM dropdown stays in the body summary section
  pending a primitive enhancement for dropdown-attached toolbar actions.
* ScanComparisonSheet: crumb Security > Scans > Compare, name Diff,
  meta with the +added/-removed delta.
* SecurityHistoryView: the inner sheet only. Crumb Security > Scan
  history. Compare (paid + 2 selected) and Refresh in toolbar.
* ScheduledOperationsView run-history sheet (lines ~847-935 only):
  crumb Schedules > {taskName} > Runs, Download CSV in toolbar, footer
  surfaces next-run timestamp.

Hook refactor:
* useOverlayState replaces three separate state vars (alertSheetOpen,
  alertSheetStack, autoHealStackName) with one stackMonitor object
  carrying { stackName, tab }. New helpers openAlertSheet(stackName),
  openAutoHeal(stackName), closeStackMonitor(). Tests rewritten and
  pass (11/11).
* useSidebarContextMenu and ShellOverlays updated for the new API. The
  three other call sites (useStackMenuItems, useStackKeyboardShortcuts)
  already use openAlertSheet/openAutoHeal and need no change.
This commit is contained in:
Anso
2026-05-06 23:19:16 -04:00
committed by GitHub
parent 4d9617a5c6
commit 3ec0a45ff0
11 changed files with 1307 additions and 1507 deletions
@@ -5,8 +5,7 @@ import { Input } from '@/components/ui/input';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Modal, ModalHeader, ModalBody, ModalFooter, ConfirmModal } from '@/components/ui/modal';
import { Sheet, SheetContent, SheetHeader, SheetTitle } from '@/components/ui/sheet';
import { ScrollArea } from '@/components/ui/scroll-area';
import { SystemSheet, SheetSection } from '@/components/ui/system-sheet';
import { TogglePill } from '@/components/ui/toggle-pill';
import { Label } from '@/components/ui/label';
import { Checkbox } from '@/components/ui/checkbox';
@@ -844,31 +843,27 @@ export default function ScheduledOperationsView({ filterNodeId, onClearFilter, p
</ConfirmModal>
{/* Run History Sheet */}
<Sheet open={!!runsTask} onOpenChange={(open) => { if (!open) setRunsTask(null); }}>
<SheetContent className="sm:max-w-xl">
<SheetHeader>
<div className="flex items-center justify-between">
<SheetTitle>Execution History - {runsTask?.name}</SheetTitle>
{runsTask && runs.length > 0 && (
<Button
variant="ghost"
size="sm"
onClick={() => window.open(`/api/scheduled-tasks/${runsTask.id}/runs/export`, '_blank')}
title="Export as CSV"
>
<Download className="w-4 h-4" strokeWidth={1.5} />
</Button>
)}
</div>
</SheetHeader>
<ScrollArea className="mt-4 flex-1" style={{ maxHeight: 'calc(100vh - 10rem)' }}>
<div>
{runsLoading ? (
<div className="text-center text-muted-foreground py-8">Loading...</div>
) : runs.length === 0 ? (
<div className="text-center text-muted-foreground py-8">No executions yet.</div>
) : (
<>
<SystemSheet
open={!!runsTask}
onOpenChange={(open) => { if (!open) setRunsTask(null); }}
crumb={['Schedules', runsTask?.name ?? '—', 'Runs']}
name={runsTask?.name ?? 'Run history'}
meta={`${runsTotal} run${runsTotal === 1 ? '' : 's'}`}
secondaryActions={runsTask && runs.length > 0 ? [{
label: 'Download CSV',
icon: Download,
onClick: () => window.open(`/api/scheduled-tasks/${runsTask.id}/runs/export`, '_blank'),
}] : undefined}
footerContext={runsTask?.next_run_at ? `Next run ${formatTimestamp(runsTask.next_run_at)}` : undefined}
size="lg"
>
<SheetSection title="Executions" hideHeader>
{runsLoading ? (
<div className="text-center text-muted-foreground py-8">Loading...</div>
) : runs.length === 0 ? (
<div className="text-center text-muted-foreground py-8">No executions yet.</div>
) : (
<>
<Table>
<TableHeader>
<TableRow>
@@ -927,12 +922,10 @@ export default function ScheduledOperationsView({ filterNodeId, onClearFilter, p
</div>
</div>
)}
</>
)}
</div>
</ScrollArea>
</SheetContent>
</Sheet>
</>
)}
</SheetSection>
</SystemSheet>
</div>
);
}