feat: Nessie catalog UI + Iceberg structure explorer + live Data Flow online/offline

Add Project Nessie on lake01 with Command Center Iceberg tab (snapshots,
manifests, data files, time-travel SQL). Data Flow pulses only when endpoints
are reachable; offline nodes/edges render red.
This commit is contained in:
mo
2026-07-22 00:31:35 +00:00
parent d5fba208a3
commit b54f5c7a06
9 changed files with 815 additions and 23 deletions
+9 -8
View File
@@ -232,6 +232,7 @@ export function ChangesView({ liveChanges }: { liveChanges: CdcChange[] }) {
const [flash, setFlash] = useState(false)
const [resyncing, setResyncing] = useState(false)
const [resyncMsg, setResyncMsg] = useState<string | null>(null)
const [windowMin, setWindowMin] = useState(15)
// Live overlay: CDC events counted straight off the WebSocket stream since the
// last server stats snapshot. The top KPIs/charts = authoritative server stats
// (refreshed every 2.5s) + this overlay, so they move in lock-step with the
@@ -248,11 +249,11 @@ export function ChangesView({ liveChanges }: { liveChanges: CdcChange[] }) {
}, [])
const load = useCallback(async () => {
const [c, s] = await Promise.all([fetchChanges({ limit: 200 }), fetchChangeStats(15)])
const [c, s] = await Promise.all([fetchChanges({ limit: 200, minutes: windowMin }), fetchChangeStats(windowMin)])
setSeed(c.changes)
setConnected(c.connected)
applyStats(s)
}, [applyStats])
}, [applyStats, windowMin])
const doResync = useCallback(async () => {
setResyncing(true)
@@ -275,9 +276,9 @@ export function ChangesView({ liveChanges }: { liveChanges: CdcChange[] }) {
useEffect(() => {
load()
const iv = setInterval(() => fetchChangeStats(15).then((s) => applyStats(s)), 2500)
const iv = setInterval(() => fetchChangeStats(windowMin).then((s) => applyStats(s)), 2500)
return () => clearInterval(iv)
}, [load, applyStats])
}, [load, applyStats, windowMin])
// Fold freshly-arrived WS changes into the overlay → instant top-of-page update.
useEffect(() => {
@@ -410,9 +411,9 @@ export function ChangesView({ liveChanges }: { liveChanges: CdcChange[] }) {
{/* KPI row */}
<div className="grid shrink-0 grid-cols-2 gap-2 lg:grid-cols-4">
<KpiCard label="New records" value={inserts} accent="#34d399" icon={PlusCircle} sub="inserts · last 15m" />
<KpiCard label="Updates" value={updates} accent="#fbbf24" icon={Pencil} sub="modified rows · 15m" />
<KpiCard label="Deletes" value={deletes} accent="#fb7185" icon={Trash2} sub="removed rows · 15m" />
<KpiCard label="New records" value={inserts} accent="#34d399" icon={PlusCircle} sub={`inserts · last ${windowMin}m`} />
<KpiCard label="Updates" value={updates} accent="#fbbf24" icon={Pencil} sub={`modified rows · ${windowMin}m`} />
<KpiCard label="Deletes" value={deletes} accent="#fb7185" icon={Trash2} sub={`removed rows · ${windowMin}m`} />
<KpiCard label="Throughput" value={Math.round(perMin)} accent="#38bdf8" icon={TrendingUp} sub={`changes/min · ${(stats?.consumed ?? 0).toLocaleString()} total consumed`} />
</div>
@@ -420,7 +421,7 @@ export function ChangesView({ liveChanges }: { liveChanges: CdcChange[] }) {
<div className="grid shrink-0 grid-cols-1 gap-2 lg:grid-cols-3">
<div className="rounded-lg border border-border/60 bg-surface-raised p-3 lg:col-span-2">
<div className="mb-1 flex items-center gap-1.5 text-[10px] uppercase tracking-wide text-foreground-faint">
<TrendingUp className="h-3 w-3" /> Change volume last 15 minutes
<TrendingUp className="h-3 w-3" /> Change volume selected window
</div>
<VolumeArea buckets={liveBuckets} />
</div>