diff --git a/ui/src/e2e/chat-pasted-text-show-in-text-field.e2e.test.ts b/ui/src/e2e/chat-pasted-text-show-in-text-field.e2e.test.ts new file mode 100644 index 000000000000..c60c859a77bf --- /dev/null +++ b/ui/src/e2e/chat-pasted-text-show-in-text-field.e2e.test.ts @@ -0,0 +1,55 @@ +import { expect, it } from "vitest"; +import { installMockGateway } from "../test-helpers/control-ui-e2e.ts"; +import { createControlUiE2eSuite } from "./control-ui-e2e-suite.test-support.ts"; + +const suite = createControlUiE2eSuite({ + name: "Control UI pasted text field action", + startServerBeforeBrowser: true, + unavailableMessage: (executablePath) => `Playwright Chromium is unavailable at ${executablePath}`, +}); + +const pastedText = `Quarterly launch plan\n\n${"x".repeat(1100)}`; + +suite.define(() => { + it("returns a pasted text attachment to the text field without sending", async () => { + await suite.withPage( + { + locale: "en-US", + reducedMotion: "reduce", + serviceWorkers: "block", + viewport: { height: 900, width: 1280 }, + }, + async ({ page }) => { + const gateway = await installMockGateway(page); + await page.goto(`${suite.server.baseUrl}chat`); + + const composer = page.locator(".agent-chat__composer-combobox textarea"); + await composer.waitFor({ state: "visible" }); + await composer.evaluate((element, text) => { + const clipboard = new DataTransfer(); + clipboard.setData("text/plain", text); + element.dispatchEvent( + new ClipboardEvent("paste", { + bubbles: true, + cancelable: true, + clipboardData: clipboard, + }), + ); + }, pastedText); + + const showInTextField = page.getByRole("button", { + name: "Show in text field", + exact: true, + }); + await showInTextField.waitFor({ state: "visible" }); + expect((await showInTextField.textContent())?.trim()).toBe("Show in text field"); + + await showInTextField.click(); + + await expect.poll(() => page.locator(".chat-attachment-thumb").count()).toBe(0); + await expect.poll(() => composer.inputValue()).toBe(pastedText); + expect(await gateway.getRequests("chat.send")).toHaveLength(0); + }, + ); + }); +}); diff --git a/ui/src/i18n/locales/en.ts b/ui/src/i18n/locales/en.ts index 33845a8b3559..4428cb2c5daa 100644 --- a/ui/src/i18n/locales/en.ts +++ b/ui/src/i18n/locales/en.ts @@ -5151,6 +5151,7 @@ export const en: TranslationMap = { }, attachments: { attachedFile: "Attached file", + showInTextField: "Show in text field", outsideAllowedFolders: "Outside allowed folders", unavailable: "Unavailable", checking: "Checking...", diff --git a/ui/src/pages/chat/chat-view.test.ts b/ui/src/pages/chat/chat-view.test.ts index a989fe91aefe..08afdaec19aa 100644 --- a/ui/src/pages/chat/chat-view.test.ts +++ b/ui/src/pages/chat/chat-view.test.ts @@ -4408,8 +4408,8 @@ describe("chat attachment picker", () => { expect(container.querySelector(".chat-attachment-file__name")?.textContent).toContain( "First words from a l...", ); - expect(container.querySelector(".chat-attachment-text-action")?.textContent).toContain( - "Restore", + expect(container.querySelector(".chat-attachment-text-action")?.textContent?.trim()).toBe( + "Show in text field", ); }); @@ -4441,7 +4441,7 @@ describe("chat attachment picker", () => { expect(onAttachmentsChange).not.toHaveBeenCalled(); }); - it("moves a pasted text attachment back into the composer", async () => { + it("shows a pasted text attachment in the composer text field", async () => { const onAttachmentsChange = vi.fn(); const firstRender = renderChatView({ onAttachmentsChange }); const textarea = getComposerTextarea(firstRender); @@ -4467,13 +4467,13 @@ describe("chat attachment picker", () => { }), 'renderChatView({ attachments: [attachment], draft: "intro", getDraft:... test invariant', ); - const showButton = requireElement( + const showInTextFieldButton = requireElement( preview, - '[aria-label="Restore"]', - "show pasted text button", + '[aria-label="Show in text field"]', + "show pasted text in text field button", ) as HTMLButtonElement; - showButton.click(); + showInTextFieldButton.click(); expect(onShowAttachmentsChange).toHaveBeenCalledWith([]); expect(onDraftChange).toHaveBeenCalledWith(`intro\n\n${pastedText}`); diff --git a/ui/src/pages/chat/components/chat-attachments.ts b/ui/src/pages/chat/components/chat-attachments.ts index 53eb74807f9e..cb1e9ac3dbbe 100644 --- a/ui/src/pages/chat/components/chat-attachments.ts +++ b/ui/src/pages/chat/components/chat-attachments.ts @@ -550,11 +550,11 @@ export function renderAttachmentPreview(props: ChatAttachmentControlsProps) {