Add route diagram page with execution overlay and group-aware APIs
Backend: Add group filtering to agent list, search, stats, and timeseries
endpoints. Add diagram lookup by group+routeId. Resolve application group
to agent IDs server-side for ClickHouse IN-clause queries.
Frontend: New route detail page at /apps/{group}/routes/{routeId} with
three tabs (Diagram, Performance, Processor Tree). SVG diagram rendering
with panzoom, execution overlay (glow effects, duration/sequence badges,
flow particles, minimap), and processor detail panel. uPlot charts for
performance tab replacing old SVG sparklines. Ctrl+Click from
ExecutionExplorer navigates to route diagram with overlay.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
57
ui/src/components/charts/ThroughputChart.tsx
Normal file
57
ui/src/components/charts/ThroughputChart.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import { useRef, useEffect } from 'react';
|
||||
import uPlot from 'uplot';
|
||||
import 'uplot/dist/uPlot.min.css';
|
||||
import { baseOpts, chartColors } from './theme';
|
||||
import type { TimeseriesBucket } from '../../api/types';
|
||||
|
||||
interface ThroughputChartProps {
|
||||
buckets: TimeseriesBucket[];
|
||||
}
|
||||
|
||||
export function ThroughputChart({ buckets }: ThroughputChartProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const chartRef = useRef<uPlot | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!containerRef.current || buckets.length < 2) return;
|
||||
const el = containerRef.current;
|
||||
const w = el.clientWidth || 600;
|
||||
|
||||
const xs = buckets.map((b) => new Date(b.time!).getTime() / 1000);
|
||||
const totals = buckets.map((b) => b.totalCount ?? 0);
|
||||
const failed = buckets.map((b) => b.failedCount ?? 0);
|
||||
|
||||
const opts: uPlot.Options = {
|
||||
...baseOpts(w, 220),
|
||||
width: w,
|
||||
height: 220,
|
||||
series: [
|
||||
{ label: 'Time' },
|
||||
{
|
||||
label: 'Total',
|
||||
stroke: chartColors.amber,
|
||||
fill: `${chartColors.amber}20`,
|
||||
width: 2,
|
||||
},
|
||||
{
|
||||
label: 'Failed',
|
||||
stroke: chartColors.rose,
|
||||
fill: `${chartColors.rose}20`,
|
||||
width: 2,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
chartRef.current?.destroy();
|
||||
chartRef.current = new uPlot(opts, [xs, totals, failed], el);
|
||||
|
||||
return () => {
|
||||
chartRef.current?.destroy();
|
||||
chartRef.current = null;
|
||||
};
|
||||
}, [buckets]);
|
||||
|
||||
if (buckets.length < 2) return null;
|
||||
|
||||
return <div ref={containerRef} />;
|
||||
}
|
||||
Reference in New Issue
Block a user