import { AlertTriangle, ArrowRight } from "lucide-react" import React from "react" import { useObservabilityData } from "../hooks/useObservabilityData" import { useIssues } from "../hooks/useIssues" import { getServiceName, isSpanError } from "../lib/otel-utils" /** Full-width alert strip docked under the top bar; renders nothing when there is nothing anomalous. */ export const AnomalyRadarBar: React.FC = () => { const { logs, traces, showErrorsOnly, setShowErrorsOnly, setActiveTab } = useObservabilityData() const { issues } = useIssues() const errorStats = React.useMemo(() => { let errorCount = 0 const services = new Set() const note = (name: string) => { if (name !== "unknown-service") services.add(name) } logs.forEach((l) => (l.scopeLogs ?? []).forEach((sl) => (sl.logRecords ?? []).forEach((r) => { if ((r.severityNumber ?? 0) >= 17) { errorCount++ note(getServiceName(l.resource?.attributes ?? [], r.attributes ?? [])) } }), ), ) traces.forEach((t) => (t.resourceSpans ?? []).forEach((rs) => (rs.scopeSpans ?? []).forEach((ss) => (ss.spans ?? []).forEach((s) => { if (isSpanError(s)) { errorCount++ note(getServiceName(rs.resource?.attributes ?? [], s.attributes ?? [])) } }), ), ), ) return { errorCount, services: Array.from(services) } }, [logs, traces]) const topOpenIssue = React.useMemo( () => issues.filter((i) => !i.status || i.status === "open").sort((a, b) => b.count - a.count)[0] ?? null, [issues], ) if (errorStats.errorCount === 0 && !topOpenIssue) return null const services = errorStats.services.slice(0, 3).join(", ") + (errorStats.services.length > 3 ? ` +${errorStats.services.length - 3}` : "") return (
{errorStats.errorCount > 0 && ( <>{errorStats.errorCount} errors in the active window{services && · {services}} )} {topOpenIssue && ( {errorStats.errorCount > 0 ? " · top issue " : ""} {topOpenIssue.title} ×{topOpenIssue.count} ({topOpenIssue.service}) )}
{!showErrorsOnly && ( )}
) } export default AnomalyRadarBar