From 9716db018d62532ed45000eaa8c683beb0859194 Mon Sep 17 00:00:00 2001 From: Aleksander Grygier Date: Fri, 12 Dec 2025 13:54:43 +0100 Subject: [PATCH 1/7] feat: Create copy/paste user message including "pasted text" attachments --- tools/server/webui/README.md | 11 +- tools/server/webui/package.json | 5 +- .../app/chat/ChatForm/ChatForm.svelte | 28 +- .../app/chat/ChatMessages/ChatMessage.svelte | 7 +- .../app/chat/ChatSettings/ChatSettings.svelte | 5 + .../src/lib/constants/settings-config.ts | 3 + tools/server/webui/src/lib/utils/clipboard.ts | 267 +++++++++++ tools/server/webui/src/lib/utils/copy.ts | 71 --- tools/server/webui/src/lib/utils/index.ts | 10 +- tools/server/webui/tests/server/demo.spec.ts | 7 - .../server/webui/tests/unit/clipboard.test.ts | 423 ++++++++++++++++++ .../unit}/latex-protection.test.ts | 2 +- .../utils => tests/unit}/model-names.test.ts | 2 +- tools/server/webui/vite.config.ts | 4 +- 14 files changed, 750 insertions(+), 95 deletions(-) create mode 100644 tools/server/webui/src/lib/utils/clipboard.ts delete mode 100644 tools/server/webui/src/lib/utils/copy.ts delete mode 100644 tools/server/webui/tests/server/demo.spec.ts create mode 100644 tools/server/webui/tests/unit/clipboard.test.ts rename tools/server/webui/{src/lib/utils => tests/unit}/latex-protection.test.ts (99%) rename tools/server/webui/{src/lib/utils => tests/unit}/model-names.test.ts (95%) diff --git a/tools/server/webui/README.md b/tools/server/webui/README.md index d995271fc4b..98b01fdcd7f 100644 --- a/tools/server/webui/README.md +++ b/tools/server/webui/README.md @@ -619,11 +619,12 @@ flowchart TB ### Test Types -| Type | Tool | Location | Command | -| ------------- | ------------------ | -------------------------------- | ------------------- | -| **E2E** | Playwright | `tests/e2e/` | `npm run test:e2e` | -| **Unit** | Vitest | `tests/client/`, `tests/server/` | `npm run test:unit` | -| **UI/Visual** | Storybook + Vitest | `tests/stories/` | `npm run test:ui` | +| Type | Tool | Location | Command | +| ------------- | ------------------ | ---------------- | ------------------- | +| **Unit** | Vitest | `tests/unit/` | `npm run test:unit` | +| **UI/Visual** | Storybook + Vitest | `tests/stories/` | `npm run test:ui` | +| **E2E** | Playwright | `tests/e2e/` | `npm run test:e2e` | +| **Client** | Vitest | `tests/client/`. | `npm run test:unit` | ### Running Tests diff --git a/tools/server/webui/package.json b/tools/server/webui/package.json index c20ab3cfde0..1c970ae7a89 100644 --- a/tools/server/webui/package.json +++ b/tools/server/webui/package.json @@ -13,12 +13,11 @@ "reset": "rm -rf .svelte-kit node_modules", "format": "prettier --write .", "lint": "prettier --check . && eslint .", - "test": "npm run test:ui -- --run && npm run test:client -- --run && npm run test:server -- --run && npm run test:e2e", + "test": "npm run test:ui -- --run && npm run test:client -- --run && npm run test:unit -- --run && npm run test:e2e", "test:e2e": "playwright test", "test:client": "vitest --project=client", - "test:server": "vitest --project=server", + "test:unit": "vitest --project=unit", "test:ui": "vitest --project=ui", - "test:unit": "vitest", "storybook": "storybook dev -p 6006", "build-storybook": "storybook build", "cleanup": "rm -rf .svelte-kit build node_modules test-results" diff --git a/tools/server/webui/src/lib/components/app/chat/ChatForm/ChatForm.svelte b/tools/server/webui/src/lib/components/app/chat/ChatForm/ChatForm.svelte index 78cc1c47daa..3ad14ed3ab0 100644 --- a/tools/server/webui/src/lib/components/app/chat/ChatForm/ChatForm.svelte +++ b/tools/server/webui/src/lib/components/app/chat/ChatForm/ChatForm.svelte @@ -24,7 +24,7 @@ MimeTypeImage, MimeTypeText } from '$lib/enums'; - import { isIMEComposing } from '$lib/utils'; + import { isIMEComposing, parseClipboardContent } from '$lib/utils'; import { AudioRecorder, convertToWav, @@ -191,7 +191,6 @@ if ((!message.trim() && uploadedFiles.length === 0) || disabled || isLoading) return; - // Check if model is selected first if (!checkModelSelected()) return; const messageToSend = message.trim(); @@ -228,6 +227,31 @@ const text = event.clipboardData.getData(MimeTypeText.PLAIN); + if (text.startsWith('"')) { + const parsed = parseClipboardContent(text); + + if (parsed.textAttachments.length > 0) { + event.preventDefault(); + + message = parsed.message; + + const attachmentFiles = parsed.textAttachments.map( + (att) => + new File([att.content], att.name, { + type: MimeTypeText.PLAIN + }) + ); + + onFileUpload?.(attachmentFiles); + + setTimeout(() => { + textareaRef?.focus(); + }, 10); + + return; + } + } + if ( text.length > 0 && pasteLongTextToFileLength > 0 && diff --git a/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessage.svelte b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessage.svelte index 96ed56a7758..0969a937ed2 100644 --- a/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessage.svelte +++ b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessage.svelte @@ -1,6 +1,7 @@