diff --git a/apps/web/src/app/(authenticated)/mission-control/page.tsx b/apps/web/src/app/(authenticated)/mission-control/page.tsx new file mode 100644 index 00000000..8ea71b97 --- /dev/null +++ b/apps/web/src/app/(authenticated)/mission-control/page.tsx @@ -0,0 +1,5 @@ +import { MissionControlLayout } from "@/components/mission-control/MissionControlLayout"; + +export default function MissionControlPage(): React.JSX.Element { + return ; +} diff --git a/apps/web/src/components/layout/AppSidebar.tsx b/apps/web/src/components/layout/AppSidebar.tsx index d0cbd97c..6126c427 100644 --- a/apps/web/src/components/layout/AppSidebar.tsx +++ b/apps/web/src/components/layout/AppSidebar.tsx @@ -156,6 +156,26 @@ function IconTerminal(): React.JSX.Element { ); } +function IconMissionControl(): React.JSX.Element { + return ( + + ); +} + function IconSettings(): React.JSX.Element { return ( , }, + { + href: "/mission-control", + label: "Mission Control", + icon: , + }, ], }, { diff --git a/apps/web/src/components/mission-control/GlobalAgentRoster.tsx b/apps/web/src/components/mission-control/GlobalAgentRoster.tsx new file mode 100644 index 00000000..778d06d6 --- /dev/null +++ b/apps/web/src/components/mission-control/GlobalAgentRoster.tsx @@ -0,0 +1,16 @@ +"use client"; + +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; + +export function GlobalAgentRoster(): React.JSX.Element { + return ( + + + Agent Roster + + + No active agents + + + ); +} diff --git a/apps/web/src/components/mission-control/MissionControlLayout.tsx b/apps/web/src/components/mission-control/MissionControlLayout.tsx new file mode 100644 index 00000000..135409b0 --- /dev/null +++ b/apps/web/src/components/mission-control/MissionControlLayout.tsx @@ -0,0 +1,21 @@ +"use client"; + +import { GlobalAgentRoster } from "@/components/mission-control/GlobalAgentRoster"; +import { MissionControlPanel } from "@/components/mission-control/MissionControlPanel"; + +const DEFAULT_PANEL_SLOTS = ["panel-1", "panel-2", "panel-3", "panel-4"] as const; + +export function MissionControlLayout(): React.JSX.Element { + return ( +
+
+ +
+ +
+
+
+ ); +} diff --git a/apps/web/src/components/mission-control/MissionControlPanel.tsx b/apps/web/src/components/mission-control/MissionControlPanel.tsx new file mode 100644 index 00000000..f17d37a7 --- /dev/null +++ b/apps/web/src/components/mission-control/MissionControlPanel.tsx @@ -0,0 +1,17 @@ +"use client"; + +import { OrchestratorPanel } from "@/components/mission-control/OrchestratorPanel"; + +interface MissionControlPanelProps { + panels: readonly string[]; +} + +export function MissionControlPanel({ panels }: MissionControlPanelProps): React.JSX.Element { + return ( +
+ {panels.map((panelId) => ( + + ))} +
+ ); +} diff --git a/apps/web/src/components/mission-control/OrchestratorPanel.tsx b/apps/web/src/components/mission-control/OrchestratorPanel.tsx new file mode 100644 index 00000000..6bf841a0 --- /dev/null +++ b/apps/web/src/components/mission-control/OrchestratorPanel.tsx @@ -0,0 +1,16 @@ +"use client"; + +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; + +export function OrchestratorPanel(): React.JSX.Element { + return ( + + + Orchestrator Panel + + + Select an agent + + + ); +} diff --git a/apps/web/src/hooks/useMissionControl.ts b/apps/web/src/hooks/useMissionControl.ts new file mode 100644 index 00000000..3a5a4299 --- /dev/null +++ b/apps/web/src/hooks/useMissionControl.ts @@ -0,0 +1,10 @@ +interface UseMissionControlResult { + sessions: []; + loading: boolean; + error: null; +} + +// Stub — will be wired in P2-002 +export function useMissionControl(): UseMissionControlResult { + return { sessions: [], loading: false, error: null }; +}