• Debug command center for accessing development utilities. Displays enabled debug panels (Storage Explorer, Log Viewer, State Inspector, IPC Traffic, Event Logger). Panels are toggled from Settings → Data → Debug Tools.

    Parameters

    Returns Element

    JSX element rendering the debug menu dialog

    export function DebugMenu({ isOpen, onClose }: Readonly<DebugMenuProps>) {
    const {
    isStorageDebuggerEnabled,
    isLogViewerEnabled,
    isStateInspectorEnabled,
    isIpcViewerEnabled,
    isEventLoggerEnabled,
    isPerformanceMonitorEnabled,
    } = useDebugState();

    const [activePanel, setActivePanel] = useState<string>("");

    // Build list of enabled debug panels based on user settings
    const panels = useMemo(() => {
    const entries: DebugPanelDefinition[] = [];

    if (isStorageDebuggerEnabled) {
    entries.push({
    id: "storage",
    label: "Storage Explorer",
    description:
    "Inspect and edit localStorage and Electron Store entries in real time.",
    icon: (
    <div className="bg-primary/10 text-primary grid h-10 w-10 place-items-center rounded-xl">
    <svg
    xmlns="http://www.w3.org/2000/svg"
    viewBox="0 0 24 24"
    fill="none"
    stroke="currentColor"
    strokeWidth="1.5"
    strokeLinecap="round"
    strokeLinejoin="round"
    className="h-5 w-5"
    >
    <rect x="3" y="4" width="18" height="7" rx="1" />
    <rect x="3" y="13" width="18" height="7" rx="1" />
    <path d="M7 17h0" />
    <path d="M7 8h0" />
    </svg>
    </div>
    ),
    element: <StorageDebugger />,
    });
    }

    if (isLogViewerEnabled) {
    entries.push({
    id: "logs",
    label: "Log Viewer",
    description:
    "Review captured console output, filter by severity, and export logs for support.",
    icon: (
    <div className="grid h-10 w-10 place-items-center rounded-xl bg-purple-500/10 text-purple-500">
    <ScrollText className="h-5 w-5" />
    </div>
    ),
    element: <LogViewer />,
    });
    }

    if (isStateInspectorEnabled) {
    entries.push({
    id: "state",
    label: "State Inspector",
    description:
    "Inspect registered application state snapshots and safely mutate values for testing.",
    icon: (
    <div className="grid h-10 w-10 place-items-center rounded-xl bg-amber-500/10 text-amber-500">
    <Braces className="h-5 w-5" />
    </div>
    ),
    element: <StateInspector />,
    });
    }

    if (isIpcViewerEnabled) {
    entries.push({
    id: "ipc",
    label: "IPC Traffic",
    description:
    "Monitor renderer ↔ main process messages, filter by channel, and inspect payloads.",
    icon: (
    <div className="grid h-10 w-10 place-items-center rounded-xl bg-sky-500/10 text-sky-500">
    <Radio className="h-5 w-5" />
    </div>
    ),
    element: <IpcViewer />,
    });
    }

    if (isEventLoggerEnabled) {
    entries.push({
    id: "events",
    label: "Event Logger",
    description:
    "Timeline of captured user actions and application events with advanced filtering.",
    icon: (
    <div className="grid h-10 w-10 place-items-center rounded-xl bg-emerald-500/10 text-emerald-500">
    <ActivitySquare className="h-5 w-5" />
    </div>
    ),
    element: <EventLogger />,
    });
    }

    if (isPerformanceMonitorEnabled) {
    entries.push({
    id: "performance",
    label: "Performance Monitor",
    description:
    "Real-time monitoring of API latency, cache efficiency, matching speed, and memory usage.",
    icon: (
    <div className="grid h-10 w-10 place-items-center rounded-xl bg-rose-500/10 text-rose-500">
    <Gauge className="h-5 w-5" />
    </div>
    ),
    element: <PerformanceMonitor />,
    });
    }

    return entries;
    }, [
    isIpcViewerEnabled,
    isEventLoggerEnabled,
    isLogViewerEnabled,
    isStateInspectorEnabled,
    isStorageDebuggerEnabled,
    isPerformanceMonitorEnabled,
    setActivePanel,
    ]);

    // Ensure activePanel is valid when panels list changes
    useEffect(() => {
    if (!panels.length) {
    setActivePanel("");
    return;
    }

    // Select first panel if currently active panel is no longer available
    if (!panels.some((panel) => panel.id === activePanel)) {
    setActivePanel(panels[0].id);
    }
    }, [panels, activePanel, setActivePanel]);

    const hasPanels = panels.length > 0;

    return (
    <Dialog
    open={isOpen}
    onOpenChange={(open) => {
    if (!open) {
    onClose();
    }
    }}
    >
    <DialogContent className="border-border/60 bg-background/95 lg:max-w-5xl! max-h-[80vh] grid-rows-[auto,1fr] overflow-hidden border p-0 shadow-2xl backdrop-blur-xl md:max-w-[95vw]">
    <DialogHeader className="relative overflow-hidden px-8 pb-4 pt-8">
    <div className="from-primary/10 bg-linear-to-br absolute inset-0 h-full w-full via-purple-500/10 to-transparent" />
    <div className="bg-primary/15 absolute right-10 top-8 h-32 w-32 rounded-full blur-3xl" />
    <div className="relative z-10 flex flex-col gap-3">
    <DialogTitle className="flex items-center gap-3 text-2xl font-semibold">
    <span className="bg-muted/60 text-primary border-primary/20 hidden h-11 w-11 items-center justify-center rounded-xl border shadow-inner sm:flex">
    <Bug className="h-5 w-5" />
    </span>
    <div>
    <p className="text-muted-foreground text-xs uppercase tracking-[0.3em]">
    Internal Tools
    </p>
    <span>Debug Command Center</span>
    </div>
    </DialogTitle>
    <DialogDescription className="text-muted-foreground max-w-2xl text-sm">
    Access experimental developer utilities. Toggle individual panels
    from SettingsDataDebug Tools.
    </DialogDescription>
    {hasPanels ? (
    <Badge
    variant="outline"
    className="border-primary/40 bg-primary/10 text-primary w-fit rounded-full text-xs font-semibold"
    >
    {panels.length} panel{panels.length === 1 ? "" : "s"} enabled
    </Badge>
    ) : (
    <Badge
    variant="outline"
    className="w-fit rounded-full border-orange-300/60 bg-orange-100/40 text-xs font-semibold text-orange-600 dark:border-orange-500/40 dark:bg-orange-900/30 dark:text-orange-200"
    >
    No panels enabled
    </Badge>
    )}
    </div>
    </DialogHeader>
    <div className="flex h-full max-h-[60vh] min-h-0 flex-1 flex-col gap-6 px-8 pb-8 pt-6">
    {hasPanels ? (
    <Tabs
    value={activePanel}
    onValueChange={setActivePanel}
    orientation="vertical"
    className="flex min-h-0 flex-1"
    >
    <div className="flex min-h-0 flex-col gap-6 md:max-w-[87.5vw] lg:flex-row">
    <div className="border-border/80 bg-muted/10 relative flex w-full flex-col overflow-hidden rounded-2xl border pr-1 shadow-sm md:min-h-[10vh] lg:w-64">
    <ScrollArea type="always" className="flex h-full w-full pr-2">
    <div className="p-2">
    <TabsList
    className={cn("flex h-auto w-full flex-col gap-2")}
    aria-label="Debug panel selector"
    >
    {panels.map((panel) => (
    <TabsTrigger
    key={panel.id}
    id={`panel-${panel.id}`}
    value={panel.id}
    className={cn(
    "group w-full flex-none justify-start gap-3 rounded-xl border px-3 py-3 text-left text-sm transition-all",
    "min-h-13 h-auto",
    // default card appearance
    "bg-background/90 border-border/40",
    // active state: stronger background, border, subtle shadow and left accent
    "data-[state=active]:bg-background/30! data-[state=active]:border-primary/40! data-[state=active]:text-primary! data-[state=active]:shadow-md!",
    "hover:border-primary/30! hover:bg-primary/5!",
    // Ensure text can wrap instead of overflowing
    "wrap-break-word min-w-0 whitespace-normal",
    )}
    style={{ position: "relative" }}
    >
    <div className="flex items-start gap-3">
    <div className="shrink-0">{panel.icon}</div>
    <div className="min-w-0 flex-1 space-y-1">
    <div className="font-semibold leading-tight">
    {panel.label}
    </div>
    <p className="text-muted-foreground text-xs">
    {panel.description}
    </p>
    </div>
    </div>
    </TabsTrigger>
    ))}
    </TabsList>
    </div>
    </ScrollArea>
    </div>

    {/* Content column */}
    <div className="border-border/80 bg-background/95 relative flex-1 overflow-hidden rounded-2xl border shadow-inner md:min-h-[40vh]">
    <div className="from-primary/10 bg-linear-to-b absolute inset-x-12 top-0 h-24 rounded-b-full to-transparent blur-3xl" />
    <div className="relative h-full min-h-0 overflow-y-auto p-4">
    {panels.map((panel) => (
    <TabsContent
    key={panel.id}
    value={panel.id}
    className="h-full"
    aria-labelledby={`panel-${panel.id}`}
    >
    <div className="flex h-full min-h-[600px] flex-col">
    {panel.element}
    </div>
    </TabsContent>
    ))}
    </div>
    </div>
    </div>
    </Tabs>
    ) : (
    <div className="border-border/60 bg-muted/20 flex h-full flex-col items-center justify-center gap-4 rounded-2xl border border-dashed py-4 text-center">
    <p className="text-muted-foreground max-w-md text-sm">
    Enable at least one debug panel from{" "}
    <strong>SettingsDataDebug tools</strong> to start using
    the command center.
    </p>
    <Button variant="outline" onClick={onClose}>
    Close
    </Button>
    </div>
    )}
    </div>
    </DialogContent>
    </Dialog>
    );
    }