From bd3f3c771466750dc5f6b8ef876e778c6f9f5921 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Tue, 18 Aug 2026 15:19:28 +0200 Subject: [PATCH] fix(app): seed changes tab in explorer pane even when setup tab occupies it The explorer companion pane retention commit (de9e85862) auto-opens the setup progress tab into the hidden explorer pane. toggleWorkspaceExplorerPane only seeded the working_diff (Changes) tab when the pane was completely empty, so once the setup tab landed there, clicking the explorer toggle could never surface Changes/Files again via that pane's default tab. Also fixes two e2e testid locators (workspace-new-tab-menu-trigger) and one unit test assertion (browser automation handler) that assumed a bare pane root, which predates that same explorer-pane-retention change: the workspace root is now always a group with a hidden companion pane, so unscoped locators/assertions must target the visible/named pane. --- .../app/e2e/browser/terminal-stuck-size.spec.ts | 9 +++++++-- .../desktop/browser/automation/handler.test.ts | 15 ++++++++++----- .../src/screens/workspace/workspace-screen.tsx | 10 +++++++++- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/packages/app/e2e/browser/terminal-stuck-size.spec.ts b/packages/app/e2e/browser/terminal-stuck-size.spec.ts index 45c70838d..ffca86b93 100644 --- a/packages/app/e2e/browser/terminal-stuck-size.spec.ts +++ b/packages/app/e2e/browser/terminal-stuck-size.spec.ts @@ -56,7 +56,10 @@ async function readRenderedTerminalSize(page: Page): Promise { - await page.getByTestId("workspace-new-tab-menu-trigger").click(); + // Workspaces always render a hidden explorer companion pane alongside the + // main pane, so an unscoped testid locator matches both; scope to the + // visible one. + await page.getByTestId("workspace-new-tab-menu-trigger").filter({ visible: true }).click(); await page.getByTestId("workspace-new-tab-menu-terminal").click(); } @@ -124,7 +127,9 @@ test.describe("terminal PTY size claim under lost window focus", () => { await page.setViewportSize({ width: 1280, height: 900 }); await page.goto(buildHostWorkspaceRoute(getServerId(), harness.workspaceId)); - await expect(page.getByTestId("workspace-new-tab-menu-trigger")).toBeVisible({ + await expect( + page.getByTestId("workspace-new-tab-menu-trigger").filter({ visible: true }), + ).toBeVisible({ timeout: 30_000, }); diff --git a/packages/app/src/desktop/browser/automation/handler.test.ts b/packages/app/src/desktop/browser/automation/handler.test.ts index 81e1f0bb6..739584e0e 100644 --- a/packages/app/src/desktop/browser/automation/handler.test.ts +++ b/packages/app/src/desktop/browser/automation/handler.test.ts @@ -4,6 +4,7 @@ import { createJSONStorage, type StateStorage } from "zustand/middleware"; import { mountBrowserAutomationHandler } from "./handler"; import type { DesktopHostBridge } from "@/desktop/host"; import { useBrowserStore } from "@/desktop/browser/store"; +import { findPaneById } from "@/stores/workspace-layout-actions"; import { useWorkspaceLayoutStore } from "@/stores/workspace-layout-store"; import { buildWorkspaceTabPersistenceKey } from "@/workspace-tabs/model"; @@ -306,11 +307,15 @@ describe("mountBrowserAutomationHandler", () => { target: { kind: "browser", browserId: result.browserId }, }), ]); - expect(layout?.root).toEqual( - expect.objectContaining({ - kind: "pane", - pane: expect.objectContaining({ focusedTabId: previousFocusedTabId }), - }), + // Workspaces keep a stable hidden explorer companion pane at the root + // (see "retain workspace explorer pane"), so the root is a group and the + // draft/browser tabs land in the "main" pane, not at the root directly. + if (!layout) { + throw new Error("Expected workspace layout"); + } + expect(layout.root.kind).toBe("group"); + expect(findPaneById(layout.root, "main")).toEqual( + expect.objectContaining({ focusedTabId: previousFocusedTabId }), ); expect(openedTabs[0]?.tabId).not.toBe(previousFocusedTabId); expect(browser.browser.activeWorkspaceBrowsers).toEqual([]); diff --git a/packages/app/src/screens/workspace/workspace-screen.tsx b/packages/app/src/screens/workspace/workspace-screen.tsx index a2b3c1395..231580776 100644 --- a/packages/app/src/screens/workspace/workspace-screen.tsx +++ b/packages/app/src/screens/workspace/workspace-screen.tsx @@ -1404,7 +1404,15 @@ function toggleWorkspaceExplorerPane(input: ToggleWorkspaceExplorerPaneInput): v store.hidePane(input.persistenceKey, explorerPane.id); return; } - if (explorerPane.tabIds.length === 0) { + // The companion pane can already hold an unrelated tab (the setup + // progress tab auto-opens here) before the user ever toggles it, so + // "empty" is the wrong signal for "needs a Changes tab seeded". Check + // for the working_diff tab specifically. + const layoutTabs = collectAllTabs(layout.root); + const hasWorkingDiffTab = explorerPane.tabIds.some( + (tabId) => layoutTabs.find((tab) => tab.tabId === tabId)?.target.kind === "working_diff", + ); + if (!hasWorkingDiffTab) { const tabId = parentTabId ? store.openChildTabFocused(input.persistenceKey, { kind: "working_diff" }, parentTabId) : store.openTabFocused(input.persistenceKey, { kind: "working_diff" });