import { scopeThreadRef } from "@t3tools/client-runtime/environment";import { type EnvironmentId, ThreadId } from "@t3tools/contracts";import { beforeEach, describe, expect, it } from "vite-plus/test"; import { migratePersistedRightPanelState, pullRequestSurfaceId, selectActiveRightPanel, selectActiveRightPanelSurface, selectSelectedRightPanelSurface, selectThreadPanelOpen, selectThreadPanelVisibility, selectThreadRightPanelState, useRightPanelStore,} from "./rightPanelStore"; const refA = scopeThreadRef("env-1" as EnvironmentId, ThreadId.make("thread-A"));const refB = scopeThreadRef("env-1" as EnvironmentId, ThreadId.make("thread-B")); beforeEach(() => { useRightPanelStore.setState({ byThreadKey: {}, threadPanelVisibilityByThreadKey: {} });}); describe("rightPanelStore", () => { it("drops the legacy singleton terminal surface during migration", () => { expect( migratePersistedRightPanelState({ byThreadKey: { "env-1:thread-A": { activeSurfaceId: "terminal", surfaces: [ { id: "browser:tab-a", kind: "preview", resourceId: "tab-a" }, { id: "terminal", kind: "terminal" }, ], }, }, }), ).toEqual({ byThreadKey: { "env-1:thread-A": { isOpen: false, activeSurfaceId: null, surfaces: [{ id: "browser:tab-a", kind: "preview", resourceId: "tab-a" }], }, }, threadPanelVisibilityByThreadKey: {}, }); }); it("upgrades saved single-session terminal surfaces to split-capable surfaces", () => { expect( migratePersistedRightPanelState({ byThreadKey: { "env-1:thread-A": { isOpen: true, activeSurfaceId: "terminal:term-1", surfaces: [{ id: "terminal:term-1", kind: "terminal", resourceId: "term-1" }], }, }, }), ).toEqual({ byThreadKey: { "env-1:thread-A": { isOpen: true, activeSurfaceId: "terminal:term-1", surfaces: [ { id: "terminal:term-1", kind: "terminal", resourceId: "term-1", terminalIds: ["term-1"], activeTerminalId: "term-1", }, ], }, }, threadPanelVisibilityByThreadKey: {}, }); }); it("upgrades saved file surfaces with neutral reveal state", () => { expect( migratePersistedRightPanelState({ byThreadKey: { "env-1:thread-A": { isOpen: true, activeSurfaceId: "file:src/index.ts", surfaces: [{ id: "file:src/index.ts", kind: "file", relativePath: "src/index.ts" }], }, }, }), ).toEqual({ byThreadKey: { "env-1:thread-A": { isOpen: true, activeSurfaceId: "file:src/index.ts", surfaces: [ { id: "file:src/index.ts", kind: "file", relativePath: "src/index.ts", revealLine: null, revealRequestId: 0, }, ], }, }, threadPanelVisibilityByThreadKey: {}, }); }); it("upgrades the legacy singleton pull request surface to a reference-keyed tab", () => { const id = pullRequestSurfaceId({ projectId: "project-a", repository: "pingdotgg/t3code", number: 4909, }); expect( migratePersistedRightPanelState({ byThreadKey: { "env-1:thread-A": { isOpen: true, activeSurfaceId: "pull-request", surfaces: [ { id: "pull-request", kind: "pull-request", projectId: "project-a", repository: "pingdotgg/t3code", number: 4909, }, ], }, }, }), ).toEqual({ byThreadKey: { "env-1:thread-A": { isOpen: true, activeSurfaceId: id, surfaces: [ { id, kind: "pull-request", projectId: "project-a", repository: "pingdotgg/t3code", number: 4909, }, ], }, }, threadPanelVisibilityByThreadKey: {}, }); }); it("drops the pull-request list's shared panel so a restart opens the page fresh", () => { const id = pullRequestSurfaceId({ projectId: "project-a", repository: "pingdotgg/t3code", number: 4909, }); const panelState = { isOpen: true, activeSurfaceId: id, surfaces: [ { id, kind: "pull-request" as const, projectId: "project-a", repository: "pingdotgg/t3code", number: 4909, }, ], }; expect( migratePersistedRightPanelState({ byThreadKey: { "env-1:pull-requests-panel": panelState, "env-1:thread-A": panelState, }, }), ).toEqual({ byThreadKey: { "env-1:thread-A": panelState }, threadPanelVisibilityByThreadKey: {}, }); }); it("drops persisted plan surfaces and does not reopen an empty panel", () => { expect( migratePersistedRightPanelState({ byThreadKey: { "env-1:thread-A": { isOpen: true, activeSurfaceId: "plan", surfaces: [{ id: "plan", kind: "plan" }], }, "env-1:thread-B": { isOpen: true, activeSurfaceId: "plan", surfaces: [ { id: "plan", kind: "plan" }, { id: "diff", kind: "diff" }, ], }, }, }), ).toEqual({ byThreadKey: { "env-1:thread-A": { isOpen: false, activeSurfaceId: null, surfaces: [], }, "env-1:thread-B": { isOpen: true, activeSurfaceId: "diff", surfaces: [{ id: "diff", kind: "diff" }], }, }, threadPanelVisibilityByThreadKey: {}, }); }); it("persists inline preference without restoring an open popover", () => { expect( migratePersistedRightPanelState({ threadPanelVisibilityByThreadKey: { "env-1:thread-A": { inlineOpen: false, popoverOpen: true }, "env-1:thread-B": { inlineOpen: true, popoverOpen: true }, }, }), ).toEqual({ byThreadKey: {}, threadPanelVisibilityByThreadKey: { "env-1:thread-A": { inlineOpen: false, popoverOpen: false }, }, }); }); it("tracks inline and popover visibility independently", () => { const store = useRightPanelStore.getState(); expect(selectThreadPanelOpen(store.threadPanelVisibilityByThreadKey, refA, "inline")).toBe( true, ); expect(selectThreadPanelOpen(store.threadPanelVisibilityByThreadKey, refA, "popover")).toBe( false, ); store.setThreadPanelOpen(refA, "inline", false); store.toggleThreadPanel(refA, "popover"); expect( selectThreadPanelVisibility( useRightPanelStore.getState().threadPanelVisibilityByThreadKey, refA, ), ).toEqual({ inlineOpen: false, popoverOpen: true }); expect( selectThreadPanelVisibility( useRightPanelStore.getState().threadPanelVisibilityByThreadKey, refB, ), ).toEqual({ inlineOpen: true, popoverOpen: false }); }); it("closes the popover atomically when the real right panel opens", () => { useRightPanelStore.getState().setThreadPanelOpen(refA, "popover", true); useRightPanelStore.getState().open(refA, "diff"); expect( selectThreadPanelVisibility( useRightPanelStore.getState().threadPanelVisibilityByThreadKey, refA, ), ).toEqual({ inlineOpen: true, popoverOpen: false }); }); it("keeps an open popover visible by promoting it to inline when the real panel closes", () => { const store = useRightPanelStore.getState(); store.open(refA, "diff"); store.setThreadPanelOpen(refA, "inline", false); store.setThreadPanelOpen(refA, "popover", true); store.close(refA); expect( selectThreadPanelVisibility( useRightPanelStore.getState().threadPanelVisibilityByThreadKey, refA, ), ).toEqual({ inlineOpen: true, popoverOpen: true }); }); it("open sets the active panel for a thread", () => { useRightPanelStore.getState().open(refA, "preview"); expect(selectActiveRightPanel(useRightPanelStore.getState().byThreadKey, refA)).toBe("preview"); expect(selectActiveRightPanel(useRightPanelStore.getState().byThreadKey, refB)).toBeNull(); }); it("opening a different kind keeps both surfaces and activates the new one", () => { useRightPanelStore.getState().open(refA, "agents"); useRightPanelStore.getState().open(refA, "preview"); expect(selectActiveRightPanel(useRightPanelStore.getState().byThreadKey, refA)).toBe("preview"); expect( selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA).surfaces, ).toHaveLength(2); }); it("reopening an inactive singleton activates its existing surface", () => { useRightPanelStore.getState().open(refA, "diff"); useRightPanelStore.getState().open(refA, "agents"); useRightPanelStore.getState().open(refA, "diff"); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: true, activeSurfaceId: "diff", surfaces: [ { id: "diff", kind: "diff" }, { id: "agents", kind: "agents" }, ], }); }); it("keeps files as a singleton surface", () => { useRightPanelStore.getState().open(refA, "files"); useRightPanelStore.getState().open(refA, "files"); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: true, activeSurfaceId: "files", surfaces: [{ id: "files", kind: "files" }], }); }); it("replaces the standalone explorer with peer file surfaces", () => { useRightPanelStore.getState().open(refA, "files"); useRightPanelStore.getState().openFile(refA, "src/index.ts"); useRightPanelStore.getState().openFile(refA, "src/index.ts"); useRightPanelStore.getState().openFile(refA, "README.md"); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: true, activeSurfaceId: "file:README.md", surfaces: [ { id: "file:src/index.ts", kind: "file", relativePath: "src/index.ts", revealLine: null, revealRequestId: 2, }, { id: "file:README.md", kind: "file", relativePath: "README.md", revealLine: null, revealRequestId: 1, }, ], }); }); it("opens an attachment as a file surface without the standalone explorer", () => { const attachment = { type: "file" as const, id: "thread-A-attachment-pdf", name: "report.pdf", mimeType: "application/pdf", sizeBytes: 42, }; useRightPanelStore.getState().open(refA, "files"); useRightPanelStore.getState().openAttachment(refA, attachment); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: true, activeSurfaceId: "attachment:thread-A-attachment-pdf", surfaces: [ { id: "attachment:thread-A-attachment-pdf", kind: "file", relativePath: "report.pdf", revealLine: null, revealRequestId: 0, attachment, }, ], }); }); it("keeps attachment and workspace file ids disjoint", () => { useRightPanelStore.getState().openFile(refA, "attachment:shared-id"); useRightPanelStore.getState().openAttachment(refA, { type: "file", id: "shared-id", name: "report.pdf", mimeType: "application/pdf", sizeBytes: 42, }); expect( selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA).surfaces.map( (surface) => surface.id, ), ).toEqual(["file:attachment:shared-id", "attachment:shared-id"]); }); it("updates line reveal requests when reopening a file surface", () => { useRightPanelStore.getState().openFile(refA, "src/index.ts", 42); useRightPanelStore.getState().openFile(refA, "src/index.ts", 87); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: true, activeSurfaceId: "file:src/index.ts", surfaces: [ { id: "file:src/index.ts", kind: "file", relativePath: "src/index.ts", revealLine: 87, revealRequestId: 2, }, ], }); useRightPanelStore.getState().openFile(refA, "src/index.ts"); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: true, activeSurfaceId: "file:src/index.ts", surfaces: [ { id: "file:src/index.ts", kind: "file", relativePath: "src/index.ts", revealLine: null, revealRequestId: 3, }, ], }); }); it("removes persisted file surfaces when their workspace no longer exists", () => { useRightPanelStore.getState().openFile(refA, "src/index.ts"); useRightPanelStore.getState().open(refA, "agents"); useRightPanelStore.getState().openFile(refA, "README.md"); useRightPanelStore.getState().reconcileFileSurfaces(refA, false); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: true, activeSurfaceId: "agents", surfaces: [{ id: "agents", kind: "agents" }], }); useRightPanelStore.getState().openFile(refB, "conductor.json"); useRightPanelStore.getState().reconcileFileSurfaces(refB, false); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refB)).toEqual({ isOpen: false, activeSurfaceId: null, surfaces: [], }); }); it("keeps attachment previews when their workspace is unavailable", () => { const attachment = { type: "file" as const, id: "thread-A-attachment-pdf", name: "report.pdf", mimeType: "application/pdf", sizeBytes: 42, }; useRightPanelStore.getState().openFile(refA, "README.md"); useRightPanelStore.getState().openAttachment(refA, attachment); useRightPanelStore.getState().reconcileFileSurfaces(refA, false); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: true, activeSurfaceId: "attachment:thread-A-attachment-pdf", surfaces: [ { id: "attachment:thread-A-attachment-pdf", kind: "file", relativePath: "report.pdf", revealLine: null, revealRequestId: 0, attachment, }, ], }); }); it("close hides the panel without clearing its selected surface", () => { useRightPanelStore.getState().open(refA, "agents"); useRightPanelStore.getState().close(refA); expect(selectActiveRightPanel(useRightPanelStore.getState().byThreadKey, refA)).toBeNull(); expect( selectSelectedRightPanelSurface(useRightPanelStore.getState().byThreadKey, refA), ).toEqual({ id: "agents", kind: "agents" }); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: false,Lines 1–500 of 794. Load more
import { scopeThreadRef } from "@t3tools/client-runtime/environment"; import { type EnvironmentId, ThreadId } from "@t3tools/contracts"; import { beforeEach, describe, expect, it } from "vite-plus/test"; import { migratePersistedRightPanelState, pullRequestSurfaceId, selectActiveRightPanel, selectActiveRightPanelSurface, selectSelectedRightPanelSurface, selectThreadPanelOpen, selectThreadPanelVisibility, selectThreadRightPanelState, useRightPanelStore, } from "./rightPanelStore"; const refA = scopeThreadRef("env-1" as EnvironmentId, ThreadId.make("thread-A")); const refB = scopeThreadRef("env-1" as EnvironmentId, ThreadId.make("thread-B")); beforeEach(() => { useRightPanelStore.setState({ byThreadKey: {}, threadPanelVisibilityByThreadKey: {} }); }); describe("rightPanelStore", () => { it("drops the legacy singleton terminal surface during migration", () => { expect( migratePersistedRightPanelState({ byThreadKey: { "env-1:thread-A": { activeSurfaceId: "terminal", surfaces: [ { id: "browser:tab-a", kind: "preview", resourceId: "tab-a" }, { id: "terminal", kind: "terminal" }, ], }, }, }), ).toEqual({ byThreadKey: { "env-1:thread-A": { isOpen: false, activeSurfaceId: null, surfaces: [{ id: "browser:tab-a", kind: "preview", resourceId: "tab-a" }], }, }, threadPanelVisibilityByThreadKey: {}, }); }); it("upgrades saved single-session terminal surfaces to split-capable surfaces", () => { expect( migratePersistedRightPanelState({ byThreadKey: { "env-1:thread-A": { isOpen: true, activeSurfaceId: "terminal:term-1", surfaces: [{ id: "terminal:term-1", kind: "terminal", resourceId: "term-1" }], }, }, }), ).toEqual({ byThreadKey: { "env-1:thread-A": { isOpen: true, activeSurfaceId: "terminal:term-1", surfaces: [ { id: "terminal:term-1", kind: "terminal", resourceId: "term-1", terminalIds: ["term-1"], activeTerminalId: "term-1", }, ], }, }, threadPanelVisibilityByThreadKey: {}, }); }); it("upgrades saved file surfaces with neutral reveal state", () => { expect( migratePersistedRightPanelState({ byThreadKey: { "env-1:thread-A": { isOpen: true, activeSurfaceId: "file:src/index.ts", surfaces: [{ id: "file:src/index.ts", kind: "file", relativePath: "src/index.ts" }], }, }, }), ).toEqual({ byThreadKey: { "env-1:thread-A": { isOpen: true, activeSurfaceId: "file:src/index.ts", surfaces: [ { id: "file:src/index.ts", kind: "file", relativePath: "src/index.ts", revealLine: null, revealRequestId: 0, }, ], }, }, threadPanelVisibilityByThreadKey: {}, }); }); it("upgrades the legacy singleton pull request surface to a reference-keyed tab", () => { const id = pullRequestSurfaceId({ projectId: "project-a", repository: "pingdotgg/t3code", number: 4909, }); expect( migratePersistedRightPanelState({ byThreadKey: { "env-1:thread-A": { isOpen: true, activeSurfaceId: "pull-request", surfaces: [ { id: "pull-request", kind: "pull-request", projectId: "project-a", repository: "pingdotgg/t3code", number: 4909, }, ], }, }, }), ).toEqual({ byThreadKey: { "env-1:thread-A": { isOpen: true, activeSurfaceId: id, surfaces: [ { id, kind: "pull-request", projectId: "project-a", repository: "pingdotgg/t3code", number: 4909, }, ], }, }, threadPanelVisibilityByThreadKey: {}, }); }); it("drops the pull-request list's shared panel so a restart opens the page fresh", () => { const id = pullRequestSurfaceId({ projectId: "project-a", repository: "pingdotgg/t3code", number: 4909, }); const panelState = { isOpen: true, activeSurfaceId: id, surfaces: [ { id, kind: "pull-request" as const, projectId: "project-a", repository: "pingdotgg/t3code", number: 4909, }, ], }; expect( migratePersistedRightPanelState({ byThreadKey: { "env-1:pull-requests-panel": panelState, "env-1:thread-A": panelState, }, }), ).toEqual({ byThreadKey: { "env-1:thread-A": panelState }, threadPanelVisibilityByThreadKey: {}, }); }); it("drops persisted plan surfaces and does not reopen an empty panel", () => { expect( migratePersistedRightPanelState({ byThreadKey: { "env-1:thread-A": { isOpen: true, activeSurfaceId: "plan", surfaces: [{ id: "plan", kind: "plan" }], }, "env-1:thread-B": { isOpen: true, activeSurfaceId: "plan", surfaces: [ { id: "plan", kind: "plan" }, { id: "diff", kind: "diff" }, ], }, }, }), ).toEqual({ byThreadKey: { "env-1:thread-A": { isOpen: false, activeSurfaceId: null, surfaces: [], }, "env-1:thread-B": { isOpen: true, activeSurfaceId: "diff", surfaces: [{ id: "diff", kind: "diff" }], }, }, threadPanelVisibilityByThreadKey: {}, }); }); it("persists inline preference without restoring an open popover", () => { expect( migratePersistedRightPanelState({ threadPanelVisibilityByThreadKey: { "env-1:thread-A": { inlineOpen: false, popoverOpen: true }, "env-1:thread-B": { inlineOpen: true, popoverOpen: true }, }, }), ).toEqual({ byThreadKey: {}, threadPanelVisibilityByThreadKey: { "env-1:thread-A": { inlineOpen: false, popoverOpen: false }, }, }); }); it("tracks inline and popover visibility independently", () => { const store = useRightPanelStore.getState(); expect(selectThreadPanelOpen(store.threadPanelVisibilityByThreadKey, refA, "inline")).toBe( true, ); expect(selectThreadPanelOpen(store.threadPanelVisibilityByThreadKey, refA, "popover")).toBe( false, ); store.setThreadPanelOpen(refA, "inline", false); store.toggleThreadPanel(refA, "popover"); expect( selectThreadPanelVisibility( useRightPanelStore.getState().threadPanelVisibilityByThreadKey, refA, ), ).toEqual({ inlineOpen: false, popoverOpen: true }); expect( selectThreadPanelVisibility( useRightPanelStore.getState().threadPanelVisibilityByThreadKey, refB, ), ).toEqual({ inlineOpen: true, popoverOpen: false }); }); it("closes the popover atomically when the real right panel opens", () => { useRightPanelStore.getState().setThreadPanelOpen(refA, "popover", true); useRightPanelStore.getState().open(refA, "diff"); expect( selectThreadPanelVisibility( useRightPanelStore.getState().threadPanelVisibilityByThreadKey, refA, ), ).toEqual({ inlineOpen: true, popoverOpen: false }); }); it("keeps an open popover visible by promoting it to inline when the real panel closes", () => { const store = useRightPanelStore.getState(); store.open(refA, "diff"); store.setThreadPanelOpen(refA, "inline", false); store.setThreadPanelOpen(refA, "popover", true); store.close(refA); expect( selectThreadPanelVisibility( useRightPanelStore.getState().threadPanelVisibilityByThreadKey, refA, ), ).toEqual({ inlineOpen: true, popoverOpen: true }); }); it("open sets the active panel for a thread", () => { useRightPanelStore.getState().open(refA, "preview"); expect(selectActiveRightPanel(useRightPanelStore.getState().byThreadKey, refA)).toBe("preview"); expect(selectActiveRightPanel(useRightPanelStore.getState().byThreadKey, refB)).toBeNull(); }); it("opening a different kind keeps both surfaces and activates the new one", () => { useRightPanelStore.getState().open(refA, "agents"); useRightPanelStore.getState().open(refA, "preview"); expect(selectActiveRightPanel(useRightPanelStore.getState().byThreadKey, refA)).toBe("preview"); expect( selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA).surfaces, ).toHaveLength(2); }); it("reopening an inactive singleton activates its existing surface", () => { useRightPanelStore.getState().open(refA, "diff"); useRightPanelStore.getState().open(refA, "agents"); useRightPanelStore.getState().open(refA, "diff"); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: true, activeSurfaceId: "diff", surfaces: [ { id: "diff", kind: "diff" }, { id: "agents", kind: "agents" }, ], }); }); it("keeps files as a singleton surface", () => { useRightPanelStore.getState().open(refA, "files"); useRightPanelStore.getState().open(refA, "files"); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: true, activeSurfaceId: "files", surfaces: [{ id: "files", kind: "files" }], }); }); it("replaces the standalone explorer with peer file surfaces", () => { useRightPanelStore.getState().open(refA, "files"); useRightPanelStore.getState().openFile(refA, "src/index.ts"); useRightPanelStore.getState().openFile(refA, "src/index.ts"); useRightPanelStore.getState().openFile(refA, "README.md"); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: true, activeSurfaceId: "file:README.md", surfaces: [ { id: "file:src/index.ts", kind: "file", relativePath: "src/index.ts", revealLine: null, revealRequestId: 2, }, { id: "file:README.md", kind: "file", relativePath: "README.md", revealLine: null, revealRequestId: 1, }, ], }); }); it("opens an attachment as a file surface without the standalone explorer", () => { const attachment = { type: "file" as const, id: "thread-A-attachment-pdf", name: "report.pdf", mimeType: "application/pdf", sizeBytes: 42, }; useRightPanelStore.getState().open(refA, "files"); useRightPanelStore.getState().openAttachment(refA, attachment); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: true, activeSurfaceId: "attachment:thread-A-attachment-pdf", surfaces: [ { id: "attachment:thread-A-attachment-pdf", kind: "file", relativePath: "report.pdf", revealLine: null, revealRequestId: 0, attachment, }, ], }); }); it("keeps attachment and workspace file ids disjoint", () => { useRightPanelStore.getState().openFile(refA, "attachment:shared-id"); useRightPanelStore.getState().openAttachment(refA, { type: "file", id: "shared-id", name: "report.pdf", mimeType: "application/pdf", sizeBytes: 42, }); expect( selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA).surfaces.map( (surface) => surface.id, ), ).toEqual(["file:attachment:shared-id", "attachment:shared-id"]); }); it("updates line reveal requests when reopening a file surface", () => { useRightPanelStore.getState().openFile(refA, "src/index.ts", 42); useRightPanelStore.getState().openFile(refA, "src/index.ts", 87); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: true, activeSurfaceId: "file:src/index.ts", surfaces: [ { id: "file:src/index.ts", kind: "file", relativePath: "src/index.ts", revealLine: 87, revealRequestId: 2, }, ], }); useRightPanelStore.getState().openFile(refA, "src/index.ts"); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: true, activeSurfaceId: "file:src/index.ts", surfaces: [ { id: "file:src/index.ts", kind: "file", relativePath: "src/index.ts", revealLine: null, revealRequestId: 3, }, ], }); }); it("removes persisted file surfaces when their workspace no longer exists", () => { useRightPanelStore.getState().openFile(refA, "src/index.ts"); useRightPanelStore.getState().open(refA, "agents"); useRightPanelStore.getState().openFile(refA, "README.md"); useRightPanelStore.getState().reconcileFileSurfaces(refA, false); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: true, activeSurfaceId: "agents", surfaces: [{ id: "agents", kind: "agents" }], }); useRightPanelStore.getState().openFile(refB, "conductor.json"); useRightPanelStore.getState().reconcileFileSurfaces(refB, false); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refB)).toEqual({ isOpen: false, activeSurfaceId: null, surfaces: [], }); }); it("keeps attachment previews when their workspace is unavailable", () => { const attachment = { type: "file" as const, id: "thread-A-attachment-pdf", name: "report.pdf", mimeType: "application/pdf", sizeBytes: 42, }; useRightPanelStore.getState().openFile(refA, "README.md"); useRightPanelStore.getState().openAttachment(refA, attachment); useRightPanelStore.getState().reconcileFileSurfaces(refA, false); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: true, activeSurfaceId: "attachment:thread-A-attachment-pdf", surfaces: [ { id: "attachment:thread-A-attachment-pdf", kind: "file", relativePath: "report.pdf", revealLine: null, revealRequestId: 0, attachment, }, ], }); }); it("close hides the panel without clearing its selected surface", () => { useRightPanelStore.getState().open(refA, "agents"); useRightPanelStore.getState().close(refA); expect(selectActiveRightPanel(useRightPanelStore.getState().byThreadKey, refA)).toBeNull(); expect( selectSelectedRightPanelSurface(useRightPanelStore.getState().byThreadKey, refA), ).toEqual({ id: "agents", kind: "agents" }); expect(selectThreadRightPanelState(useRightPanelStore.getState().byThreadKey, refA)).toEqual({ isOpen: false,