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:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user