"use client"; import { useState, useEffect, useCallback } from "react"; import { FlaskConical, Play, RotateCcw, ChevronDown, Clock, Zap } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet"; import { Badge } from "@/components/ui/badge"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; import { fetchScenarios, triggerScenario, type ScenarioInfo } from "@/lib/api"; // ── Small select for target override ───────────────────────────────────────── function TargetSelect({ targets, value, onChange, }: { targets: string[]; value: string; onChange: (v: string) => void; }) { if (targets.length <= 1) return null; return (
); } // ── Single scenario card ────────────────────────────────────────────────────── function ScenarioCard({ scenario, active, onRun, }: { scenario: ScenarioInfo; active: boolean; onRun: (name: string, target?: string) => void; }) { const [target, setTarget] = useState(scenario.default_target ?? ""); return (
{/* Header row */}
{scenario.label} {scenario.compound && ( compound )} {active && ( running )}
{!scenario.compound && ( )}
{/* Description */}

{scenario.description}

{/* Footer */}
{scenario.duration}
); } // ── Main panel ──────────────────────────────────────────────────────────────── export function SimulatorPanel() { const [open, setOpen] = useState(false); const [scenarios, setScenarios] = useState([]); const [loading, setLoading] = useState(false); const [activeScenario, setActiveScenario] = useState(null); const [status, setStatus] = useState<{ message: string; ok: boolean } | null>(null); // Load scenario list once when panel first opens useEffect(() => { if (!open || scenarios.length > 0) return; setLoading(true); fetchScenarios() .then(setScenarios) .catch(() => setStatus({ message: "Failed to load scenarios", ok: false })) .finally(() => setLoading(false)); }, [open, scenarios.length]); const showStatus = useCallback((message: string, ok: boolean) => { setStatus({ message, ok }); setTimeout(() => setStatus(null), 3000); }, []); const handleRun = useCallback( async (name: string, target?: string) => { try { await triggerScenario(name, target); setActiveScenario(name); showStatus( `▶ ${name}${target ? ` → ${target}` : ""} triggered`, true ); } catch { showStatus("Failed to trigger scenario", false); } }, [showStatus] ); const handleReset = useCallback(async () => { try { await triggerScenario("RESET"); setActiveScenario(null); showStatus("All scenarios reset", true); } catch { showStatus("Failed to reset", false); } }, [showStatus]); const compound = scenarios.filter((s) => s.compound); const single = scenarios.filter((s) => !s.compound); return ( Scenario Simulator {/* Header */}
Scenario Simulator demo only

Inject realistic fault scenarios into the live simulator. Changes are reflected immediately across all dashboard pages.

{/* Reset bar */}
{status && ( {status.message} )}
{/* Scrollable scenario list */}
{loading && (

Loading scenarios…

)} {!loading && compound.length > 0 && (

Compound Scenarios

Multi-device, time-sequenced chains — fires automatically across the site.

{compound.map((s) => ( ))}
)} {!loading && single.length > 0 && (

Single Fault Scenarios

{single.map((s) => ( ))}
)}
); }