import { useEffect, useState } from "react";
import { applyTheme, readTheme, type ThemeMode } from "../lib/theme";
import { getAuthToken, getStoredRole, health } from "../lib/api";
import { useAppStore } from "../store/useAppStore";
import type { WsStatus } from "../lib/types";
import { UiModeSwitch } from "../design/UiModeSwitch";
import { ADMIN_GROUPS, ADMIN_SECTIONS } from "./sections";
import { navigateAdmin, navigateUserShell, type AdminSectionId } from "./router";
import { Button, Tag, type TagTone } from "../components/primitives";
import { Icon } from "../components/Icon";
import { DashboardModule } from "./modules/Dashboard";
import { PersonasModule } from "./modules/Personas";
import { SessionsModule } from "./modules/Sessions";
import { MemoriesModule } from "./modules/Memories";
import { PluginsModule } from "./modules/Plugins";
import { ChannelsModule } from "./modules/Channels";
import { ChannelEventsModule } from "./modules/ChannelEvents";
import { IoTModule } from "./modules/IoT";
import { RagModule } from "./modules/Rag";
import { LlmModule } from "./modules/Llm";
import { AutomationsModule } from "./modules/Automations";
import { AgentsModule } from "./modules/Agents";
import { FlowModule } from "./modules/Flow";
import { BackthinkModule } from "./modules/Backthink";
import { NotificationsModule } from "./modules/Notifications";
import { ObservabilityModule } from "./modules/Observability";
import { UsersModule } from "./modules/Users";
import { SystemModule } from "./modules/System";
function renderSection(section: AdminSectionId): React.ReactNode {
switch (section) {
case "dashboard": return ;
case "personas": return ;
case "sessions": return ;
case "memories": return ;
case "plugins": return ;
case "channels": return ;
case "channel-events": return ;
case "iot": return ;
case "rag": return ;
case "llm": return ;
case "automations": return ;
case "agents": return ;
case "flow": return ;
case "backthink": return ;
case "notifications": return ;
case "observability": return ;
case "users": return ;
case "system": return ;
default: return ;
}
}
/**
* Sidebar content shared by the desktop rail and the mobile drawer (design/10).
* Both render ADMIN_GROUPS with the same `onNavigate` hook — the drawer passes
* its close callback (tap an item → close), the desktop rail passes a no-op — so
* desktop and mobile never diverge.
*/
function adminNavContent({ active, onNavigate }: { active: AdminSectionId; onNavigate: () => void }): React.ReactNode {
return (
<>
{ADMIN_GROUPS.map((group) => (
);
}
export function AdminApp({ section }: { section: AdminSectionId }): React.ReactNode {
// Mobile nav drawer — only surfaced on the admin shell (md+ keeps the fixed
// sidebar); the login/403 guards never render it but still hold the hook.
const [adminMenuOpen, setAdminMenuOpen] = useState(false);
// RBAC guard (design/10 §2 + design/11 §7). A logged-in viewer or an
// unauthenticated user never sees the admin module; the gateway would also
// reject them with 401/403.
if (!getAuthToken() || !getStoredRole()) {
return (