import { useQuery } from "@tanstack/react-query"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Activity, Globe, Shield, TrendingUp, AlertTriangle } from "lucide-react"; import { AreaChart, Area, BarChart, Bar, PieChart, Pie, Cell, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer } from "recharts"; import type { Detection, NetworkLog } from "@shared/schema"; import { getFlag } from "@/lib/country-flags"; import { format } from "date-fns"; interface DashboardStats { totalPackets: number; attackPackets: number; normalPackets: number; uniqueIps: number; attackUniqueIps: number; attacksByCountry: Record; attacksByType: Record; recentDetections: Detection[]; } export default function DashboardLive() { // Fetch aggregated stats from analytics (ultimi 72h = 3 giorni) const { data: stats, isLoading } = useQuery({ queryKey: ["/api/dashboard/live?hours=72"], refetchInterval: 10000, // Aggiorna ogni 10s }); // Usa dati aggregati precisi const totalTraffic = stats?.totalPackets || 0; const totalAttacks = stats?.attackPackets || 0; const normalTraffic = stats?.normalPackets || 0; const attackPercentage = totalTraffic > 0 ? ((totalAttacks / totalTraffic) * 100).toFixed(2) : "0"; const detections = stats?.recentDetections || []; const blockedAttacks = detections.filter(d => d.blocked).length; // Usa dati aggregati già calcolati dal backend const attacksByCountry = stats?.attacksByCountry || {}; const attacksByType = stats?.attacksByType || {}; const countryChartData = Object.entries(attacksByCountry) .map(([name, attacks]) => ({ name: `${getFlag(name, name.substring(0, 2))} ${name}`, attacks, normal: 0, })) .sort((a, b) => b.attacks - a.attacks) .slice(0, 10); const typeChartData = Object.entries(attacksByType).map(([name, value]) => ({ name: name.replace('_', ' ').toUpperCase(), value, })); // Traffico normale vs attacchi (gauge data) const trafficDistribution = [ { name: 'Normal', value: normalTraffic, color: '#22c55e' }, { name: 'Attacks', value: totalAttacks, color: '#ef4444' }, ]; // Ultimi eventi (stream) const recentEvents = [...detections] .sort((a, b) => new Date(b.detectedAt).getTime() - new Date(a.detectedAt).getTime()) .slice(0, 20); const COLORS = ['#ef4444', '#f97316', '#f59e0b', '#eab308', '#84cc16']; return (
{/* Header */}

Dashboard Live

Monitoraggio real-time (ultimi 3 giorni)

{isLoading && (
Caricamento dati...
)} {!isLoading && ( <> {/* KPI Cards */}
Traffico Totale
{totalTraffic.toLocaleString()}

pacchetti

Traffico Normale
{normalTraffic.toLocaleString()}

{(100 - parseFloat(attackPercentage)).toFixed(1)}% del totale

Attacchi Rilevati
{totalAttacks}

{attackPercentage}% del traffico

IP Bloccati
{blockedAttacks}

{totalAttacks > 0 ? ((blockedAttacks / totalAttacks) * 100).toFixed(1) : 0}% degli attacchi

{/* Charts Row 1 */}
{/* Traffic Distribution (Pie) */} Distribuzione Traffico `${entry.name}: ${entry.value}`} outerRadius={100} fill="#8884d8" dataKey="value" > {trafficDistribution.map((entry, index) => ( ))} {/* Attacks by Type (Pie) */} Tipi di Attacco {typeChartData.length > 0 ? ( `${entry.name}: ${entry.value}`} outerRadius={100} fill="#8884d8" dataKey="value" > {typeChartData.map((entry, index) => ( ))} ) : (
Nessun attacco rilevato
)}
{/* Top Countries (Bar Chart) */} Top 10 Paesi Attaccanti {countryChartData.length > 0 ? ( ) : (
Nessun dato disponibile
)}
{/* Real-time Event Stream */} Stream Eventi Recenti
{recentEvents.map(event => (
{event.countryCode && ( {getFlag(event.country, event.countryCode)} )}
{event.sourceIp}

{event.anomalyType.replace('_', ' ')} • {format(new Date(event.detectedAt), "HH:mm:ss")}

{event.blocked ? "Bloccato" : "Attivo"}
))}
)}
); }