wip: rescue uncommitted dashboard-v2 panels and cluster changes before archiving

Snapshot of work in progress found in ~/claw-store on 2026-09-12: maintenance,
pollution and warming-candidate panels in dashboard-v2, plus cluster blob/rpc/
services and daemon edits. Committed as-is for safekeeping.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01DjN5qhFxHFuXjQ8krZoG81
This commit is contained in:
Omar Sobh
2026-09-12 04:40:42 -07:00
co-authored by Claude Fable 5.1
parent 5e7f7dfc83
commit 425ce58127
18 changed files with 1143 additions and 42 deletions
+3 -1
View File
@@ -3,6 +3,8 @@ import { useEffect, useState } from 'react';
import { api, fmtBytes, fmtAge } from '../lib/api';
import { NodeCard } from '../components/NodeCard';
import { ProjectsPanel } from '../components/ProjectsPanel';
import { WarmingCandidatesPanel } from '../components/WarmingCandidatesPanel';
import { PollutionPanel } from '../components/PollutionPanel';
// FleetHealth landing — human-oriented single-pane-of-glass.
// Polls the aggregator's /api/v2/fleet every 10 s.
export function CommandCenter() {
@@ -39,5 +41,5 @@ export function CommandCenter() {
const alertNodes = anomalies.filter((a) => a.level === 'alert');
const warnNodes = anomalies.filter((a) => a.level === 'warn');
return (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-semibold text-slate-100", children: "Fleet health" }), _jsx("div", { className: "text-sm text-slate-500 mt-1", children: fleet && (_jsxs(_Fragment, { children: [_jsx("span", { className: "text-emerald-300", children: totals?.online }), "/", fleet.nodes.length, " nodes online", ' · ', totals?.mounted, "/", fleet.nodes.length, " mounted", ' · ', "updated ", _jsx("span", { className: "font-mono", children: fmtAge(fleet.fetched_at_unix) }), ' · ', "hosted by ", _jsx("span", { className: "font-mono text-slate-300", children: fleet.aggregator_name })] })) })] }), err && (_jsx("div", { className: "rounded border border-red-800 bg-red-950/40 p-3 text-red-300 text-sm", children: err })), alertNodes.length > 0 && (_jsxs("div", { className: "rounded border border-red-800 bg-red-950/40 px-4 py-3 text-sm flex items-start gap-3", children: [_jsx("span", { className: "text-red-400 font-bold mt-0.5", children: "\u25CF" }), _jsxs("div", { children: [_jsx("span", { className: "text-red-300 font-semibold", children: "Metric anomaly detected \u2014 " }), _jsxs("span", { className: "text-red-200", children: [alertNodes.map((a) => a.node).join(', '), " deviating >2\u03C3 from baseline", alertNodes.length === 1 && ` (score ${alertNodes[0].score.toFixed(1)})`] })] })] })), alertNodes.length === 0 && warnNodes.length > 0 && (_jsxs("div", { className: "rounded border border-amber-800 bg-amber-950/40 px-4 py-3 text-sm flex items-start gap-3", children: [_jsx("span", { className: "text-amber-400 font-bold mt-0.5", children: "\u25CF" }), _jsxs("div", { children: [_jsx("span", { className: "text-amber-300 font-semibold", children: "Metric drift \u2014 " }), _jsxs("span", { className: "text-amber-200", children: [warnNodes.map((a) => a.node).join(', '), " showing unusual patterns"] })] })] })), totals && totals.diskTotal > 0 && (_jsxs("div", { className: "rounded-lg border border-slate-800 bg-slate-900/60 p-4 flex items-center justify-between", children: [_jsxs("div", { children: [_jsx("div", { className: "text-xs uppercase tracking-wider text-slate-500", children: "Fleet-wide storage" }), _jsxs("div", { className: "text-2xl font-semibold font-mono mt-1", children: [fmtBytes(totals.diskUsed), ' ', _jsxs("span", { className: "text-slate-500 text-lg", children: ["/ ", fmtBytes(totals.diskTotal)] })] })] }), _jsxs("div", { className: "text-right text-slate-400 text-sm", children: [_jsxs("div", { children: [Math.round((totals.diskUsed / totals.diskTotal) * 100), "% used"] }), _jsxs("div", { className: "text-xs text-slate-500 mt-1", children: ["hot tier: ", fmtBytes(totals.hotUsed), " / ", fmtBytes(totals.hotMax)] })] })] })), _jsxs("section", { children: [_jsx("h2", { className: "text-lg font-semibold text-slate-100 mb-3", children: "Nodes" }), _jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4", children: [fleet?.nodes.map((n) => (_jsx(NodeCard, { node: n, anomalyLevel: anomalyMap[n.node_name] }, n.node_name))), !fleet &&
[1, 2, 3].map((i) => (_jsx("div", { className: "rounded-lg border border-slate-800 bg-slate-900/40 p-5 h-64 animate-pulse" }, i)))] })] }), _jsx(ProjectsPanel, {})] }));
[1, 2, 3].map((i) => (_jsx("div", { className: "rounded-lg border border-slate-800 bg-slate-900/40 p-5 h-64 animate-pulse" }, i)))] })] }), _jsx(ProjectsPanel, {}), _jsx(WarmingCandidatesPanel, {}), _jsx(PollutionPanel, {})] }));
}
+6
View File
@@ -2,6 +2,8 @@ import { useEffect, useState } from 'react';
import { api, FleetSnapshot, AnomalyStatus, fmtBytes, fmtAge } from '../lib/api';
import { NodeCard } from '../components/NodeCard';
import { ProjectsPanel } from '../components/ProjectsPanel';
import { WarmingCandidatesPanel } from '../components/WarmingCandidatesPanel';
import { PollutionPanel } from '../components/PollutionPanel';
// FleetHealth landing — human-oriented single-pane-of-glass.
// Polls the aggregator's /api/v2/fleet every 10 s.
@@ -140,6 +142,10 @@ export function CommandCenter() {
</section>
<ProjectsPanel />
<WarmingCandidatesPanel />
<PollutionPanel />
</div>
);
}
+2 -1
View File
@@ -3,6 +3,7 @@ import { useEffect, useState } from 'react';
import { Link } from 'wouter';
import { api, fmtBytes } from '../lib/api';
import { StatTile } from '../components/StatTile';
import { MaintenancePanel } from '../components/MaintenancePanel';
export function NodeDetail({ name }) {
const [status, setStatus] = useState(null);
const [err, setErr] = useState(null);
@@ -15,5 +16,5 @@ export function NodeDetail({ name }) {
})
.catch((e) => setErr(String(e)));
}, [name]);
return (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsx(Link, { href: "/", children: _jsx("a", { className: "text-sm text-slate-500 hover:text-slate-300", children: "\u2190 fleet" }) }), _jsx("h1", { className: "text-2xl font-semibold text-slate-100 mt-2", children: name })] }), err && (_jsxs("div", { className: "rounded border border-amber-800 bg-amber-950/40 p-3 text-amber-300 text-sm", children: [err, _jsxs("div", { className: "mt-2 text-xs text-slate-400", children: ["Cross-node lookup lands in a follow-on PR. Until then this page shows detail only when you're already viewing the dashboard hosted by ", name, ". Try opening", ' ', _jsxs("span", { className: "font-mono", children: ["http://", name, ":7700/v2/#/nodes/", name] }), ' ', "directly."] })] })), status && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3", children: [_jsx(StatTile, { label: "blobs", value: status.blob_count.toLocaleString(), color: "ok" }), _jsx(StatTile, { label: "tags", value: status.tag_count, color: "ok" }), _jsx(StatTile, { label: "refs", value: status.ref_count, color: "ok" }), _jsx(StatTile, { label: "snapshots", value: status.snapshot_count, color: "ok" }), _jsx(StatTile, { label: "ref-tracking", value: status.ref_tracking_count, color: "ok" }), _jsx(StatTile, { label: "store size", value: fmtBytes(status.blob_store_bytes), color: "ok" })] }), _jsxs("div", { className: "rounded border border-slate-800 bg-slate-900/40 p-4 text-sm", children: [_jsx("div", { className: "text-slate-500 uppercase text-xs tracking-wider", children: "blob store root" }), _jsx("div", { className: "font-mono mt-1", children: status.blob_store_root ?? '—' })] })] }))] }));
return (_jsxs("div", { className: "space-y-6", children: [_jsxs("div", { children: [_jsx(Link, { href: "/", children: _jsx("a", { className: "text-sm text-slate-500 hover:text-slate-300", children: "\u2190 fleet" }) }), _jsx("h1", { className: "text-2xl font-semibold text-slate-100 mt-2", children: name })] }), err && (_jsxs("div", { className: "rounded border border-amber-800 bg-amber-950/40 p-3 text-amber-300 text-sm", children: [err, _jsxs("div", { className: "mt-2 text-xs text-slate-400", children: ["Cross-node lookup lands in a follow-on PR. Until then this page shows detail only when you're already viewing the dashboard hosted by ", name, ". Try opening", ' ', _jsxs("span", { className: "font-mono", children: ["http://", name, ":7700/v2/#/nodes/", name] }), ' ', "directly."] })] })), status && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 gap-3", children: [_jsx(StatTile, { label: "blobs", value: status.blob_count.toLocaleString(), color: "ok" }), _jsx(StatTile, { label: "tags", value: status.tag_count, color: "ok" }), _jsx(StatTile, { label: "refs", value: status.ref_count, color: "ok" }), _jsx(StatTile, { label: "snapshots", value: status.snapshot_count, color: "ok" }), _jsx(StatTile, { label: "ref-tracking", value: status.ref_tracking_count, color: "ok" }), _jsx(StatTile, { label: "store size", value: fmtBytes(status.blob_store_bytes), color: "ok" })] }), _jsxs("div", { className: "rounded border border-slate-800 bg-slate-900/40 p-4 text-sm", children: [_jsx("div", { className: "text-slate-500 uppercase text-xs tracking-wider", children: "blob store root" }), _jsx("div", { className: "font-mono mt-1", children: status.blob_store_root ?? '—' })] })] })), _jsx(MaintenancePanel, {})] }));
}
+3
View File
@@ -2,6 +2,7 @@ import { useEffect, useState } from 'react';
import { Link } from 'wouter';
import { api, NodeStatusV2, fmtBytes } from '../lib/api';
import { StatTile } from '../components/StatTile';
import { MaintenancePanel } from '../components/MaintenancePanel';
interface Props {
name: string;
@@ -69,6 +70,8 @@ export function NodeDetail({ name }: Props) {
</div>
</>
)}
<MaintenancePanel />
</div>
);
}