From 8f2d80573af693d6246a7129ff3029253cba5bb4 Mon Sep 17 00:00:00 2001 From: Andre Padez Date: Mon, 10 Aug 2026 01:15:40 +0100 Subject: [PATCH] actually give existing users the live panel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous commit added it to defaultLayout, which anyone who has ever opened /chat never sees: useDashboardState seeds its default only when the key is ABSENT, so a stored layout keeps the shape it had when it was first written. appTypes/normalizeLayout does not cover this — it repairs which app a panel runs, never the tree — so the change was visible only on a fresh account. It was shipped with a note to reset the layout by hand, which is not a fix. The screen now replaces a layout with no chat-live panel. Replacing outright is safe here specifically because the screen is locked: the structure is dictated by code, and the only user contribution is column sizes. Terminates because the replacement contains the panel it tests for. Co-Authored-By: Claude Opus 5 --- .../Dashboard/ChatHistory/defaultLayout.ts | 6 ++++++ .../Screens/Dashboard/ChatHistory/index.tsx | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/apps/officer-web/Screens/Dashboard/ChatHistory/defaultLayout.ts b/src/apps/officer-web/Screens/Dashboard/ChatHistory/defaultLayout.ts index 24ce525c..ef4f017a 100644 --- a/src/apps/officer-web/Screens/Dashboard/ChatHistory/defaultLayout.ts +++ b/src/apps/officer-web/Screens/Dashboard/ChatHistory/defaultLayout.ts @@ -1,5 +1,11 @@ import type { LayoutNode } from 'officerdev'; +/** Does this tree contain a panel running `appType`? */ +export function hasAppType(node: LayoutNode, appType: string): boolean { + if (node.type === 'panel') return node.appType === appType; + return node.children.some((child) => hasAppType(child.node, appType)); +} + // The left column is itself a split: what is running now on top, the whole history below. They answer // different questions from different sources — the agent's in-memory map versus transcripts on disk — // and the live one is small and usually empty, hence the lopsided 25/75. diff --git a/src/apps/officer-web/Screens/Dashboard/ChatHistory/index.tsx b/src/apps/officer-web/Screens/Dashboard/ChatHistory/index.tsx index 5f8fda0a..0d24e5ca 100644 --- a/src/apps/officer-web/Screens/Dashboard/ChatHistory/index.tsx +++ b/src/apps/officer-web/Screens/Dashboard/ChatHistory/index.tsx @@ -8,7 +8,7 @@ import { useClient } from 'hooks/useClient'; import { errorText } from 'helpers/error-text'; import { useDashboardState } from 'state/useDashboardState'; import type { ClaudeSessionDetail } from 'state/useClaudeSessions'; -import { defaultLayout } from './defaultLayout'; +import { defaultLayout, hasAppType } from './defaultLayout'; // How many messages to render on first open (anchored to the bottom); scroll-up pages older ones in. const CHAT_TAIL = 20; @@ -32,6 +32,22 @@ export const SessionListPage = ({ isNew }: SessionListPageProps) => { const navigate = useNavigate(); const mobilePanelId = isMobile && (sessionId || isNew) ? 'chat-detail' : undefined; + // Adopt a structural change to this screen's layout. + // + // `useDashboardState` seeds its default ONLY when the key is absent, so anyone who has ever opened + // /chat keeps the shape it had then — for good. `appTypes`/`normalizeLayout` does not help: it repairs + // which app a panel runs, never the tree, so adding the Live panel above the list would have been + // invisible to every existing user and visible only on a fresh account. + // + // Replacing outright is safe *here* specifically because the screen is `locked`: its structure is + // dictated by code and the only thing a user can have contributed is the column sizes, which is a + // cheap thing to lose once. Terminates because the replacement contains the panel it tests for. + useEffect(() => { + if (!workspace.isLoaded) return; + if (hasAppType(workspace.value, 'chat-live')) return; + workspace.setValue(defaultLayout); + }, [workspace.isLoaded, workspace.value, workspace.setValue]); + // Retire a legacy `?cwd=`. Nothing reads it any more and nothing writes it, but a refresh re-requests // the address bar verbatim — so one left over from before the path-based groups sits there forever, // looking like it means something. On a bare /chat it still says which group you wanted, so upgrade