From 7fe77d235bcad79ab3b05a71f79ab41906bac0ba Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 19 May 2026 08:52:36 +0000 Subject: [PATCH] fix: correct AlertSource/AlertSeverity casing to match serde snake_case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause: AlertSource and AlertSeverity use #[serde(rename_all = "snake_case")], so the JSON values are "ml"/"rule"/"fusion" and "high"/"critical" — not PascalCase. SOURCE_CONFIG and SEVERITY_CONFIG keys were PascalCase, causing undefined lookups. Changes: - Type aliases: 'Ml'|'Rule'|'Fusion' -> 'ml'|'rule'|'fusion' 'High'|'Critical' -> 'high'|'critical' - SOURCE_CONFIG keys: Ml/Rule/Fusion -> ml/rule/fusion - SEVERITY_CONFIG keys: Critical/High -> critical/high - All source/severity comparisons updated to lowercase - Stats filter predicates updated to lowercase - Filter button arrays updated to lowercase https://claude.ai/code/session_01Wen51749mAnwBEfh7XmvUw --- .research/frontend-refactor/detection.tsx | 42 +++++++++++------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/.research/frontend-refactor/detection.tsx b/.research/frontend-refactor/detection.tsx index c89acd9..f8ed249 100644 --- a/.research/frontend-refactor/detection.tsx +++ b/.research/frontend-refactor/detection.tsx @@ -26,8 +26,8 @@ import LoadingSpinner from '../components/LoadingSpinner' // --- Types (mirrors backend UnifiedAlert) --- -type AlertSource = 'Ml' | 'Rule' | 'Fusion' -type AlertSeverity = 'High' | 'Critical' +type AlertSource = 'ml' | 'rule' | 'fusion' +type AlertSeverity = 'high' | 'critical' interface UnifiedAlert { timestamp: number @@ -50,19 +50,19 @@ interface UnifiedAlert { // --- Display config --- const SOURCE_CONFIG = { - Ml: { - label: 'AI', + ml: { + label: 'ML', color: '#7c3aed', bgColor: 'rgba(124,58,237,0.10)', icon: faBrain, }, - Rule: { + rule: { label: 'Rule', color: '#2563eb', bgColor: 'rgba(37,99,235,0.10)', icon: faScroll, }, - Fusion: { + fusion: { label: 'Fusion', color: '#dc2626', bgColor: 'rgba(220,38,38,0.10)', @@ -71,13 +71,13 @@ const SOURCE_CONFIG = { } as const const SEVERITY_CONFIG = { - Critical: { + critical: { label: 'Critical', color: '#dc2626', bgColor: 'rgba(220,38,38,0.10)', icon: faExclamationTriangle, }, - High: { + high: { label: 'High', color: '#d97706', bgColor: 'rgba(217,119,6,0.10)', @@ -383,7 +383,7 @@ const AlertDetails: React.FC = ({ alert, onClose, showNotific {(alert.attack_type || alert.rule_msg) && (
- {alert.source === 'Ml' ? 'Attack Type' : 'Rule Message'}: + {alert.source === 'ml' ? 'Attack Type' : 'Rule Message'}:

{alert.attack_type ?? alert.rule_msg}

@@ -392,7 +392,7 @@ const AlertDetails: React.FC = ({ alert, onClose, showNotific )} {/* ML inference metrics */} - {(alert.source === 'Ml' || alert.source === 'Fusion') && ( + {(alert.source === 'ml' || alert.source === 'fusion') && (

ML Inference Metrics

@@ -420,7 +420,7 @@ const AlertDetails: React.FC = ({ alert, onClose, showNotific )} {/* Rule SID */} - {(alert.source === 'Rule' || alert.source === 'Fusion') && alert.rule_sid !== null && ( + {(alert.source === 'rule' || alert.source === 'fusion') && alert.rule_sid !== null && (

Rule Info

@@ -530,11 +530,11 @@ const Detection: React.FC = () => { const stats = useMemo( () => ({ total: alerts.length, - critical: alerts.filter(a => a.severity === 'Critical').length, - high: alerts.filter(a => a.severity === 'High').length, - ml: alerts.filter(a => a.source === 'Ml').length, - rule: alerts.filter(a => a.source === 'Rule').length, - fusion: alerts.filter(a => a.source === 'Fusion').length, + critical: alerts.filter(a => a.severity === 'critical').length, + high: alerts.filter(a => a.severity === 'high').length, + ml: alerts.filter(a => a.source === 'ml').length, + rule: alerts.filter(a => a.source === 'rule').length, + fusion: alerts.filter(a => a.source === 'fusion').length, uniqueIPs: new Set([...alerts.map(a => a.src_ip), ...alerts.map(a => a.dst_ip)]).size, }), [alerts] @@ -652,15 +652,15 @@ const Detection: React.FC = () => { {/* Source filter */}
Source: - {(['all', 'Ml', 'Rule', 'Fusion'] as const).map(s => ( + {(['all', 'ml', 'rule', 'fusion'] as const).map(s => ( setSourceFilter(s)} activeColor={ s === 'all' ? '#374151' - : s === 'Ml' ? '#7c3aed' - : s === 'Rule' ? '#2563eb' + : s === 'ml' ? '#7c3aed' + : s === 'rule' ? '#2563eb' : '#dc2626' } > @@ -674,13 +674,13 @@ const Detection: React.FC = () => { {/* Severity filter */}
Severity: - {(['all', 'Critical', 'High'] as const).map(s => ( + {(['all', 'critical', 'high'] as const).map(s => ( setSeverityFilter(s)} activeColor={ - s === 'all' ? '#374151' : s === 'Critical' ? '#dc2626' : '#d97706' + s === 'all' ? '#374151' : s === 'critical' ? '#dc2626' : '#d97706' } > {s === 'all' ? 'All' : SEVERITY_CONFIG[s].label}