import { useState } from "react"; import { ShieldAlert, Download } from "lucide-react"; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Cell, } from "recharts"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Skeleton } from "@/components/ui/skeleton"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@/components/ui/table"; import { useAuditLogs } from "@/api/logs"; import type { AuditEntry } from "@/types/api"; const SENSITIVITY_COLORS: Record = { none: "#94a3b8", low: "#60a5fa", medium: "#f59e0b", high: "#f97316", critical: "#ef4444", }; const PERIOD_OPTIONS = [ { value: "7", label: "7 derniers jours" }, { value: "30", label: "30 derniers jours" }, { value: "90", label: "90 derniers jours" }, ]; function getPeriodStart(days: number): string { const d = new Date(); d.setDate(d.getDate() - days); return d.toISOString(); } function buildSensitivityChart(entries: AuditEntry[]) { const counts: Record = { none: 0, low: 0, medium: 0, high: 0, critical: 0, }; for (const e of entries) { const key = e.sensitivity_level || "none"; counts[key] = (counts[key] ?? 0) + 1; } return Object.entries(counts).map(([name, count]) => ({ name, count })); } function buildTopUsers(entries: AuditEntry[], limit = 10) { const map = new Map(); for (const e of entries) { const cur = map.get(e.user_id) ?? { pii: 0, requests: 0 }; cur.pii += e.pii_entity_count; cur.requests += 1; map.set(e.user_id, cur); } return [...map.entries()] .sort((a, b) => b[1].pii - a[1].pii) .slice(0, limit) .map(([userId, stats]) => ({ userId, ...stats })); } function exportCSV(entries: AuditEntry[]) { const headers = [ "timestamp", "user_id", "provider", "model_used", "sensitivity_level", "pii_entity_count", "status", "cost_usd", ]; const rows = entries.map((e) => headers.map((h) => String(e[h as keyof AuditEntry] ?? "")).join(",") ); const csv = [headers.join(","), ...rows].join("\n"); const blob = new Blob([csv], { type: "text/csv" }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = `security-logs-${new Date().toISOString().slice(0, 10)}.csv`; a.click(); URL.revokeObjectURL(url); } export function SecurityPage() { const [period, setPeriod] = useState("30"); const start = getPeriodStart(parseInt(period, 10)); const { data, isLoading } = useAuditLogs({ start, limit: 500 }, 60_000); const entries = data?.data ?? []; const blockedEntries = entries.filter((e) => e.status !== "ok"); const chartData = buildSensitivityChart(entries); const topUsers = buildTopUsers(entries); return (

Sécurité RSSI

Vue consolidée des risques et données sensibles

{/* KPIs */}
{[ { label: "Requêtes totales", value: isLoading ? "—" : entries.length.toLocaleString() }, { label: "Requêtes bloquées", value: isLoading ? "—" : blockedEntries.length.toLocaleString() }, { label: "Données PII détectées", value: isLoading ? "—" : entries.reduce((s, e) => s + e.pii_entity_count, 0).toLocaleString(), }, { label: "Requêtes critique/haute", value: isLoading ? "—" : entries.filter((e) => e.sensitivity_level === "critical" || e.sensitivity_level === "high").length.toLocaleString(), }, ].map((kpi) => (

{kpi.label}

{kpi.value}

))}
{/* Sensitivity chart */}

Répartition par sensibilité

{isLoading ? ( ) : ( {chartData.map((entry) => ( ))} )}
{/* Top users by PII count */}

Top 10 utilisateurs (données PII)

{isLoading ? (
{Array.from({ length: 5 }).map((_, i) => ( ))}
) : topUsers.length === 0 ? (

Aucune donnée

) : (
{topUsers.map((u, idx) => (
#{idx + 1} {u.userId}
{u.requests} req. {u.pii} PII
))}
)}
{/* Blocked requests timeline */}

Requêtes bloquées / en erreur {blockedEntries.length > 0 && ( {blockedEntries.length} )}

{isLoading ? (
{Array.from({ length: 4 }).map((_, i) => ( ))}
) : blockedEntries.length === 0 ? (

Aucune requête bloquée sur la période — système sain ✓

) : (
Horodatage Utilisateur Modèle Sensibilité Erreur {blockedEntries.slice(0, 20).map((e) => ( {new Date(e.timestamp).toLocaleString("fr-FR")} {e.user_id} {e.model_used || e.model_requested} {e.sensitivity_level || "—"} {e.error_type || e.status} ))}
)}
); }