skills/creating-dashboards/examples/monitoring-dashboard.tsx

222 lines
6.5 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts';
import { Activity, Cpu, HardDrive, Wifi } from 'lucide-react';
/**
* System Monitoring Dashboard
*
* Real-time infrastructure monitoring with:
* - Gauge widgets for CPU, memory, disk
* - Live request rate chart (SSE updates)
* - Alert indicators for threshold breaches
* - Color-coded health status
*/
interface GaugeProps {
title: string;
value: number;
max: number;
unit: string;
icon: React.ReactNode;
}
function Gauge({ title, value, max, unit, icon }: GaugeProps) {
const percentage = (value / max) * 100;
const color =
percentage >= 90 ? '#ef4444' :
percentage >= 70 ? '#f59e0b' :
'#10b981';
return (
<div style={{
backgroundColor: '#fff',
border: '1px solid #e2e8f0',
borderRadius: '12px',
padding: '24px',
}}>
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '16px' }}>
<div style={{ color: '#64748b' }}>{icon}</div>
<span style={{ fontSize: '14px', fontWeight: 500, color: '#64748b' }}>{title}</span>
</div>
<div style={{ position: 'relative', width: '100%', height: '120px', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
{/* Gauge background */}
<svg width="100%" height="100%" viewBox="0 0 200 120">
{/* Background arc */}
<path
d="M 20 100 A 80 80 0 0 1 180 100"
fill="none"
stroke="#e2e8f0"
strokeWidth="12"
strokeLinecap="round"
/>
{/* Value arc */}
<path
d="M 20 100 A 80 80 0 0 1 180 100"
fill="none"
stroke={color}
strokeWidth="12"
strokeLinecap="round"
strokeDasharray={`${percentage * 2.5} 251`}
/>
</svg>
<div style={{ position: 'absolute', textAlign: 'center' }}>
<div style={{ fontSize: '32px', fontWeight: 700, color }}>
{value.toFixed(1)}
<span style={{ fontSize: '20px', color: '#64748b' }}>{unit}</span>
</div>
<div style={{ fontSize: '14px', color: '#94a3b8' }}>
of {max}{unit}
</div>
</div>
</div>
</div>
);
}
export function MonitoringDashboard() {
const [metricsData, setMetricsData] = useState([
{ time: '10:00', requests: 1200 },
{ time: '10:05', requests: 1350 },
{ time: '10:10', requests: 1180 },
{ time: '10:15', requests: 1420 },
{ time: '10:20', requests: 1560 },
{ time: '10:25', requests: 1380 },
]);
// Simulate real-time updates (replace with actual SSE)
useEffect(() => {
const interval = setInterval(() => {
setMetricsData((prev) => {
const newData = [...prev.slice(1)];
const lastTime = prev[prev.length - 1].time;
const [hours, minutes] = lastTime.split(':').map(Number);
const newMinutes = (minutes + 5) % 60;
const newTime = `${hours}:${newMinutes.toString().padStart(2, '0')}`;
newData.push({
time: newTime,
requests: Math.floor(1000 + Math.random() * 600),
});
return newData;
});
}, 5000);
return () => clearInterval(interval);
}, []);
return (
<div style={{ padding: '24px', backgroundColor: '#f8fafc', minHeight: '100vh' }}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '24px' }}>
<h1 style={{ fontSize: '30px', fontWeight: 700, color: '#0f172a' }}>
System Monitoring
</h1>
<div style={{
display: 'flex',
alignItems: 'center',
gap: '8px',
padding: '8px 16px',
backgroundColor: '#10b981',
borderRadius: '8px',
color: '#fff',
fontSize: '14px',
fontWeight: 600,
}}>
<div style={{ width: '8px', height: '8px', backgroundColor: '#fff', borderRadius: '50%' }} />
All Systems Operational
</div>
</div>
{/* Gauge Widgets */}
<div style={{
display: 'grid',
gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))',
gap: '16px',
marginBottom: '24px',
}}>
<Gauge
title="CPU Usage"
value={45.2}
max={100}
unit="%"
icon={<Cpu size={20} />}
/>
<Gauge
title="Memory Usage"
value={68.5}
max={100}
unit="%"
icon={<HardDrive size={20} />}
/>
<Gauge
title="Disk Usage"
value={52.3}
max={100}
unit="%"
icon={<HardDrive size={20} />}
/>
<Gauge
title="Network I/O"
value={234}
max={1000}
unit=" Mbps"
icon={<Wifi size={20} />}
/>
</div>
{/* Request Rate Chart */}
<div style={{
backgroundColor: '#fff',
border: '1px solid #e2e8f0',
borderRadius: '12px',
padding: '24px',
}}>
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '16px' }}>
<Activity size={20} color="#64748b" />
<h2 style={{ fontSize: '18px', fontWeight: 600, color: '#0f172a', margin: 0 }}>
Request Rate (Real-time)
</h2>
<div style={{
marginLeft: 'auto',
padding: '4px 12px',
backgroundColor: '#eff6ff',
borderRadius: '6px',
fontSize: '12px',
color: '#3b82f6',
fontWeight: 600,
}}>
LIVE
</div>
</div>
<ResponsiveContainer width="100%" height={300}>
<LineChart data={metricsData}>
<CartesianGrid strokeDasharray="3 3" stroke="#e2e8f0" />
<XAxis dataKey="time" stroke="#64748b" />
<YAxis stroke="#64748b" label={{ value: 'Requests', angle: -90, position: 'insideLeft' }} />
<Tooltip
contentStyle={{
backgroundColor: '#fff',
border: '1px solid #e2e8f0',
borderRadius: '8px',
}}
/>
<Line
type="monotone"
dataKey="requests"
stroke="#3b82f6"
strokeWidth={2}
dot={false}
isAnimationActive={false}
/>
</LineChart>
</ResponsiveContainer>
</div>
</div>
);
}
export default MonitoringDashboard;