From f83263771fdc240c339c297c674d2c3dec267bcd Mon Sep 17 00:00:00 2001 From: SOC Analyst Date: Thu, 19 Mar 2026 11:28:26 +0100 Subject: [PATCH] =?UTF-8?q?feat(clustering):=20animation=20de=20calcul=20+?= =?UTF-8?q?=20scroll=20ind=C3=A9pendant=20des=20colonnes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Layout fix (App.tsx): - Création de MainContent avec useLocation pour layout adaptatif - Route /clustering : main sans padding, overflow-hidden, height=calc(100vh-3.5rem) → ClusteringView remplit exactement la fenêtre, colonnes scrollables indépendamment - Autres routes : comportement inchangé (px-6 py-5 overflow-auto) Animation de calcul (ClusteringView.tsx): - Overlay absolu z-20 sur le canvas pendant computing || loading - 2 anneaux concentriques contra-rotatifs (accent-primary + blue-500) - 8 noeuds orbitaux avec animate-ping colorés selon taxonomie menace - Emoji 🔬 pulsant au centre - Texte : 'Clustering en cours…' + détails (31 features, toutes les IPs) - Mise à jour toutes les 3s (texte animé) Scroll indépendant: - Panneau gauche : style height:100% explicite - Sidebar droite : style height:100% explicite - Canvas : overflow-hidden ajouté - La main a overflow-hidden → les colonnes scrollent sans bouger les voisines Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- frontend/src/App.tsx | 83 ++++++++++++++-------- frontend/src/components/ClusteringView.tsx | 57 +++++++++++++-- 2 files changed, 103 insertions(+), 37 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 82784a6..4155bb7 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -321,6 +321,57 @@ function RouteTracker() { return null; } +// ─── MainContent : layout adaptatif selon la route ─────────────────────────── +// Les vues "canvas" ont besoin d'une hauteur fixe sans padding +// pour que leurs colonnes scroll indépendamment. +const FULLHEIGHT_ROUTES = ['/clustering']; + +function MainContent({ counts: _counts }: { counts: AlertCounts | null }) { + const location = useLocation(); + const isFullHeight = FULLHEIGHT_ROUTES.some(r => location.pathname.startsWith(r)); + + if (isFullHeight) { + return ( +
+ + } /> + +
+ ); + } + + return ( +
+ + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + +
+ ); +} + // ─── App ────────────────────────────────────────────────────────────────────── export default function App() { @@ -362,36 +413,8 @@ export default function App() { {/* Fixed top header */} - {/* Scrollable page content */} -
- - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - -
+ {/* Page content — full-height sans padding pour les vues canvas */} + diff --git a/frontend/src/components/ClusteringView.tsx b/frontend/src/components/ClusteringView.tsx index ccadef6..3b9bebe 100644 --- a/frontend/src/components/ClusteringView.tsx +++ b/frontend/src/components/ClusteringView.tsx @@ -330,8 +330,8 @@ export default function ClusteringView() { return (
- {/* ── Panneau gauche ── */} -
+ {/* ── Panneau gauche (scroll indépendant) ── */} +

🔬 Clustering IPs

Rendu WebGL · K-means++ sur toutes les IPs

@@ -440,12 +440,55 @@ export default function ClusteringView() {
{/* ── Canvas WebGL (deck.gl) ── */} -
- {!data && !loading && !computing && ( -
- Cliquez sur Recalculer pour démarrer +
+ + {/* Animation de calcul — remplace le canvas pendant le traitement */} + {(computing || loading) && ( +
+ {/* Noeuds pulsants animés */} +
+ {/* Anneau tournant */} +
+
+
+
+
+
+ {/* Noeuds orbitaux représentant les clusters */} + {([0,1,2,3,4,5,6,7] as const).map((i) => { + const angle = (i / 8) * 2 * Math.PI; + const r = 88; + const x = 50 + (r / 1.12) * Math.cos(angle); + const y = 50 + (r / 1.12) * Math.sin(angle); + const colors = ['#dc2626','#f97316','#eab308','#22c55e','#3b82f6','#8b5cf6','#ec4899','#14b8a6']; + return ( +
+ ); + })} + {/* Centre */} +
+
🔬
+
+
+

Clustering en cours…

+

K-means++ · 31 features · toutes les IPs

+

Mise à jour automatique toutes les 3 secondes

)} + + {/* Message état vide */} + {!data && !loading && !computing && ( +
+ 🔬 + Cliquez sur Recalculer pour démarrer +
+ )} + +
{/* Header */}