58 lines
1.5 KiB
TypeScript
58 lines
1.5 KiB
TypeScript
|
|
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} />;
|
||
|
|
}
|