import { useQuery } from '@tanstack/react-query' import { Activity, AlertTriangle, Bell, Cpu, Database, ShieldAlert } from 'lucide-react' import { PieChart, Pie, Cell, Tooltip as ChartTooltip, BarChart, Bar, XAxis, YAxis, ResponsiveContainer, } from 'recharts' import { api, type Alert, type ProcessMetric } from '@/lib/api' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { SystemChart } from '@/components/SystemChart' // ── shared tooltip style ────────────────────────────────────────────────────── const TOOLTIP_STYLE = { contentStyle: { background: '#111118', border: '1px solid #00ff9d33', borderRadius: 6, fontSize: 12, fontFamily: 'JetBrains Mono, monospace', }, labelStyle: { color: '#6b7280' }, } // ── stat card ───────────────────────────────────────────────────────────────── function StatCard({ title, value, icon: Icon, accent = '#00ff9d', }: { title: string value: string | number icon: React.ElementType accent?: string }) { return (
{title}
{value}
) } // ── active anomalies list ───────────────────────────────────────────────────── function ActiveAnomaliesList({ procs }: { procs: ProcessMetric[] }) { return (
Активные угрозы {procs.length > 0 && ( {procs.length} )}
{procs.length === 0 ? (
Аномалий не обнаружено
) : (
    {procs.map((p) => (
  • {p.name} PID {p.pid}
    CPU {p.cpu_percent}% RAM {Math.round(p.memory_mb)} МБ {p.connections > 0 && ( {p.connections} TCP )}
  • ))}
)}
) } // ── severity donut ──────────────────────────────────────────────────────────── const SEV_META = [ { key: 'high', label: 'Высокий', color: '#ff3366' }, { key: 'medium', label: 'Средний', color: '#ff6b35' }, { key: 'low', label: 'Низкий', color: '#00d4ff' }, ] as const function SeverityDonut({ alerts }: { alerts: Alert[] }) { const counts = { high: 0, medium: 0, low: 0 } for (const a of alerts) counts[a.severity] = (counts[a.severity] || 0) + 1 const data = SEV_META.map((m) => ({ name: m.label, value: counts[m.key], color: m.color })) .filter((d) => d.value > 0) const renderLegend = () => ( ) return ( Алерты по серьёзности {data.length === 0 ? (
Алертов нет
) : (
{data.map((d) => ( ))} [v, n]} />
{renderLegend()}
)}
) } // ── top processes bar ───────────────────────────────────────────────────────── function TopProcessesBar({ alerts }: { alerts: Alert[] }) { const counts: Record = {} for (const a of alerts) { counts[a.process_name] = (counts[a.process_name] || 0) + (a.count ?? 1) } const data = Object.entries(counts) .sort(([, a], [, b]) => b - a) .slice(0, 6) .map(([name, value]) => ({ name, value })) return ( Топ процессов по алертам {data.length === 0 ? (
Нет данных
) : ( [v, 'алертов']} /> )}
) } // ── main component ──────────────────────────────────────────────────────────── export function Overview() { const { data: stats } = useQuery({ queryKey: ['stats'], queryFn: api.stats, refetchInterval: 5_000, }) const { data: sysRows } = useQuery({ queryKey: ['system-metrics'], queryFn: () => api.systemMetrics(60), refetchInterval: 5_000, }) const { data: activeProcs } = useQuery({ queryKey: ['active-anomalies'], queryFn: api.activeAnomalies, refetchInterval: 5_000, }) const { data: alerts } = useQuery({ queryKey: ['alerts'], queryFn: () => api.alerts(200), refetchInterval: 10_000, }) const chartData = (sysRows ?? []).map((r) => ({ t: r.timestamp.slice(11, 19), cpu: Math.round(r.cpu_percent * 10) / 10, ram: Math.round(r.ram_percent * 10) / 10, })) return (
{/* Stat cards */}
{/* Active anomalies + system chart */}
Нагрузка системы — реальное время (60 точек)
{/* Severity donut + top processes */}
) }