| 1 | import { lazy, Suspense, type ComponentProps } from "react"; |
| 2 | import { RemoteHostKeyDialog } from "../components/RemoteHostKeyDialog"; |
| 3 | import { RemoteSecretDialog } from "../components/RemoteSecretDialog"; |
| 4 | import { ShortcutsCheatsheet } from "../components/ShortcutsCheatsheet"; |
| 5 | import { StartupSplash } from "../components/StartupSplash"; |
| 6 | import { ManagementSurface } from "../components/ManagementSurface"; |
| 7 | |
| 8 | const HistoryPanel = lazy(() => import("../components/HistoryPanel").then((module) => ({ default: module.HistoryPanel }))); |
| 9 | const SessionRecoveryVersionsHost = lazy(() => import("../components/SessionRecoveryVersionsHost").then((module) => ({ default: module.SessionRecoveryVersionsHost }))); |
| 10 | const loadSettingsPage = () => import("../components/SettingsPanelEntry").then((module) => ({ default: module.SettingsPanel })); |
| 11 | const loadTrashPage = () => import("../components/TrashPage").then((module) => ({ default: module.TrashPage })); |
| 12 | const loadAutomationPage = () => import("../custom/features/heartbeat/HeartbeatPanel").then((module) => ({ default: module.HeartbeatView })); |
| 13 | type LoadedProps<T> = T extends () => Promise<{ default: React.ComponentType<infer Props> }> ? Props : never; |
| 14 | const CommandPalette = lazy(() => import("../components/CommandPalette").then((module) => ({ default: module.CommandPalette }))); |
| 15 | const WorktreeMergeModal = lazy(() => import("../components/WorktreeMergeModal").then((module) => ({ default: module.WorktreeMergeModal }))); |
| 16 | |
| 17 | type Region<Props, ViewKey extends keyof Props> = { |
| 18 | view: Pick<Props, ViewKey>; |
| 19 | commands: Omit<Props, ViewKey>; |
| 20 | }; |
| 21 | |
| 22 | export type AppOverlayHostProps = { |
| 23 | history?: Region<ComponentProps<typeof HistoryPanel>, "kind" | "sessions" | "running">; |
| 24 | recovery: Region<ComponentProps<typeof SessionRecoveryVersionsHost>, "sessions">; |
| 25 | settings?: Region<LoadedProps<typeof loadSettingsPage>, "initialTab" | "initialFocus" | "agentRunning" | "desktopPlatform" | "activeWorkspaceKey">; |
| 26 | trash?: Region<LoadedProps<typeof loadTrashPage>, "active">; |
| 27 | automation?: Region<LoadedProps<typeof loadAutomationPage>, "active">; |
| 28 | palette?: Region<ComponentProps<typeof CommandPalette>, "open" | "items" | "placeholder" | "emptyText">; |
| 29 | shortcuts: Region<ComponentProps<typeof ShortcutsCheatsheet>, "open" | "platform" | "t">; |
| 30 | startup?: Region<ComponentProps<typeof StartupSplash>, "hold">; |
| 31 | worktree?: Region<ComponentProps<typeof WorktreeMergeModal>, "tabId" | "isOpen">; |
| 32 | }; |
| 33 | |
| 34 | /** Presentation-only overlay region. Async ownership stays in feature owners. */ |
| 35 | export function AppOverlayHost({ history, recovery, settings, trash, automation, palette, shortcuts, startup, worktree }: AppOverlayHostProps) { |
| 36 | return ( |
| 37 | <> |
| 38 | {history && <Suspense fallback={null}><HistoryPanel {...history.view} {...history.commands} /></Suspense>} |
| 39 | <Suspense fallback={null}><SessionRecoveryVersionsHost {...recovery.view} {...recovery.commands} /></Suspense> |
| 40 | {trash && <ManagementSurface loader={loadTrashPage} active={trash.view.active} onBack={trash.commands.onBack} |
| 41 | surfaceProps={{ ...trash.view, ...trash.commands }} />} |
| 42 | {automation && <ManagementSurface loader={loadAutomationPage} active={automation.view.active !== false} onBack={automation.commands.onBack!} |
| 43 | surfaceProps={{ ...automation.view, ...automation.commands }} />} |
| 44 | {settings && <ManagementSurface loader={loadSettingsPage} active onBack={settings.commands.onClose} |
| 45 | surfaceProps={{ ...settings.view, ...settings.commands }} />} |
| 46 | <RemoteHostKeyDialog /> |
| 47 | <RemoteSecretDialog /> |
| 48 | {palette && <Suspense fallback={null}><CommandPalette {...palette.view} {...palette.commands} /></Suspense>} |
| 49 | <ShortcutsCheatsheet {...shortcuts.view} {...shortcuts.commands} /> |
| 50 | {startup && <StartupSplash {...startup.view} {...startup.commands} />} |
| 51 | {worktree && <Suspense fallback={null}><WorktreeMergeModal {...worktree.view} {...worktree.commands} /></Suspense>} |
| 52 | </> |
| 53 | ); |
| 54 | } |
| 55 |