diff --git a/packages/app/e2e/regression/session-message-revert.spec.ts b/packages/app/e2e/regression/session-message-revert.spec.ts index ab5829529f9..60e0f472a59 100644 --- a/packages/app/e2e/regression/session-message-revert.spec.ts +++ b/packages/app/e2e/regression/session-message-revert.spec.ts @@ -20,45 +20,47 @@ const messages = [ }, { id: "msg_second", type: "user", text: "Second prompt", time: { created: 4 } }, ] satisfies SessionMessageInfo[] +const session = { + id: sessionID, + slug: "session-message-revert", + projectID, + directory, + title: "Session message revert", + agent: "build", + model: { id: "test", providerID: "opencode" }, + version: "dev", + time: { created: 1, updated: 4 }, +} +const fixture = { + directory, + project: { + id: projectID, + worktree: directory, + canonical: directory, + vcs: "git", + name: "session-message-revert", + time: { created: 1, updated: 1 }, + sandboxes: [], + }, + provider: { + all: [ + { + id: "opencode", + name: "OpenCode", + models: { test: { id: "test", name: "Test", variants: {}, limit: { context: 200_000 } } }, + }, + ], + connected: ["opencode"], + default: { providerID: "opencode", modelID: "test" }, + }, + pageMessages: () => ({ items: messages }), +} test("reverts directly to the selected user message", async ({ page }) => { const staged: { sessionID: string; messageID: string }[] = [] await mockOpenCodeServer(page, { - directory, - project: { - id: projectID, - worktree: directory, - canonical: directory, - vcs: "git", - name: "session-message-revert", - time: { created: 1, updated: 1 }, - sandboxes: [], - }, - provider: { - all: [ - { - id: "opencode", - name: "OpenCode", - models: { test: { id: "test", name: "Test", variants: {}, limit: { context: 200_000 } } }, - }, - ], - connected: ["opencode"], - default: { providerID: "opencode", modelID: "test" }, - }, - sessions: [ - { - id: sessionID, - slug: "session-message-revert", - projectID, - directory, - title: "Session message revert", - agent: "build", - model: { id: "test", providerID: "opencode" }, - version: "dev", - time: { created: 1, updated: 4 }, - }, - ], - pageMessages: () => ({ items: messages }), + ...fixture, + sessions: [session], onRevertStage: (input) => staged.push(input), }) await page.goto(`/server/${base64Encode(server)}/session/${sessionID}`) @@ -77,3 +79,19 @@ test("reverts directly to the selected user message", async ({ page }) => { await expect(page.getByRole("textbox", { name: "Prompt" })).toHaveText("Second prompt") expect(staged).toEqual([{ sessionID, messageID: "msg_second" }]) }) + +test("hides revert actions in a child session", async ({ page }) => { + await mockOpenCodeServer(page, { + ...fixture, + sessions: [ + { ...session, id: "ses_parent", slug: "parent", title: "Parent session" }, + { ...session, parentID: "ses_parent" }, + ], + }) + await page.goto(`/server/${base64Encode(server)}/session/${sessionID}`) + await expectSessionTitle(page, "Session message revert") + + const message = page.locator('[data-message-id="msg_second"]') + await message.hover() + await expect(message.getByRole("button", { name: "Revert message" })).toHaveCount(0) +}) diff --git a/packages/app/src/session/composer/region.tsx b/packages/app/src/session/composer/region.tsx index 794bba7454f..e25b8a213ca 100644 --- a/packages/app/src/session/composer/region.tsx +++ b/packages/app/src/session/composer/region.tsx @@ -156,6 +156,7 @@ export function createActiveSessionRegion(input: { session: input.session, setActiveMessage: input.timeline.actions.setActiveMessage, }) + const revertMessage: NonNullable = ({ messageID }) => revert.to(messageID) useComposerCommands() useSessionCommands({ session: input.session, @@ -178,7 +179,13 @@ export function createActiveSessionRegion(input: { return { actions: { - timeline: { revert: ({ messageID }) => revert.to(messageID), openAttachment } satisfies SessionUserActions, + timeline: { + get revert() { + if (input.session.data.isChild()) return + return revertMessage + }, + openAttachment, + } satisfies SessionUserActions, }, region: { centered: input.screen.centered,