import { useEffect, useMemo, useRef, useState } from "react"; import type { ClientOnboardingResult, DashboardSnapshot, ManagementApiClient, ManagementRole, SessionStatus } from "./contracts"; import { routeTitle } from "./contracts"; import { ApiError, createApiClient, safeApiMessage } from "./api"; import { RbacProvider } from "./rbac-context"; import { can } from "./rbac"; import { basePath, connectorDetailId, resourceKind, usePath } from "./routing"; import { Brand } from "./components/Brand"; import { CommandMenu } from "./components/CommandMenu"; import { ErrorPanel } from "./components/ErrorPanel"; import { Icon } from "./components/Icon"; import { LoadingPanel } from "./components/LoadingPanel"; import { SessionMenu } from "./components/SessionMenu"; import { navigation } from "./navigation"; import { AuthGateway } from "./pages/AuthGateway"; import { Dashboard } from "./pages/Dashboard"; import { ForbiddenPanel } from "./pages/ForbiddenPanel"; import { Operations } from "./pages/Operations"; import { ProjectDetail } from "./pages/ProjectDetail"; import { ResourcePage } from "./pages/ResourcePage"; import { SettingsPage } from "./pages/SettingsPage"; import { ConnectorDetail } from "./pages/ConnectorDetail"; import { focusableElements, isolateOutside, lockBodyScroll, trapTab } from "./components/modal-focus"; export function App({ api: apiProp }: { api?: ManagementApiClient }) { const [api] = useState(() => apiProp ?? createApiClient()); const [path, navigate] = usePath(); const [session, setSession] = useState("checking"); const [snapshot, setSnapshot] = useState(null); const [loadState, setLoadState] = useState<"idle" | "loading" | "error">("loading"); const [error, setError] = useState("The control API is unavailable."); const [roles, setRoles] = useState([]); const [subject, setSubject] = useState(null); const [navOpen, setNavOpen] = useState(false); const [commandOpen, setCommandOpen] = useState(false); const [createdClient, setCreatedClient] = useState(null); const identitySubject = useRef(null); identitySubject.current = session === "authenticated" ? subject : null; const navTriggerRef = useRef(null); const navCloseRef = useRef(null); const navSidebarRef = useRef(null); const navBackdropRef = useRef(null); const [compactNavigation, setCompactNavigation] = useState(() => window.matchMedia("(max-width: 840px)").matches); const title = useMemo(() => connectorDetailId(path) ? "Connector detail" : routeTitle(basePath(path)), [path]); const clearIdentity = () => { setRoles([]); setSnapshot(null); setSubject(null); setCreatedClient(null); }; const closeNavigation = () => setNavOpen(false); const load = async () => { setSession("checking"); setLoadState("loading"); let current; try { current = await api.session(); } catch (caught) { if (caught instanceof ApiError && caught.status === 401) { clearIdentity(); setSession("unauthenticated"); setLoadState("idle"); return; } clearIdentity(); setError(safeApiMessage(caught)); setLoadState("error"); return; } if (!current.authenticated) { clearIdentity(); setSession("unauthenticated"); setLoadState("idle"); return; } setSession("authenticated"); setRoles(current.session?.roles ?? []); setSubject(current.session?.subject ?? null); try { setSnapshot(await api.dashboard()); setLoadState("idle"); } catch (caught) { if (caught instanceof ApiError && caught.status === 401) { clearIdentity(); setSession("expired"); setError(caught.message); } else { setError(safeApiMessage(caught)); } setLoadState("error"); } }; useEffect(() => { void load(); }, []); useEffect(() => { setNavOpen(false); }, [path]); useEffect(() => { const media = window.matchMedia("(max-width: 840px)"); const update = () => { setCompactNavigation(media.matches); if (!media.matches) setNavOpen(false); }; media.addEventListener("change", update); return () => media.removeEventListener("change", update); }, []); useEffect(() => { const sidebar = navSidebarRef.current; if (!navOpen || !compactNavigation || !sidebar) return; const previouslyFocused = document.activeElement instanceof HTMLElement ? document.activeElement : null; const backdrop = navBackdropRef.current; const restoreIsolation = isolateOutside(sidebar, backdrop ? [backdrop] : []); const restoreScroll = lockBodyScroll(); const focusables = () => focusableElements(sidebar); const onFocusIn = (event: FocusEvent) => { if (event.target instanceof Node && sidebar.contains(event.target)) return; (focusables()[0] ?? sidebar).focus(); }; const onKeyDown = (event: KeyboardEvent) => { if (event.key === "Escape") { event.preventDefault(); setNavOpen(false); } else { trapTab(event, sidebar); } }; navCloseRef.current?.focus(); document.addEventListener("focusin", onFocusIn, true); document.addEventListener("keydown", onKeyDown); return () => { document.removeEventListener("focusin", onFocusIn, true); document.removeEventListener("keydown", onKeyDown); restoreIsolation(); restoreScroll(); if (previouslyFocused?.isConnected) previouslyFocused.focus(); }; }, [navOpen, compactNavigation]); useEffect(() => { if (session !== "authenticated") return; const onKeyDown = (event: KeyboardEvent) => { if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "k") { event.preventDefault(); setCommandOpen((current) => { if (!current && document.querySelector('[role="dialog"]')) return current; return !current; }); } }; document.addEventListener("keydown", onKeyDown); return () => document.removeEventListener("keydown", onKeyDown); }, [session]); const kind = resourceKind(path); const detail = basePath(path).startsWith("/projects/"); const connectorId = connectorDetailId(path); const scopeParams = new URLSearchParams(path.split("?")[1] ?? ""); const scopeKey = `${scopeParams.get("project") ?? ""}:${scopeParams.get("environment") ?? ""}`; const canReadAudit = can(roles, "audit.read"); const active = (href: string) => basePath(path) === href || (href !== "/" && basePath(path).startsWith(`${href}/`)); const authenticated = session === "authenticated"; const content = session === "checking" || loadState === "loading" ? : session === "unauthenticated" && loadState === "idle" ? : loadState === "error" ? void load()} /> : detail ? : connectorId ? : kind ? { if (subject !== null && identitySubject.current === subject) setCreatedClient(client); }} /> : snapshot && basePath(path) === "/" ? void load()} navigate={navigate} /> : basePath(path) === "/operations" ? : basePath(path) === "/settings" ? : ; return ( Skip to main content
{authenticated ? <> {navOpen ?
Same-origin · server-managed
: null}
{authenticated ?

Governance control plane

{title}

: null} {authenticated && createdClient ?
Pending client {createdClient.name} created for {createdClient.project} / {createdClient.environment}. { event.preventDefault(); navigate(`/clients?onboard=${encodeURIComponent(createdClient.id)}`); setCreatedClient(null); }}>Resume onboarding
: null} {content}
{authenticated ? setCommandOpen(false)} /> : null}
); }