Просмотр исходного кода

fix(app): preserve command menu drafts (#37942)

Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
opencode-agent[bot] 1 месяц назад
Родитель
Сommit
da312b009c

+ 50 - 0
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")
+})

+ 11 - 8
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)
+    const action = event.type === "popover.select" ? input.onSuggestionSelect?.(event.item) : undefined
+    if (event.type === "popover.select") {
+      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))
-    result.commands.forEach(execute)
+    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") {
-      const action = input.onSuggestionSelect?.(event.item)
       if (!action) return result.handled
-      if (event.item.kind === "command") {
-        draft.setPrompt(
-          draft.state.prompt.filter((part): part is PromptInputV2Attachment => part.type === "image"),
-          0,
-        )
-      }
       action()
     }
     return result.handled