diff --git a/ui/src/e2e/chat-sidebar-panel-contract.e2e.test.ts b/ui/src/e2e/chat-sidebar-panel-contract.e2e.test.ts index 7a019e996fec..14c92f064472 100644 --- a/ui/src/e2e/chat-sidebar-panel-contract.e2e.test.ts +++ b/ui/src/e2e/chat-sidebar-panel-contract.e2e.test.ts @@ -3,6 +3,7 @@ import type { Page } from "playwright"; import { expect, it } from "vitest"; import { waitForControlUiGatewayReady } from "../test-helpers/control-ui-e2e-readiness.ts"; import { + controlUiBundledSettingsStorageKey, installMockGateway, type ControlUiMockGatewayScenario, } from "../test-helpers/control-ui-e2e.ts"; @@ -13,6 +14,8 @@ const suite = createControlUiE2eSuite({ startServerBeforeBrowser: true, }); +const HIDDEN_BOARD_SESSION_KEY = "agent:main:hidden-board-slot"; + const ONE_PIXEL_PNG = Buffer.from( "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAusB9Wl2nPcAAAAASUVORK5CYII=", "base64", @@ -232,6 +235,38 @@ async function openColdSidebar(page: Page, scenario = coldOpenScenario()) { return choices; } +async function seedHiddenBoardSlot(page: Page) { + const settingsKey = controlUiBundledSettingsStorageKey(suite.server.baseUrl); + await page.addInitScript( + ({ key, sessionKey }) => { + localStorage.setItem( + key, + JSON.stringify({ + sessionKey, + sidebarSessionLayouts: { + [sessionKey]: { + columns: [ + { + id: "side-panel-column", + side: "right", + panels: [{ id: "chat", slot: "chat" }], + activePanelId: "chat", + height: 360, + width: 480, + }, + ], + dock: "right", + open: true, + expanded: false, + }, + }, + }), + ); + }, + { key: settingsKey, sessionKey: HIDDEN_BOARD_SESSION_KEY }, + ); +} + async function readColdOpenOutcome(page: Page): Promise { const activePanel = page.locator(".side-panel__panel:not([hidden])"); await activePanel.waitFor(); @@ -280,6 +315,29 @@ async function readSlotColdOpenOutcome( } suite.define(() => { + it("closes a projected-empty side panel when a hidden board tab remains persisted", async () => { + const context = await suite.newBrowserContext({ serviceWorkers: "block" }); + try { + const page = await context.newPage(); + await seedHiddenBoardSlot(page); + await installMockGateway(page, { + ...coldOpenScenario(), + sessionKey: HIDDEN_BOARD_SESSION_KEY, + }); + await page.goto(`${suite.server.baseUrl}chat`); + await waitForControlUiGatewayReady(page); + + const panel = page.locator(".sidebar-region__right-runtime .side-panel"); + await panel.locator(".side-panel-empty--selector").waitFor(); + expect(await panel.locator("wa-tab").count()).toBe(0); + + await panel.getByRole("button", { name: "Close", exact: true }).click(); + await expect.poll(() => panel.count()).toBe(0); + } finally { + await suite.closeBrowserContext(context); + } + }); + it("preserves the production header-action shapes for Side chat and Discussion", async () => { const context = await suite.newBrowserContext({ serviceWorkers: "block" }); const page = await context.newPage(); diff --git a/ui/src/pages/chat/sidebar-layout.ts b/ui/src/pages/chat/sidebar-layout.ts index d3af78623f69..222562fa069f 100644 --- a/ui/src/pages/chat/sidebar-layout.ts +++ b/ui/src/pages/chat/sidebar-layout.ts @@ -121,7 +121,6 @@ export function closeSlot(layout: SidebarLayout, slot: SidebarSlotId): SidebarLa .find((entry) => entry.slot === slot); if (panel) { removePanel(next, panel.id); - next.open = true; } return next; }