diff --git a/packages/app/e2e/session/session-artifacts.spec.ts b/packages/app/e2e/session/session-artifacts.spec.ts index 74d138c7c..a389cf834 100644 --- a/packages/app/e2e/session/session-artifacts.spec.ts +++ b/packages/app/e2e/session/session-artifacts.spec.ts @@ -1,7 +1,8 @@ import { test, expect } from "../fixtures" +import { openRightPanel, waitSessionIdle } from "../actions" import { bodyText } from "../prompt/mock" -test("first added file auto-opens the Files tab and offers open actions", async ({ page, llm, project }) => { +test("added files stay quiet until the user opens the Files tab", async ({ page, llm, project }) => { const callsBefore = await llm.calls() await project.open() const session = await project.sdk.session.create({ title: "E2E artifacts" }).then((res) => { @@ -35,10 +36,28 @@ test("first added file auto-opens the Files tab and offers open actions", async }) await expect.poll(() => llm.calls().then((count) => count > callsBefore), { timeout: 30000 }).toBe(true) - await expect(page.getByRole("tab", { name: /files/i })).toHaveAttribute("aria-selected", "true") - await expect(page.locator('[data-artifact-file="artifact-report.md"]')).toBeVisible() + await waitSessionIdle(project.sdk, session.id) + await expect + .poll( + async () => { + const diff = await project.sdk.session.diff({ sessionID: session.id }).then((res) => res.data ?? []) + return diff.some((entry) => entry.file.endsWith("artifact-report.md") && entry.status === "added") + }, + { timeout: 30000 }, + ) + .toBe(true) + + const rightPanel = page.locator('[data-component="right-panel"]') + await expect(rightPanel).toHaveAttribute("aria-hidden", "true") + + const panel = await openRightPanel(page) + await panel.getByRole("button", { name: "Add tab" }).click() + await page.getByRole("menuitem", { name: "Files" }).click() + + const shellTabList = panel.getByRole("tablist").first() + const filesTab = shellTabList.getByRole("tab", { name: "Files", exact: true }) + await expect(filesTab).toHaveAttribute("aria-selected", "true") + await expect(page.locator('[data-artifact-file="artifact-report.md"]')).toBeVisible({ timeout: 30000 }) await expect(page.getByRole("button", { name: /open file/i })).toBeVisible() await expect(page.getByRole("button", { name: /open folder/i })).toBeVisible() - await page.getByRole("tab", { name: /changes/i }).click() - await expect(page.getByRole("tab", { name: /all/i })).toBeVisible() }) diff --git a/packages/app/src/context/layout.tsx b/packages/app/src/context/layout.tsx index cbd0fb1f5..d9ffebebb 100644 --- a/packages/app/src/context/layout.tsx +++ b/packages/app/src/context/layout.tsx @@ -63,8 +63,6 @@ type SessionView = { reviewOpen?: string[] openShellTabs?: RightPanelTab[] sidePanelTab?: RightPanelTab | "changes" - filesAutoOpenSeen?: boolean - filesAutoOpenDismissed?: boolean pendingMessage?: string pendingMessageAt?: number } @@ -935,11 +933,7 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( }, closeTab(tab: RightPanelTab) { if (tab === "status") return - const session = key() - if (tab === "files" && (s().filesAutoOpenSeen ?? false)) { - setStore("sessionView", session, "filesAutoOpenDismissed", true) - } - setShellTabState(session, closeShellTab(shellTabState(), tab)) + setShellTabState(key(), closeShellTab(shellTabState(), tab)) }, toggleTab(tab: RightPanelTab | "changes") { const target = defaultSidePanelTab(tab) @@ -955,21 +949,6 @@ export const { use: useLayout, provider: LayoutProvider } = createSimpleContext( if (tab === "status") return setShellTabState(key(), moveShellTab(shellTabState(), tab, to)) }, - filesAutoOpenSeen: createMemo(() => s().filesAutoOpenSeen ?? false), - filesAutoOpenDismissed: createMemo(() => s().filesAutoOpenDismissed ?? false), - setAutoOpenState(next: { seenAdded: boolean; dismissed: boolean }) { - const session = key() - if (!store.sessionView[session]) { - setStore("sessionView", session, { - scroll: {}, - filesAutoOpenSeen: next.seenAdded, - filesAutoOpenDismissed: next.dismissed, - }) - return - } - setStore("sessionView", session, "filesAutoOpenSeen", next.seenAdded) - setStore("sessionView", session, "filesAutoOpenDismissed", next.dismissed) - }, explorer: { tab: createMemo(() => store.fileTree?.tab ?? "changes"), setTab(tab: "changes" | "all") { diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx index 999b55a34..cde9270d3 100644 --- a/packages/app/src/pages/session.tsx +++ b/packages/app/src/pages/session.tsx @@ -344,6 +344,7 @@ export default function Page() { sdk, wantsReview, turnDiffs, + artifactDiffs: () => (timelineDiffs().length > 0 ? timelineDiffs() : turnDiffs()), }) const newSessionWorktree = createSessionNewWorktree({ @@ -403,8 +404,6 @@ export default function Page() { sdk, sessionKey: timelineSessionKey, sync, - timelineDiffs, - turnDiffs, view, wantsReview, openTab: tabs().open, diff --git a/packages/app/src/pages/session/files-tab-state.test.ts b/packages/app/src/pages/session/files-tab-state.test.ts index 3a3198d03..b9c80abc3 100644 --- a/packages/app/src/pages/session/files-tab-state.test.ts +++ b/packages/app/src/pages/session/files-tab-state.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test" -import { deriveArtifactFiles, nextFilesPanelAutoOpen } from "./files-tab-state" +import { deriveArtifactFiles } from "./files-tab-state" describe("files tab state", () => { test("maps cumulative artifact history into Files-tab entries", () => { @@ -13,18 +13,4 @@ describe("files tab state", () => { "/Users/yuhan/PawWork/notes.md", ]) }) - - test("auto-opens only on the first added diff and never after manual dismiss", () => { - expect(nextFilesPanelAutoOpen({ seenAdded: false, dismissed: false }, [{ status: "added" }] as any)).toEqual({ - open: true, - seenAdded: true, - dismissed: false, - }) - - expect(nextFilesPanelAutoOpen({ seenAdded: true, dismissed: true }, [{ status: "added" }] as any)).toEqual({ - open: false, - seenAdded: true, - dismissed: true, - }) - }) }) diff --git a/packages/app/src/pages/session/files-tab-state.ts b/packages/app/src/pages/session/files-tab-state.ts index 8f5db5adf..b1b270184 100644 --- a/packages/app/src/pages/session/files-tab-state.ts +++ b/packages/app/src/pages/session/files-tab-state.ts @@ -7,11 +7,6 @@ export type FilesTabEntry = SessionArtifactFile & { path: string } -export type FilesPanelAutoOpenState = { - seenAdded: boolean - dismissed: boolean -} - function isAbsolutePath(path: string) { return path.startsWith("/") || /^[A-Za-z]:[\\/]/.test(path) } @@ -24,30 +19,3 @@ export function deriveArtifactFiles(baseDir: string, artifacts: SessionArtifactF : `${baseDir.replace(/[\\/]+$/, "")}/${artifact.file.replace(/^[\\/]+/, "")}`, })) } - -export function nextFilesPanelAutoOpen( - state: FilesPanelAutoOpenState, - diffs: Array<{ status?: string | null }>, -): FilesPanelAutoOpenState & { open: boolean } { - const hasAdded = diffs.some((diff) => diff.status === "added") - if (!hasAdded) { - return { - ...state, - open: false, - } - } - - if (state.seenAdded || state.dismissed) { - return { - ...state, - seenAdded: true, - open: false, - } - } - - return { - seenAdded: true, - dismissed: false, - open: true, - } -} diff --git a/packages/app/src/pages/session/use-session-review-panel.test.tsx b/packages/app/src/pages/session/use-session-review-panel.test.tsx new file mode 100644 index 000000000..a9df246f6 --- /dev/null +++ b/packages/app/src/pages/session/use-session-review-panel.test.tsx @@ -0,0 +1,13 @@ +import { describe, expect, test } from "bun:test" + +describe("createSessionReviewPanel", () => { + test("does not keep the old Files panel auto-open path", async () => { + const source = await Bun.file(new URL("./use-session-review-panel.tsx", import.meta.url)).text() + + expect(source).not.toContain("nextFilesPanelAutoOpen") + expect(source).not.toContain('openTab("files")') + expect(source).not.toContain('setTab("files")') + expect(source).not.toContain('toggleTab("files")') + expect(source).not.toContain("sidePanel.open()") + }) +}) diff --git a/packages/app/src/pages/session/use-session-review-panel.tsx b/packages/app/src/pages/session/use-session-review-panel.tsx index 1059bf3c1..f29a7c2fa 100644 --- a/packages/app/src/pages/session/use-session-review-panel.tsx +++ b/packages/app/src/pages/session/use-session-review-panel.tsx @@ -4,7 +4,6 @@ import type { useFile } from "@/context/file" import type { useLanguage } from "@/context/language" import type { useSDK } from "@/context/sdk" import type { useSync } from "@/context/sync" -import { nextFilesPanelAutoOpen } from "@/pages/session/files-tab-state" import { createOpenReviewFile } from "@/pages/session/helpers" import { createReviewPanelScroll } from "@/pages/session/review-panel-scroll" import { createReviewPanelView } from "@/pages/session/review-panel-view" @@ -26,8 +25,6 @@ export function createSessionReviewPanel(input: { sdk: ReturnType sessionKey: () => string sync: ReturnType - timelineDiffs: () => Array<{ status?: string | null }> - turnDiffs: () => Array<{ status?: string | null }> view: ReturnType["view"] wantsReview: () => boolean openTab: (tab: string) => void @@ -36,25 +33,6 @@ export function createSessionReviewPanel(input: { let diffFrame: number | undefined let diffTimer: number | undefined - createEffect(() => { - if (!input.routeSessionID()) return - - const source = input.timelineDiffs().length > 0 ? input.timelineDiffs() : input.turnDiffs() - const next = nextFilesPanelAutoOpen( - { - seenAdded: input.view().sidePanel.filesAutoOpenSeen(), - dismissed: input.view().sidePanel.filesAutoOpenDismissed(), - }, - source, - ) - - if (next.open) { - input.view().sidePanel.setTab("files") - input.view().sidePanel.open() - } - input.view().sidePanel.setAutoOpenState(next) - }) - createEffect( on( () => input.sync.data.session_status[input.routeSessionID() ?? ""]?.type, diff --git a/packages/app/src/pages/session/use-session-review-state.ts b/packages/app/src/pages/session/use-session-review-state.ts index 9068e3aca..cd68be2e7 100644 --- a/packages/app/src/pages/session/use-session-review-state.ts +++ b/packages/app/src/pages/session/use-session-review-state.ts @@ -53,6 +53,7 @@ export function createSessionReviewState(input: { sdk: ReturnType wantsReview: () => boolean turnDiffs: () => SessionReviewDiff[] + artifactDiffs?: () => SessionReviewDiff[] }) { const [changes, setChanges] = createSignal("turn") const [vcs, setVcs] = createStore<{ @@ -214,7 +215,7 @@ export function createSessionReviewState(input: { currentScope: input.executionScope(), sessionID: input.sessionID(), history: artifactHistory.latest, - turnDiffs: input.turnDiffs(), + turnDiffs: input.artifactDiffs?.() ?? input.turnDiffs(), }), ) @@ -245,7 +246,7 @@ export function createSessionReviewState(input: { createEffect(() => { const id = input.sessionID() if (!id) return - input.turnDiffs() + input.artifactDiffs?.() ?? input.turnDiffs() queueArtifactHistoryRefetch() })