feat: migrate agent charts to ThemedChart + Recharts
Some checks failed
CI / cleanup-branch (push) Has been skipped
CI / docker (push) Has been cancelled
CI / deploy (push) Has been cancelled
CI / deploy-feature (push) Has been cancelled
CI / build (push) Has been cancelled

Replace custom LineChart/AreaChart/BarChart usage with ThemedChart
wrapper. Data format changed from ChartSeries[] to Recharts-native
flat objects. Uses DS v0.1.47.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-12 19:44:55 +02:00
parent a0af53f8f5
commit 0dae1f1cc7
6 changed files with 238 additions and 267 deletions

View File

@@ -8,9 +8,12 @@ import {
DataTable,
EmptyState,
Tabs,
AreaChart,
LineChart,
BarChart,
ThemedChart,
Area,
Line,
Bar,
ReferenceLine,
CHART_COLORS,
RouteFlow,
Spinner,
MonoText,
@@ -752,44 +755,31 @@ export default function RouteDetail() {
<div className={styles.chartGrid} style={{ marginTop: 16 }}>
<div className={chartCardStyles.chartCard}>
<div className={styles.chartTitle}>Throughput</div>
<AreaChart
series={[{
label: 'Throughput',
data: chartData.map((d, i) => ({ x: i, y: d.throughput })),
}]}
height={200}
/>
<ThemedChart data={chartData} height={200} xDataKey="time" yLabel="msg/s">
<Area dataKey="throughput" name="Throughput" stroke={CHART_COLORS[0]}
fill={CHART_COLORS[0]} fillOpacity={0.1} strokeWidth={2} dot={false} />
</ThemedChart>
</div>
<div className={chartCardStyles.chartCard}>
<div className={styles.chartTitle}>Latency</div>
<LineChart
series={[{
label: 'Latency',
data: chartData.map((d, i) => ({ x: i, y: d.latency })),
}]}
height={200}
threshold={{ value: 300, label: 'SLA 300ms' }}
/>
<ThemedChart data={chartData} height={200} xDataKey="time" yLabel="ms">
<Line dataKey="latency" name="Latency" stroke={CHART_COLORS[0]} strokeWidth={2} dot={false} />
<ReferenceLine y={300} stroke="var(--error)" strokeDasharray="5 3"
label={{ value: 'SLA 300ms', position: 'right', fill: 'var(--error)', fontSize: 9 }} />
</ThemedChart>
</div>
<div className={chartCardStyles.chartCard}>
<div className={styles.chartTitle}>Errors</div>
<BarChart
series={[{
label: 'Errors',
data: chartData.map((d) => ({ x: d.time, y: d.errors })),
}]}
height={200}
/>
<ThemedChart data={chartData} height={200} xDataKey="time" yLabel="errors">
<Bar dataKey="errors" name="Errors" fill={CHART_COLORS[1]} />
</ThemedChart>
</div>
<div className={chartCardStyles.chartCard}>
<div className={styles.chartTitle}>Success Rate</div>
<AreaChart
series={[{
label: 'Success Rate',
data: chartData.map((d, i) => ({ x: i, y: d.successRate })),
}]}
height={200}
/>
<ThemedChart data={chartData} height={200} xDataKey="time" yLabel="%">
<Area dataKey="successRate" name="Success Rate" stroke={CHART_COLORS[0]}
fill={CHART_COLORS[0]} fillOpacity={0.1} strokeWidth={2} dot={false} />
</ThemedChart>
</div>
</div>
)}

View File

@@ -3,9 +3,12 @@ import { useParams, useNavigate } from 'react-router';
import {
KpiStrip,
DataTable,
AreaChart,
LineChart,
BarChart,
ThemedChart,
Area,
Line,
Bar,
ReferenceLine,
CHART_COLORS,
Card,
Sparkline,
MonoText,
@@ -243,41 +246,17 @@ export default function RoutesMetrics() {
[timeseries],
);
// Chart series from timeseries buckets
const throughputChartSeries = useMemo(() => [{
label: 'Throughput',
data: (timeseries?.buckets || []).map((b, i) => ({
x: i as number,
y: b.totalCount,
// Flat chart data from timeseries buckets
const chartData = useMemo(() =>
(timeseries?.buckets || []).map((b, i) => ({
idx: i,
throughput: b.totalCount,
latency: b.avgDurationMs,
errors: b.failedCount,
volume: b.totalCount,
})),
}], [timeseries]);
const latencyChartSeries = useMemo(() => [{
label: 'Latency',
data: (timeseries?.buckets || []).map((b, i) => ({
x: i as number,
y: b.avgDurationMs,
})),
}], [timeseries]);
const errorBarSeries = useMemo(() => [{
label: 'Errors',
data: (timeseries?.buckets || []).map((b) => {
const ts = new Date(b.time);
const label = !isNaN(ts.getTime())
? ts.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
: '—';
return { x: label, y: b.failedCount };
}),
}], [timeseries]);
const volumeChartSeries = useMemo(() => [{
label: 'Volume',
data: (timeseries?.buckets || []).map((b, i) => ({
x: i as number,
y: b.totalCount,
})),
}], [timeseries]);
[timeseries],
);
const kpiItems = useMemo(() =>
buildKpiItems(stats, rows.length, throughputSparkline, errorSparkline),
@@ -315,42 +294,34 @@ export default function RoutesMetrics() {
</div>
{/* 2x2 chart grid */}
{(timeseries?.buckets?.length ?? 0) > 0 && (
{chartData.length > 0 && (
<div className={styles.chartGrid}>
<Card title="Throughput (msg/s)">
<AreaChart
series={throughputChartSeries}
yLabel="msg/s"
height={200}
className={styles.chart}
/>
<ThemedChart data={chartData} height={200} xDataKey="idx" yLabel="msg/s">
<Area dataKey="throughput" name="Throughput" stroke={CHART_COLORS[0]}
fill={CHART_COLORS[0]} fillOpacity={0.1} strokeWidth={2} dot={false} />
</ThemedChart>
</Card>
<Card title="Latency (ms)">
<LineChart
series={latencyChartSeries}
yLabel="ms"
threshold={{ value: 300, label: 'SLA 300ms' }}
height={200}
className={styles.chart}
/>
<ThemedChart data={chartData} height={200} xDataKey="idx" yLabel="ms">
<Line dataKey="latency" name="Latency" stroke={CHART_COLORS[0]} strokeWidth={2} dot={false} />
<ReferenceLine y={300} stroke="var(--error)" strokeDasharray="5 3"
label={{ value: 'SLA 300ms', position: 'right', fill: 'var(--error)', fontSize: 9 }} />
</ThemedChart>
</Card>
<Card title="Errors by Route">
<BarChart
series={errorBarSeries}
height={200}
className={styles.chart}
/>
<Card title="Errors by Bucket">
<ThemedChart data={chartData} height={200} xDataKey="idx" yLabel="errors">
<Bar dataKey="errors" name="Errors" fill={CHART_COLORS[1]} />
</ThemedChart>
</Card>
<Card title="Message Volume (msg/min)">
<AreaChart
series={volumeChartSeries}
yLabel="msg/min"
height={200}
className={styles.chart}
/>
<ThemedChart data={chartData} height={200} xDataKey="idx" yLabel="msg/min">
<Area dataKey="volume" name="Volume" stroke={CHART_COLORS[0]}
fill={CHART_COLORS[0]} fillOpacity={0.1} strokeWidth={2} dot={false} />
</ThemedChart>
</Card>
</div>
)}