Spaces:
Sleeping
Sleeping
File size: 2,965 Bytes
9b2dc95 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | import { useState } from 'react';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend } from 'recharts';
import { Metrics } from '../types';
interface MetricsChartProps {
data: Metrics | null;
metric: 'cpu' | 'memory';
loading?: boolean;
}
export function MetricsChart({ data, metric, loading }: MetricsChartProps) {
const [visible, setVisible] = useState({ avg: true, max: true, min: true });
const chartData = data?.timestamps.map((ts, i) => ({
time: new Date(ts).toLocaleTimeString(),
avg: data[metric].avg[i] ?? 0,
max: data[metric].max[i] ?? 0,
min: data[metric].min[i] ?? 0,
})) || [];
const colors = {
avg: '#60a5fa',
max: '#f87171',
min: '#4ade80',
};
const label = metric === 'cpu' ? 'CPU %' : 'Memory %';
if (loading) {
return (
<div className="bg-gray-800 rounded-lg p-4 animate-pulse">
<div className="h-64 bg-gray-700 rounded"></div>
</div>
);
}
return (
<div className="bg-gray-800 rounded-lg p-4 border border-gray-700">
<div className="flex items-center justify-between mb-4">
<h3 className="text-lg font-semibold text-white">{label}</h3>
<div className="flex gap-2">
{(['avg', 'max', 'min'] as const).map((key) => (
<button
key={key}
onClick={() => setVisible(v => ({ ...v, [key]: !v[key] }))}
className={`px-2 py-1 rounded text-xs transition ${
visible[key] ? 'bg-gray-600 text-white' : 'bg-gray-700 text-gray-400'
}`}
>
{key.toUpperCase()}
</button>
))}
</div>
</div>
<div className="h-64">
<ResponsiveContainer width="100%" height="100%">
<LineChart data={chartData}>
<CartesianGrid strokeDasharray="3 3" stroke="#374151" />
<XAxis dataKey="time" stroke="#9ca3af" fontSize={10} />
<YAxis stroke="#9ca3af" fontSize={10} domain={[0, 100]} />
<Tooltip
contentStyle={{ backgroundColor: '#1f2937', border: 'none', borderRadius: '8px' }}
labelStyle={{ color: '#9ca3af' }}
/>
<Legend />
{visible.avg && (
<Line type="monotone" dataKey="avg" stroke={colors.avg} strokeWidth={2} dot={false} name="Avg" />
)}
{visible.max && (
<Line type="monotone" dataKey="max" stroke={colors.max} strokeWidth={2} dot={false} name="Max" />
)}
{visible.min && (
<Line type="monotone" dataKey="min" stroke={colors.min} strokeWidth={2} dot={false} name="Min" />
)}
</LineChart>
</ResponsiveContainer>
</div>
{chartData.length === 0 && (
<div className="absolute inset-0 flex items-center justify-center text-gray-500">
No data available
</div>
)}
</div>
);
} |