/** * AlertsPanel — scrollable list of anomaly alerts from the pipeline. * Alerts arrive in MetricsMessage.alerts as plain strings. */ import { useRef, useEffect } from 'react' const SEVERITY_CLASSES = { HIGH: 'border-red-500 bg-red-900/20 text-red-300', MEDIUM: 'border-yellow-500 bg-yellow-900/20 text-yellow-300', LOW: 'border-blue-500 bg-blue-900/20 text-blue-300', } function parseSeverity(text) { const upper = text.toUpperCase() if (upper.includes('HIGH') || upper.includes('STOPPED') || upper.includes('SPIKE')) return 'HIGH' if (upper.includes('MEDIUM') || upper.includes('SLOW')) return 'MEDIUM' return 'LOW' } export default function AlertsPanel({ alerts }) { const bottomRef = useRef(null) useEffect(() => { bottomRef.current?.scrollIntoView({ behavior: 'smooth' }) }, [alerts.length]) return (

Alerts

{alerts.length > 0 && ( {alerts.length} )}
{alerts.length === 0 ? (
No alerts
) : ( alerts.map((a, i) => { const sev = parseSeverity(typeof a === 'string' ? a : a.message ?? '') const text = typeof a === 'string' ? a : a.message return (
{sev}
{text}
) }) )}
) }