56 lines
2.1 KiB
TypeScript
56 lines
2.1 KiB
TypeScript
/**
|
|
* Traffic Chart — Recharts line chart for bandwidth over time
|
|
* Ball Studios <https://git.balls.studio>
|
|
*/
|
|
|
|
import React from 'react';
|
|
import {
|
|
LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer,
|
|
} from 'recharts';
|
|
|
|
interface DataPoint {
|
|
rx_bytes: number;
|
|
tx_bytes: number;
|
|
recorded_at: string;
|
|
}
|
|
|
|
interface Props { data: DataPoint[]; }
|
|
|
|
function formatTick(bytes: number): string {
|
|
if (bytes < 1024) return `${bytes}B`;
|
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)}K`;
|
|
return `${(bytes / 1024 / 1024).toFixed(1)}M`;
|
|
}
|
|
|
|
export default function TrafficChart({ data }: Props) {
|
|
if (data.length === 0) {
|
|
return <div className='addon-empty'>No historical data available yet.</div>;
|
|
}
|
|
|
|
const chartData = data.map(d => ({
|
|
time: new Date(d.recorded_at).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }),
|
|
rx: d.rx_bytes,
|
|
tx: d.tx_bytes,
|
|
}));
|
|
|
|
return (
|
|
<ResponsiveContainer width='100%' height={260}>
|
|
<LineChart data={chartData} margin={{ top: 8, right: 20, left: 0, bottom: 0 }}>
|
|
<CartesianGrid strokeDasharray='3 3' stroke='rgba(255,255,255,0.08)' />
|
|
<XAxis dataKey='time' tick={{ fill: '#9ca3af', fontSize: 11 }} tickLine={false} />
|
|
<YAxis tickFormatter={formatTick} tick={{ fill: '#9ca3af', fontSize: 11 }} tickLine={false} />
|
|
<Tooltip
|
|
contentStyle={{ background: '#1f2937', border: 'none', borderRadius: 8 }}
|
|
formatter={(v: number, name: string) => [
|
|
`${(v / 1024 / 1024).toFixed(2)} MB`,
|
|
name === 'rx' ? '⬇ Inbound' : '⬆ Outbound',
|
|
]}
|
|
/>
|
|
<Legend formatter={(v) => v === 'rx' ? '⬇ Inbound' : '⬆ Outbound'} />
|
|
<Line type='monotone' dataKey='rx' stroke='#34d399' dot={false} strokeWidth={2} />
|
|
<Line type='monotone' dataKey='tx' stroke='#60a5fa' dot={false} strokeWidth={2} />
|
|
</LineChart>
|
|
</ResponsiveContainer>
|
|
);
|
|
}
|