Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4.9 KiB
Recharts Migration Design
Goal
Replace the design system's hand-rolled SVG chart components (LineChart, AreaChart, BarChart) with Recharts-based implementations. The current custom charts have responsiveness issues (preserveAspectRatio distorting text), limited tooltip/axis formatting, and growing maintenance burden.
Architecture
Add Recharts as a DS dependency. Replace the three custom chart components and _chart-utils.ts with a single ThemedChart wrapper component. Consumers compose Recharts elements (<Line>, <Area>, <Bar>, etc.) as children inside <ThemedChart>. The DS re-exports Recharts components so consumers don't need to add Recharts as a separate dependency.
Sparkline stays hand-rolled SVG (no axes, no tooltips — Recharts is overkill).
What gets removed
composites/LineChart/directory (LineChart.tsx, LineChart.module.css)composites/AreaChart/directory (AreaChart.tsx, AreaChart.module.css)composites/BarChart/directory (BarChart.tsx, BarChart.module.css)composites/_chart-utils.tsChartSeriesandDataPointtype exports
What gets added
composites/ThemedChart/ThemedChart.tsx— wrapper componentcomposites/ThemedChart/ChartTooltip.tsx— internal themed tooltipcomposites/ThemedChart/ThemedChart.module.css- Recharts re-exports from the DS barrel
What stays unchanged
utils/rechartsTheme.ts(now also used internally by ThemedChart)CHART_COLORSprimitives/Sparkline/
Data Format
Consumers use Recharts-native flat data format instead of the current ChartSeries[]:
// Before (custom)
const series = [
{ label: 'CPU %', data: pts.map(p => ({ x: new Date(p.time), y: p.value * 100 })) }
]
<AreaChart series={series} height={160} yLabel="%" />
// After (Recharts-native)
const data = pts.map(p => ({ time: p.time, cpu: p.value * 100 }))
<ThemedChart data={data} height={160} xDataKey="time" yLabel="%">
<Area dataKey="cpu" stroke={CHART_COLORS[0]} fill={CHART_COLORS[0]} fillOpacity={0.1} />
</ThemedChart>
This is a breaking change. The migration cost is bounded — only AgentInstance.tsx in the server repo uses these components.
ThemedChart API
interface ThemedChartProps {
data: Record<string, any>[]
height?: number // default 200
xDataKey?: string // default "time"
xType?: 'number' | 'category' // default "category"
xTickFormatter?: (value: any) => string
yTickFormatter?: (value: any) => string
yLabel?: string
children: React.ReactNode // Recharts elements
className?: string
}
ThemedChart renders internally:
ResponsiveContainer(width 100%, height from prop)ComposedChart(supports mixing Line + Bar + Area in one chart)CartesianGridwithrechartsTheme.cartesianGridXAxiswithrechartsTheme.xAxis+ formatterYAxiswithrechartsTheme.yAxis+ formatter + labelTooltipwith customChartTooltipcomponent
Tooltip
ThemedChart provides a custom ChartTooltip component (internal, not exported) that:
- Shows the x-value formatted as date/time in a header row (mono font, subtle border separator)
- Shows each series with colored dot + label + formatted value
- Uses DS tokens for styling (surface bg, border, shadow, mono font)
Consumers can override by passing their own <Tooltip content={...} /> as a child. Recharts uses the last Tooltip it finds, so a consumer-provided one replaces the default.
DS Re-exports
Selected Recharts components re-exported so consumers don't need recharts in their own package.json:
export { ThemedChart } from './ThemedChart/ThemedChart'
export {
Line, Area, Bar, ReferenceLine, ReferenceArea,
Legend, Brush, ComposedChart,
} from 'recharts'
More can be added on demand.
Consumer Migration — Server UI
AgentInstance.tsx has 6 charts to migrate:
| Chart | Before | After |
|---|---|---|
| CPU Usage | <AreaChart series={cpuSeries} threshold={...}> |
<ThemedChart><Area dataKey="cpu" /><ReferenceLine y={85} /></ThemedChart> |
| Memory (Heap) | <AreaChart series={heapSeries} threshold={...}> |
<ThemedChart><Area dataKey="heap" /><ReferenceLine y={max} /></ThemedChart> |
| Throughput | <LineChart series={throughputSeries}> |
<ThemedChart><Line dataKey="throughput" /></ThemedChart> |
| Error Rate | <LineChart series={errorSeries}> |
<ThemedChart><Line dataKey="errorPct" /></ThemedChart> |
| Thread Count | <LineChart series={threadSeries}> |
<ThemedChart><Line dataKey="threads" /></ThemedChart> |
| GC Pauses | <AreaChart series={gcSeries}> |
<ThemedChart><Area dataKey="gc" /></ThemedChart> |
Data prep changes from building ChartSeries[] arrays to flat objects with named keys.
Not in Scope
- Sparkline migration (no responsiveness issues, no axes/tooltips)
- SaaS UI (no chart component usage)
- Dashboard tab (already uses Recharts directly with
rechartsTheme) - New chart types (treemap, radar, etc. — consumers compose these directly)