+
+
+
+
+
+ {error ?
{safeText(error)}
: null}
+ {!loading && !items.length ?
No correlated incidents
The engine waits for multiple related signals before creating an incident.
: null}
+ {items.length ?
+
+ {items.map((incident) => (
+
+ ))}
+
+
+
: null}
+
+ );
+}
diff --git a/frontend/src/components/IncidentsPanel.test.jsx b/frontend/src/components/IncidentsPanel.test.jsx
new file mode 100644
index 0000000..1a8adcc
--- /dev/null
+++ b/frontend/src/components/IncidentsPanel.test.jsx
@@ -0,0 +1,47 @@
+import { fireEvent, render, screen, waitFor } from "@testing-library/react";
+import { describe, expect, it, vi } from "vitest";
+
+import { IncidentsPanel } from "./IncidentsPanel";
+
+const incident = {
+ incident_id: "inc-1",
+ title: "Possible Beaconing",
+ type: "possible_beaconing",
+ severity: "high",
+ confidence: "high",
+ status: "open",
+ signal_count: 4,
+ source_hosts: ["10.0.0.5"],
+ applications: ["browser.exe"],
+ services: ["Unknown encrypted destination"],
+ domains: ["unknown.example"],
+ evidence: ["Repeated outbound TLS", "token=raw-secret"],
+ correlation_reasons: ["Same source host within correlation window"],
+ recommended_investigation_steps: ["Review the destination."],
+ false_positive_notes: ["Background updates may be periodic."],
+ related_flows: ["flow-1"], related_alerts: ["alert-1"], related_agents: [],
+ timeline: [{ timestamp: "2026-07-15T12:00:00Z", source: "alert", severity: "high", summary: "Bearer another-secret" }],
+};
+
+describe("IncidentsPanel", () => {
+ it("renders an empty state", async () => {
+ const api = { getIncidents: vi.fn().mockResolvedValue({ items: [] }), getIncident: vi.fn() };
+ render(