import { useMemo } from 'react'; import { useParams } from 'react-router'; import { StatCard, Sparkline, MonoText, Badge, DataTable, AreaChart, LineChart, BarChart, } from '@cameleer/design-system'; import type { Column } from '@cameleer/design-system'; import { useRouteMetrics } from '../../api/queries/catalog'; import { useExecutionStats, useStatsTimeseries } from '../../api/queries/executions'; import { useGlobalFilters } from '@cameleer/design-system'; interface RouteRow { id: string; routeId: string; appId: string; exchangeCount: number; successRate: number; avgDurationMs: number; p99DurationMs: number; errorRate: number; throughputPerSec: number; sparkline: number[]; } export default function RoutesMetrics() { const { appId, routeId } = useParams(); const { timeRange } = useGlobalFilters(); const timeFrom = timeRange.start.toISOString(); const timeTo = timeRange.end.toISOString(); const { data: metrics } = useRouteMetrics(timeFrom, timeTo, appId); const { data: stats } = useExecutionStats(timeFrom, timeTo, routeId, appId); const { data: timeseries } = useStatsTimeseries(timeFrom, timeTo, routeId, appId); const rows: RouteRow[] = useMemo(() => (metrics || []).map((m: any) => ({ id: `${m.appId}/${m.routeId}`, ...m, })), [metrics], ); const sparklineData = useMemo(() => (timeseries?.buckets || []).map((b: any) => b.totalCount as number), [timeseries], ); const chartData = useMemo(() => (timeseries?.buckets || []).map((b: any) => ({ time: new Date(b.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }), throughput: b.totalCount, latency: b.avgDurationMs, errors: b.failedCount, successRate: b.totalCount > 0 ? ((b.totalCount - b.failedCount) / b.totalCount) * 100 : 100, })), [timeseries], ); const columns: Column[] = [ { key: 'routeId', header: 'Route', render: (v) => {String(v)} }, { key: 'appId', header: 'App', render: (v) => }, { key: 'exchangeCount', header: 'Exchanges', sortable: true }, { key: 'successRate', header: 'Success', sortable: true, render: (v) => `${((v as number) * 100).toFixed(1)}%`, }, { key: 'avgDurationMs', header: 'Avg Duration', sortable: true, render: (v) => `${(v as number).toFixed(0)}ms` }, { key: 'p99DurationMs', header: 'P99', sortable: true, render: (v) => `${(v as number).toFixed(0)}ms` }, { key: 'errorRate', header: 'Error Rate', sortable: true, render: (v) => 0.05 ? 'var(--error)' : undefined }}>{((v as number) * 100).toFixed(1)}%, }, { key: 'sparkline', header: 'Trend', width: '80px', render: (v) => , }, ]; return (
{chartData.length > 0 && (
({ x: i, y: d.throughput })) }]} height={200} /> ({ x: i, y: d.latency })) }]} height={200} /> ({ x: d.time as string, y: d.errors })) }]} height={200} /> ({ x: i, y: d.successRate })) }]} height={200} />
)}
); }