mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-08-19 23:06:49 +00:00
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:
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user