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