Builds the Workspace/Panel screen the design doc's "Layout, v1" described but nothing had implemented yet: /command-hq and /command-hq/:sessionId, three always-mounted panels (officerdev/src/apps/CommandHQ/) — a flat category nav filtering the grid via ?category=, a commander grid reading GET /commanders, and a detail pane that is either an empty state, the new-commander composer, or the selected commander's resumed transcript. Follows the frontend route conventions in CLAUDE.md throughout: Workspace/Panel framework (locked, three fixed panels, no standalone screen), category and session both addressable in the URL rather than a channel, real <Link>s for every row and card, a route pair (/command-hq + /command-hq/:sessionId) the same shape as /chat's. The composer reuses the exact mechanism /chat already uses to create a commander — an ordinary turn with context: 'command-hq' via useChat/ EmbeddableChat — rather than the mobile-only POST /commanders/new HTTP route. Once the harness reports a real transcript id the URL is replaced onto it (useChat's own permalink writes /chat/<id>, which is the wrong screen here, so that's done by hand). fileAsCommander always files a new commander uncategorised — it has no way to know a category was selected in the composer — so if one was, a client-side PATCH sets it after the fact, the same race POST /commanders/new already resolves server-side for mobile, just resolved here on the client instead. The detail panel's transcript resume mirrors ChatPanelWrapper's fetch-then- mount pattern (GET /chat/sessions/:id first, then useChat with resumeSessionId + initialMessages + paginate) rather than reusing it directly — Command HQ's version is simpler (no dashboard/agent-panel concerns) and scopes rename/category/disarm through Command HQ's own PATCH route rather than /chat's, since a commander lives in a different directory than an ordinary chat session. Card status is the three-state read COMMS/command-hq/mobile-4.md proposed and the design record adopted: green running, amber armed-but-not-running (the watcherArmed && !running pair that makes a silently-dead watcher visible), grey neither. Registered in AppRegistry.tsx, re-exported from officerdev's barrel (route helpers + types, per CLAUDE.md's rule for anything an officer-web screen needs), a CORE_DOCK_ITEMS tile (not in DEFAULT_DOCK_PATHS — opt-in via the Dock settings screen, same as Jobs/Monitor/Activity), and a usePageTitle rule. bunx tsgo clean, suite at its 7 pre-existing baseline failures, none of them this feature's. NOT yet clicked through against a running server — the composer's redirect-on-real-id, the disarm button, the category-race PATCH have all typechecked and nothing more. That's the next real test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
26 lines
894 B
TypeScript
26 lines
894 B
TypeScript
import type { LayoutNode } from 'officerdev';
|
|
import { WorkspaceView } from 'officerdev';
|
|
import { useDashboardState } from 'state/useDashboardState';
|
|
import { defaultLayout } from './defaultLayout';
|
|
|
|
// /command-hq: nav + grid + detail, all three always mounted (like /chat), selection carried by the URL
|
|
// — `?category=` for the nav filter, `:sessionId` for the open commander. See `docs/command-hq.md` →
|
|
// "Route, surface, placement" and "Layout, v1".
|
|
|
|
export const CommandHqScreen = () => {
|
|
const workspace = useDashboardState<LayoutNode>('screens/command-hq', defaultLayout);
|
|
|
|
return (
|
|
<div className="h-full w-full pt-2">
|
|
<WorkspaceView
|
|
workspace={workspace}
|
|
locked
|
|
appTypes={{
|
|
allowed: ['command-hq-categories', 'command-hq-grid', 'command-hq-detail'],
|
|
fallback: 'command-hq-detail',
|
|
}}
|
|
/>
|
|
</div>
|
|
);
|
|
};
|