import { useState } from 'react' import { useNavigate } from 'react-router-dom' import styles from './Metrics.module.css' // Layout import { AppShell } from '../../design-system/layout/AppShell/AppShell' import { Sidebar } from '../../design-system/layout/Sidebar/Sidebar' import { TopBar } from '../../design-system/layout/TopBar/TopBar' // Composites import { AreaChart } from '../../design-system/composites/AreaChart/AreaChart' import { LineChart } from '../../design-system/composites/LineChart/LineChart' import { BarChart } from '../../design-system/composites/BarChart/BarChart' import { DataTable } from '../../design-system/composites/DataTable/DataTable' import type { Column } from '../../design-system/composites/DataTable/types' // Primitives import { StatCard } from '../../design-system/primitives/StatCard/StatCard' import { DateRangePicker } from '../../design-system/primitives/DateRangePicker/DateRangePicker' import { Sparkline } from '../../design-system/primitives/Sparkline/Sparkline' import { MonoText } from '../../design-system/primitives/MonoText/MonoText' import { Badge } from '../../design-system/primitives/Badge/Badge' // Mock data import { throughputSeries, latencySeries, errorCountSeries, routeMetrics, type RouteMetricRow, } from '../../mocks/metrics' import { routes } from '../../mocks/routes' import { agents } from '../../mocks/agents' // ─── Sidebar data (shared) ──────────────────────────────────────────────────── const APPS = [ { id: 'order-service', name: 'order-service', agentCount: 2, health: 'live' as const, execCount: 1433 }, { id: 'payment-svc', name: 'payment-svc', agentCount: 1, health: 'live' as const, execCount: 912 }, { id: 'shipment-tracker', name: 'shipment-tracker', agentCount: 2, health: 'live' as const, execCount: 471 }, { id: 'notification-hub', name: 'notification-hub', agentCount: 1, health: 'stale' as const, execCount: 128 }, ] const SIDEBAR_ROUTES = routes.slice(0, 3).map((r) => ({ id: r.id, name: r.name, execCount: r.execCount, })) // ─── Metrics KPI cards (5 cards per spec) ───────────────────────────────────── const METRIC_KPIS = [ { label: 'Throughput', value: '47.2', unit: 'msg/s', trend: 'neutral' as const, trendValue: '→', detail: 'Capacity: 120 msg/s · 39%', accent: 'running' as const, sparkline: [44, 46, 45, 47, 48, 46, 47, 48, 46, 47, 48, 47, 46, 47], }, { label: 'Latency p99', value: '287ms', trend: 'up' as const, trendValue: '+23ms', detail: 'SLA: <300ms · CLOSE', accent: 'warning' as const, sparkline: [198, 212, 205, 218, 224, 231, 238, 245, 252, 261, 268, 275, 281, 287], }, { label: 'Error Rate', value: '2.9%', trend: 'up' as const, trendValue: '+0.4%', detail: '38 errors this shift', accent: 'error' as const, sparkline: [1.2, 1.8, 1.5, 2.1, 2.4, 2.2, 2.5, 2.6, 2.7, 2.8, 2.7, 2.9, 2.8, 2.9], }, { label: 'Success Rate', value: '97.1%', trend: 'down' as const, trendValue: '-0.4%', detail: '3,147 ok · 56 warn · 38 err', accent: 'success' as const, sparkline: [98.2, 97.9, 98.1, 97.8, 97.5, 97.6, 97.4, 97.2, 97.3, 97.1, 97.0, 97.1, 97.2, 97.1], }, { label: 'Active Routes', value: 7, trend: 'neutral' as const, trendValue: '→', detail: '4 healthy · 2 degraded · 1 stale', accent: 'amber' as const, sparkline: [7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7], }, ] // ─── Route metric row with id field (required by DataTable) ────────────────── type RouteMetricRowWithId = RouteMetricRow & { id: string } const routeMetricsWithId: RouteMetricRowWithId[] = routeMetrics.map((r) => ({ ...r, id: r.routeId, })) // ─── Route performance table columns ────────────────────────────────────────── const ROUTE_COLUMNS: Column[] = [ { key: 'routeName', header: 'Route', sortable: true, render: (_, row) => ( {row.routeName} ), }, { key: 'execCount', header: 'Executions', sortable: true, render: (_, row) => ( {row.execCount.toLocaleString()} ), }, { key: 'successRate', header: 'Success %', sortable: true, render: (_, row) => { const cls = row.successRate >= 99 ? styles.rateGood : row.successRate >= 97 ? styles.rateWarn : styles.rateBad return {row.successRate.toFixed(1)}% }, }, { key: 'avgDurationMs', header: 'Avg Duration', sortable: true, render: (_, row) => ( {row.avgDurationMs}ms ), }, { key: 'p99DurationMs', header: 'p99 Duration', sortable: true, render: (_, row) => { const cls = row.p99DurationMs > 300 ? styles.rateBad : row.p99DurationMs > 200 ? styles.rateWarn : styles.rateGood return {row.p99DurationMs}ms }, }, { key: 'errorCount', header: 'Errors', sortable: true, render: (_, row) => ( 10 ? styles.rateBad : styles.rateNeutral}> {row.errorCount} ), }, { key: 'sparkline', header: 'Trend', render: (_, row) => ( ), }, ] // ─── Build bar chart data from error series ──────────────────────────────────── function buildErrorBarSeries() { // Take every 5th point and format x as time label const sampleInterval = 5 return errorCountSeries.map((s) => ({ label: s.label, data: s.data .filter((_, i) => i % sampleInterval === 0) .map((pt) => ({ x: pt.timestamp.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }), y: Math.round(pt.value), })), })) } // ─── Build volume area chart (derived from throughput) ───────────────────────── function buildVolumeSeries() { return throughputSeries.map((s) => ({ label: s.label, data: s.data.map((pt) => ({ x: pt.timestamp, y: Math.round(pt.value * 60), // approx msg/min })), })) } const ERROR_BAR_SERIES = buildErrorBarSeries() const VOLUME_SERIES = buildVolumeSeries() // Convert MetricSeries (from mocks) to ChartSeries format function convertSeries(series: typeof throughputSeries) { return series.map((s) => ({ label: s.label, data: s.data.map((pt) => ({ x: pt.timestamp, y: pt.value })), })) } // ─── Metrics page ───────────────────────────────────────────────────────────── export function Metrics() { const navigate = useNavigate() const [activeItem, setActiveItem] = useState('order-service') const [dateRange, setDateRange] = useState({ start: new Date('2026-03-18T06:00:00'), end: new Date('2026-03-18T09:15:00'), }) function handleItemClick(id: string) { setActiveItem(id) // Navigate to route detail if it's a route const route = routes.find((r) => r.id === id) if (route) navigate(`/routes/${id}`) } return ( } > {/* Top bar */} {/* Scrollable content */}
{/* Date range picker bar */}
Auto-refresh: 30s
{/* KPI stat cards (5) */}
{METRIC_KPIS.map((kpi, i) => ( ))}
{/* Per-route performance table */}
Per-Route Performance
{routeMetrics.length} routes
navigate(`/routes/${row.routeId}`)} />
{/* 2x2 chart grid */}
{/* Throughput area chart */}
Throughput (msg/s)
{/* Latency line chart with SLA threshold */}
Latency (ms)
{/* Error bar chart */}
Errors by Route
{/* Volume area chart */}
Message Volume (msg/min)
) }