diff --git a/packages/app/e2e/regression/prompt-input-v2-command-draft.spec.ts b/packages/app/e2e/regression/prompt-input-v2-command-draft.spec.ts new file mode 100644 index 0000000000..50dcc8820b --- /dev/null +++ b/packages/app/e2e/regression/prompt-input-v2-command-draft.spec.ts @@ -0,0 +1,50 @@ +import { expect, test } from "@playwright/test" +import { base64Encode } from "@opencode-ai/core/util/encode" +import { mockOpenCodeServer } from "../utils/mock-server" +import { expectAppVisible } from "../utils/waits" + +const directory = "C:/OpenCode/PromptInputV2Editing" +const projectID = "proj_prompt_input_v2_editing" +const sessionID = "ses_prompt_input_v2_editing" + +test("preserves the draft when a populated command menu triggers a built-in", async ({ page }) => { + await mockOpenCodeServer(page, { + directory, + project: { + id: projectID, + worktree: directory, + vcs: "git", + name: "prompt-input-v2-editing", + time: { created: 1700000000000, updated: 1700000000000 }, + sandboxes: [], + }, + provider: { all: [], connected: [], default: {} }, + sessions: [ + { + id: sessionID, + slug: "prompt-input-v2-editing", + projectID, + directory, + title: "Prompt input V2 editing", + version: "dev", + time: { created: 1700000000000, updated: 1700000000000 }, + }, + ], + pageMessages: () => ({ items: [] }), + }) + await page.addInitScript(() => { + localStorage.setItem("settings.v3", JSON.stringify({ general: { newLayoutDesigns: true } })) + }) + + await page.goto(`/${base64Encode(directory)}/session/${sessionID}`) + const composer = page.locator('[data-component="prompt-input-v2"]') + const input = composer.locator('[data-component="prompt-input"]') + await expectAppVisible(composer) + + await input.fill("keep me") + await composer.getByRole("button", { name: "Add images and files" }).click() + await page.getByRole("menuitem", { name: "Commands" }).click() + await page.locator('[data-suggestion-id="model.choose"]').click() + + await expect(input).toHaveText("keep me") +}) diff --git a/packages/session-ui/src/v2/components/prompt-input/interaction.ts b/packages/session-ui/src/v2/components/prompt-input/interaction.ts index 989ebcac20..f48ba6b03f 100644 --- a/packages/session-ui/src/v2/components/prompt-input/interaction.ts +++ b/packages/session-ui/src/v2/components/prompt-input/interaction.ts @@ -164,21 +164,24 @@ export function createPromptInputV2Controller(input: { function dispatch(event: PromptInputV2InteractionEvent) { const mode = state.mode const result = transitionPromptInputV2(state, event, draft.state) - setState(reconcile(result.state)) - result.commands.forEach(execute) - if (mode !== result.state.mode) { - if (result.state.mode === "shell") input.view.shell?.onOpen() - if (result.state.mode === "normal") input.view.shell?.onClose() - } + const action = event.type === "popover.select" ? input.onSuggestionSelect?.(event.item) : undefined if (event.type === "popover.select") { - const action = input.onSuggestionSelect?.(event.item) - if (!action) return result.handled - if (event.item.kind === "command") { + if (!action || state.popover.type !== "command-menu") result.commands.forEach(execute) + if (action && event.item.kind === "command" && state.popover.type !== "command-menu") { draft.setPrompt( draft.state.prompt.filter((part): part is PromptInputV2Attachment => part.type === "image"), 0, ) } + } + setState(reconcile(result.state)) + if (event.type !== "popover.select") result.commands.forEach(execute) + if (mode !== result.state.mode) { + if (result.state.mode === "shell") input.view.shell?.onOpen() + if (result.state.mode === "normal") input.view.shell?.onClose() + } + if (event.type === "popover.select") { + if (!action) return result.handled action() } return result.handled