feat: realtime Live dashboard in Data Explorer + fix panel layout

- New "Live" tab: auto-polls /api/federated/live every 2.5s with
  animated counters, ingestion throughput sparkline, per-source
  write-rate bars, a region scorecard matrix (heat-shaded) and live
  business breakdown charts (region/channel/status/customers/
  telemetry/supply)
- Backend /api/federated/live: instant source estimates (Postgres),
  monotonic max(event_id) for MySQL and Mongo estimated count for
  immediate movement, Cassandra from cached matrix; business aggs
  cached over the small Hadoop lake tables (short TTL)
- Fix embedded Trino panels being squeezed with internal scrollbars
  by making panels/grids shrink-0 so the page scrolls instead
This commit is contained in:
mo
2026-06-28 21:10:19 +00:00
parent 437574f0bb
commit 8c72d1dc63
4 changed files with 466 additions and 9 deletions
@@ -15,15 +15,18 @@ import {
Network,
HardDrive,
ShieldCheck,
Radio,
} from 'lucide-react'
import { cn } from '../../lib/utils'
import { TrinoFederationView, type SubTab } from './TrinoFederationView'
import { LiveDashboard } from './LiveDashboard'
type ExplorerTab = 'business' | SubTab
type ExplorerTab = 'business' | 'live' | SubTab
const TABS: { id: ExplorerTab; label: string; icon: typeof Users; hint: string }[] = [
const TABS: { id: ExplorerTab; label: string; icon: typeof Users; hint: string; live?: boolean }[] = [
{ id: 'business', label: 'Business Overview', icon: BarChart3, hint: 'Customers, orders, workforce, supply chain & telemetry across every source' },
{ id: 'federated', label: 'Federated (Trino)', icon: Network, hint: 'One SQL engine joining PostgreSQL, MySQL & MongoDB live — region scorecard' },
{ id: 'live', label: 'Live', icon: Radio, hint: 'Realtime business activity — live counters, ingestion throughput & region matrix', live: true },
{ id: 'federated', label: 'Federated (Trino)', icon: Network, hint: 'One SQL across all 5 databases + region scorecard joined live' },
{ id: 'lake', label: 'Hadoop Lake', icon: HardDrive, hint: 'All business data mirrored as external Iceberg tables on HDFS' },
{ id: 'dictionary', label: 'Data Dictionary', icon: ShieldCheck, hint: 'Every table & column with PII / masking status — exactly what the assistant sees' },
]
@@ -263,7 +266,7 @@ export function DataExplorerView() {
{/* tab bar */}
<div className="flex shrink-0 flex-wrap gap-1 px-1">
{TABS.map(({ id, label, icon: Icon }) => (
{TABS.map(({ id, label, icon: Icon, live }) => (
<button
key={id}
type="button"
@@ -273,13 +276,24 @@ export function DataExplorerView() {
view === id ? 'bg-docker/15 text-docker' : 'text-foreground-muted hover:bg-surface-overlay',
)}
>
<Icon className="h-3.5 w-3.5" /> {label}
{live ? (
<span className="relative flex h-2 w-2">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-emerald-400 opacity-75" />
<span className="relative inline-flex h-2 w-2 rounded-full bg-emerald-400" />
</span>
) : (
<Icon className="h-3.5 w-3.5" />
)}
{label}
</button>
))}
</div>
{/* Live realtime dashboard */}
{view === 'live' && <LiveDashboard />}
{/* Trino federation / lake / dictionary tabs */}
{view !== 'business' && <TrinoFederationView embedded activeTab={view} />}
{(view === 'federated' || view === 'lake' || view === 'dictionary') && <TrinoFederationView embedded activeTab={view} />}
{/* ───────── BUSINESS OVERVIEW ───────── */}
{view === 'business' && (