From ba230c5cce8e9d39091a9db61921e06a86dd2ce3 Mon Sep 17 00:00:00 2001 From: Aleksander Grygier Date: Sat, 24 Jan 2026 23:50:54 +0100 Subject: [PATCH] refactor: Naming + remove redundant component --- .../ChatAttachmentMcpPrompt.svelte | 5 +- .../app/chat/ChatForm/ChatForm.svelte | 460 ++++++++++++++---- .../chat/ChatForm/ChatFormInputArea.svelte | 418 ---------------- .../ChatMessages/ChatMessageEditForm.svelte | 6 +- .../ChatMessages/ChatMessageMcpPrompt.svelte | 5 +- .../ChatMessageMcpPromptContent.svelte} | 0 .../app/chat/ChatScreen/ChatScreen.svelte | 6 +- .../app/chat/ChatScreen/ChatScreenForm.svelte | 122 +++++ .../app/chat/ChatSettings/ChatSettings.svelte | 2 +- .../webui/src/lib/components/app/index.ts | 11 +- .../app/{misc => mcp}/McpLogo.svelte | 0 .../lib/components/app/mcp/McpSelector.svelte | 199 -------- ...s.svelte => ChatScreenForm.stories.svelte} | 6 +- 13 files changed, 519 insertions(+), 721 deletions(-) delete mode 100644 tools/server/webui/src/lib/components/app/chat/ChatForm/ChatFormInputArea.svelte rename tools/server/webui/src/lib/components/app/chat/{McpPromptContent.svelte => ChatMessages/ChatMessageMcpPromptContent.svelte} (100%) create mode 100644 tools/server/webui/src/lib/components/app/chat/ChatScreen/ChatScreenForm.svelte rename tools/server/webui/src/lib/components/app/{misc => mcp}/McpLogo.svelte (100%) delete mode 100644 tools/server/webui/src/lib/components/app/mcp/McpSelector.svelte rename tools/server/webui/tests/stories/{ChatForm.stories.svelte => ChatScreenForm.stories.svelte} (93%) diff --git a/tools/server/webui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentMcpPrompt.svelte b/tools/server/webui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentMcpPrompt.svelte index 88348bda6a..b50c24756c 100644 --- a/tools/server/webui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentMcpPrompt.svelte +++ b/tools/server/webui/src/lib/components/app/chat/ChatAttachments/ChatAttachmentMcpPrompt.svelte @@ -1,6 +1,5 @@
- + {#if !readonly && onRemove}
- import { afterNavigate } from '$app/navigation'; - import { ChatFormHelperText, ChatFormInputArea } from '$lib/components/app'; + import { + ChatAttachmentsList, + ChatFormActions, + ChatFormFileInputInvisible, + ChatFormPromptPicker, + ChatFormTextarea + } from '$lib/components/app'; + import { INPUT_CLASSES } from '$lib/constants/css-classes'; + import { SETTING_CONFIG_DEFAULT } from '$lib/constants/settings-config'; + import { MimeTypeText } from '$lib/enums'; + import { config } from '$lib/stores/settings.svelte'; + import { modelOptions, selectedModelId } from '$lib/stores/models.svelte'; + import { isRouterMode } from '$lib/stores/server.svelte'; + import { chatStore } from '$lib/stores/chat.svelte'; + import { mcpStore } from '$lib/stores/mcp.svelte'; + import { conversationsStore, activeMessages } from '$lib/stores/conversations.svelte'; + import type { GetPromptResult, MCPPromptInfo } from '$lib/types'; + import { isIMEComposing, parseClipboardContent } from '$lib/utils'; + import { + AudioRecorder, + convertToWav, + createAudioFile, + isAudioRecordingSupported + } from '$lib/utils/browser-only'; import { onMount } from 'svelte'; interface Props { + attachments?: DatabaseMessageExtra[]; class?: string; disabled?: boolean; - initialMessage?: string; isLoading?: boolean; - onFileRemove?: (fileId: string) => void; - onFileUpload?: (files: File[]) => void; - onSend?: (message: string, files?: ChatUploadedFile[]) => Promise; - onStop?: () => void; - onSystemPromptAdd?: (draft: { message: string; files: ChatUploadedFile[] }) => void; - showHelperText?: boolean; + placeholder?: string; + showMcpPromptButton?: boolean; uploadedFiles?: ChatUploadedFile[]; + value?: string; + onAttachmentRemove?: (index: number) => void; + onFilesAdd?: (files: File[]) => void; + onStop?: () => void; + onSubmit?: () => void; + onSystemPromptClick?: (draft: { message: string; files: ChatUploadedFile[] }) => void; + onUploadedFileRemove?: (fileId: string) => void; + onUploadedFilesChange?: (files: ChatUploadedFile[]) => void; + onValueChange?: (value: string) => void; } let { - class: className, + attachments = [], + class: className = '', disabled = false, - initialMessage = '', isLoading = false, - onFileRemove, - onFileUpload, - onSend, + placeholder = 'Type a message...', + showMcpPromptButton = false, + uploadedFiles = $bindable([]), + value = $bindable(''), + onAttachmentRemove, + onFilesAdd, onStop, - onSystemPromptAdd, - showHelperText = true, - uploadedFiles = $bindable([]) + onSubmit, + onSystemPromptClick, + onUploadedFileRemove, + onUploadedFilesChange, + onValueChange }: Props = $props(); - let inputAreaRef: ChatFormInputArea | undefined = $state(undefined); - let message = $state(initialMessage); - let previousIsLoading = $state(isLoading); - let previousInitialMessage = $state(initialMessage); + let audioRecorder: AudioRecorder | undefined; + let chatFormActionsRef: ChatFormActions | undefined = $state(undefined); + let currentConfig = $derived(config()); + let fileInputRef: ChatFormFileInputInvisible | undefined = $state(undefined); + let isRecording = $state(false); + let promptPickerRef: ChatFormPromptPicker | undefined = $state(undefined); + let isPromptPickerOpen = $state(false); + let promptSearchQuery = $state(''); + let recordingSupported = $state(false); + let textareaRef: ChatFormTextarea | undefined = $state(undefined); - // Sync message when initialMessage prop changes (e.g., after draft restoration) - $effect(() => { - if (initialMessage !== previousInitialMessage) { - message = initialMessage; - previousInitialMessage = initialMessage; + let isRouter = $derived(isRouterMode()); + + let conversationModel = $derived( + chatStore.getConversationModel(activeMessages() as DatabaseMessage[]) + ); + + let activeModelId = $derived.by(() => { + const options = modelOptions(); + + if (!isRouter) { + return options.length > 0 ? options[0].model : null; } + + const selectedId = selectedModelId(); + if (selectedId) { + const model = options.find((m) => m.id === selectedId); + if (model) return model.model; + } + + if (conversationModel) { + const model = options.find((m) => m.model === conversationModel); + if (model) return model.model; + } + + return null; }); - function handleSystemPromptClick() { - onSystemPromptAdd?.({ message, files: uploadedFiles }); + let pasteLongTextToFileLength = $derived.by(() => { + const n = Number(currentConfig.pasteLongTextToFileLen); + return Number.isNaN(n) ? Number(SETTING_CONFIG_DEFAULT.pasteLongTextToFileLen) : n; + }); + + let hasModelSelected = $derived(!isRouter || !!conversationModel || !!selectedModelId()); + let hasLoadingAttachments = $derived(uploadedFiles.some((f) => f.isLoading)); + let hasAttachments = $derived( + (attachments && attachments.length > 0) || (uploadedFiles && uploadedFiles.length > 0) + ); + let canSubmit = $derived(value.trim().length > 0 || hasAttachments); + + export function focus() { + textareaRef?.focus(); } - let hasLoadingAttachments = $derived(uploadedFiles.some((f) => f.isLoading)); + export function resetHeight() { + textareaRef?.resetHeight(); + } - async function handleSubmit() { - if ( - (!message.trim() && uploadedFiles.length === 0) || - disabled || - isLoading || - hasLoadingAttachments - ) - return; + export function openModelSelector() { + chatFormActionsRef?.openModelSelector(); + } - if (!inputAreaRef?.checkModelSelected()) return; + export function checkModelSelected(): boolean { + if (!hasModelSelected) { + chatFormActionsRef?.openModelSelector(); + return false; + } + return true; + } - const messageToSend = message.trim(); - const filesToSend = [...uploadedFiles]; + function handleFileSelect(files: File[]) { + onFilesAdd?.(files); + } - message = ''; - uploadedFiles = []; + function handleFileUpload() { + fileInputRef?.click(); + } - inputAreaRef?.resetHeight(); + function handleInput() { + const perChatOverrides = conversationsStore.getAllMcpServerOverrides(); + const hasServers = mcpStore.hasEnabledServers(perChatOverrides); - const success = await onSend?.(messageToSend, filesToSend); - - if (!success) { - message = messageToSend; - uploadedFiles = filesToSend; + if (value.startsWith('/') && hasServers) { + isPromptPickerOpen = true; + promptSearchQuery = value.slice(1); + } else { + isPromptPickerOpen = false; + promptSearchQuery = ''; } } - function handleFilesAdd(files: File[]) { - onFileUpload?.(files); + function handleKeydown(event: KeyboardEvent) { + if (isPromptPickerOpen && promptPickerRef?.handleKeydown(event)) { + return; + } + + if (event.key === 'Escape' && isPromptPickerOpen) { + isPromptPickerOpen = false; + promptSearchQuery = ''; + return; + } + + if (event.key === 'Enter' && !event.shiftKey && !isIMEComposing(event)) { + event.preventDefault(); + + if (!canSubmit || disabled || isLoading || hasLoadingAttachments) return; + + onSubmit?.(); + } } - function handleUploadedFileRemove(fileId: string) { - onFileRemove?.(fileId); + function handlePromptLoadStart( + placeholderId: string, + promptInfo: MCPPromptInfo, + args?: Record + ) { + value = ''; + onValueChange?.(''); + isPromptPickerOpen = false; + promptSearchQuery = ''; + + const promptName = promptInfo.title || promptInfo.name; + const placeholder: ChatUploadedFile = { + id: placeholderId, + name: promptName, + size: 0, + type: 'mcp-prompt', + file: new File([], 'loading'), + isLoading: true, + mcpPrompt: { + serverName: promptInfo.serverName, + promptName: promptInfo.name, + arguments: args ? { ...args } : undefined + } + }; + + uploadedFiles = [...uploadedFiles, placeholder]; + onUploadedFilesChange?.(uploadedFiles); + textareaRef?.focus(); + } + + function handlePromptLoadComplete(placeholderId: string, result: GetPromptResult) { + const promptText = result.messages + ?.map((msg) => { + if (typeof msg.content === 'string') { + return msg.content; + } + if (msg.content.type === 'text') { + return msg.content.text; + } + return ''; + }) + .filter(Boolean) + .join('\n\n'); + + uploadedFiles = uploadedFiles.map((f) => + f.id === placeholderId + ? { + ...f, + isLoading: false, + textContent: promptText, + size: promptText.length, + file: new File([promptText], `${f.name}.txt`, { type: 'text/plain' }) + } + : f + ); + onUploadedFilesChange?.(uploadedFiles); + } + + function handlePromptLoadError(placeholderId: string, error: string) { + uploadedFiles = uploadedFiles.map((f) => + f.id === placeholderId ? { ...f, isLoading: false, loadError: error } : f + ); + onUploadedFilesChange?.(uploadedFiles); + } + + function handlePromptPickerClose() { + isPromptPickerOpen = false; + promptSearchQuery = ''; + textareaRef?.focus(); + } + + function handleFileRemove(fileId: string) { + if (fileId.startsWith('attachment-')) { + const index = parseInt(fileId.replace('attachment-', ''), 10); + if (!isNaN(index) && index >= 0 && index < attachments.length) { + onAttachmentRemove?.(index); + } + } else { + onUploadedFileRemove?.(fileId); + } + } + + function handlePaste(event: ClipboardEvent) { + if (!event.clipboardData) return; + + const files = Array.from(event.clipboardData.items) + .filter((item) => item.kind === 'file') + .map((item) => item.getAsFile()) + .filter((file): file is File => file !== null); + + if (files.length > 0) { + event.preventDefault(); + onFilesAdd?.(files); + return; + } + + const text = event.clipboardData.getData(MimeTypeText.PLAIN); + + if (text.startsWith('"')) { + const parsed = parseClipboardContent(text); + + if (parsed.textAttachments.length > 0) { + event.preventDefault(); + value = parsed.message; + onValueChange?.(parsed.message); + + const attachmentFiles = parsed.textAttachments.map( + (att) => + new File([att.content], att.name, { + type: MimeTypeText.PLAIN + }) + ); + + onFilesAdd?.(attachmentFiles); + + setTimeout(() => { + textareaRef?.focus(); + }, 10); + + return; + } + } + + if ( + text.length > 0 && + pasteLongTextToFileLength > 0 && + text.length > pasteLongTextToFileLength + ) { + event.preventDefault(); + + const textFile = new File([text], 'Pasted', { + type: MimeTypeText.PLAIN + }); + + onFilesAdd?.([textFile]); + } + } + + async function handleMicClick() { + if (!audioRecorder || !recordingSupported) { + console.warn('Audio recording not supported'); + return; + } + + if (isRecording) { + try { + const audioBlob = await audioRecorder.stopRecording(); + const wavBlob = await convertToWav(audioBlob); + const audioFile = createAudioFile(wavBlob); + + onFilesAdd?.([audioFile]); + isRecording = false; + } catch (error) { + console.error('Failed to stop recording:', error); + isRecording = false; + } + } else { + try { + await audioRecorder.startRecording(); + isRecording = true; + } catch (error) { + console.error('Failed to start recording:', error); + } + } } onMount(() => { - setTimeout(() => inputAreaRef?.focus(), 10); - }); - - afterNavigate(() => { - setTimeout(() => inputAreaRef?.focus(), 10); - }); - - $effect(() => { - if (previousIsLoading && !isLoading) { - setTimeout(() => inputAreaRef?.focus(), 10); - } - - previousIsLoading = isLoading; + recordingSupported = isAudioRecordingSupported(); + audioRecorder = new AudioRecorder(); }); -
- -
+ - +
{ + e.preventDefault(); + if (!canSubmit || disabled || isLoading || hasLoadingAttachments) return; + onSubmit?.(); + }} +> + + +
+ + +
+ { + handleInput(); + onValueChange?.(value); + }} + {disabled} + {placeholder} + /> + + 0} + {disabled} + {isLoading} + {isRecording} + {uploadedFiles} + onFileUpload={handleFileUpload} + onMicClick={handleMicClick} + {onStop} + onSystemPromptClick={() => onSystemPromptClick?.({ message: value, files: uploadedFiles })} + onMcpPromptClick={showMcpPromptButton ? () => (isPromptPickerOpen = true) : undefined} + /> +
+
+ diff --git a/tools/server/webui/src/lib/components/app/chat/ChatForm/ChatFormInputArea.svelte b/tools/server/webui/src/lib/components/app/chat/ChatForm/ChatFormInputArea.svelte deleted file mode 100644 index 72e21b75c0..0000000000 --- a/tools/server/webui/src/lib/components/app/chat/ChatForm/ChatFormInputArea.svelte +++ /dev/null @@ -1,418 +0,0 @@ - - - - -
{ - e.preventDefault(); - if (!canSubmit || disabled || isLoading || hasLoadingAttachments) return; - onSubmit?.(); - }} -> - - -
- - -
- { - handleInput(); - onValueChange?.(value); - }} - {disabled} - {placeholder} - /> - - 0} - {disabled} - {isLoading} - {isRecording} - {uploadedFiles} - onFileUpload={handleFileUpload} - onMicClick={handleMicClick} - {onStop} - onSystemPromptClick={() => onSystemPromptClick?.({ message: value, files: uploadedFiles })} - onMcpPromptClick={showMcpPromptButton ? () => (isPromptPickerOpen = true) : undefined} - /> -
-
- diff --git a/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageEditForm.svelte b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageEditForm.svelte index 2f0b3a1b01..7cf342d0e9 100644 --- a/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageEditForm.svelte +++ b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageEditForm.svelte @@ -2,7 +2,7 @@ import { X, AlertTriangle } from '@lucide/svelte'; import { Button } from '$lib/components/ui/button'; import { Switch } from '$lib/components/ui/switch'; - import { ChatFormInputArea, DialogConfirmation } from '$lib/components/app'; + import { ChatForm, DialogConfirmation } from '$lib/components/app'; import { chatStore } from '$lib/stores/chat.svelte'; import { processFilesToChatUploaded } from '$lib/utils/browser-only'; @@ -36,7 +36,7 @@ onEditedUploadedFilesChange }: Props = $props(); - let inputAreaRef: ChatFormInputArea | undefined = $state(undefined); + let inputAreaRef: ChatForm | undefined = $state(undefined); let saveWithoutRegenerate = $state(false); let showDiscardDialog = $state(false); @@ -126,7 +126,7 @@
- - import ChatMessageActions from './ChatMessageActions.svelte'; - import McpPromptContent from '../McpPromptContent.svelte'; + import { ChatMessageActions, ChatMessageMcpPromptContent } from '$lib/components/app'; import { MessageRole } from '$lib/enums'; import type { DatabaseMessageExtraMcpPrompt } from '$lib/types'; @@ -45,7 +44,7 @@ class="group flex flex-col items-end gap-3 md:gap-2 {className}" role="group" > - + {#if message.timestamp}
diff --git a/tools/server/webui/src/lib/components/app/chat/McpPromptContent.svelte b/tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageMcpPromptContent.svelte similarity index 100% rename from tools/server/webui/src/lib/components/app/chat/McpPromptContent.svelte rename to tools/server/webui/src/lib/components/app/chat/ChatMessages/ChatMessageMcpPromptContent.svelte diff --git a/tools/server/webui/src/lib/components/app/chat/ChatScreen/ChatScreen.svelte b/tools/server/webui/src/lib/components/app/chat/ChatScreen/ChatScreen.svelte index 19a58553f4..5fe8942cea 100644 --- a/tools/server/webui/src/lib/components/app/chat/ChatScreen/ChatScreen.svelte +++ b/tools/server/webui/src/lib/components/app/chat/ChatScreen/ChatScreen.svelte @@ -1,7 +1,7 @@ + +
+ +
+ + diff --git a/tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettings.svelte b/tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettings.svelte index 7b52a992f3..d18cf602df 100644 --- a/tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettings.svelte +++ b/tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettings.svelte @@ -16,7 +16,7 @@ ChatSettingsImportExportTab, ChatSettingsFields } from '$lib/components/app'; - import McpLogo from '$lib/components/app/misc/McpLogo.svelte'; + import McpLogo from '$lib/components/app/mcp/McpLogo.svelte'; import { ScrollArea } from '$lib/components/ui/scroll-area'; import { config, settingsStore } from '$lib/stores/settings.svelte'; import { setMode } from 'mode-watcher'; diff --git a/tools/server/webui/src/lib/components/app/index.ts b/tools/server/webui/src/lib/components/app/index.ts index 0fc7780d80..8d3dd2b23e 100644 --- a/tools/server/webui/src/lib/components/app/index.ts +++ b/tools/server/webui/src/lib/components/app/index.ts @@ -14,7 +14,6 @@ export { default as ChatFormActions } from './chat/ChatForm/ChatFormActions/Chat export { default as ChatFormActionSubmit } from './chat/ChatForm/ChatFormActions/ChatFormActionSubmit.svelte'; export { default as ChatFormFileInputInvisible } from './chat/ChatForm/ChatFormFileInputInvisible.svelte'; export { default as ChatFormHelperText } from './chat/ChatForm/ChatFormHelperText.svelte'; -export { default as ChatFormInputArea } from './chat/ChatForm/ChatFormInputArea.svelte'; export { default as ChatFormPromptPicker } from './chat/ChatForm/ChatFormPromptPicker.svelte'; export { default as ChatFormTextarea } from './chat/ChatForm/ChatFormTextarea.svelte'; @@ -24,15 +23,15 @@ export { default as ChatMessageActions } from './chat/ChatMessages/ChatMessageAc export { default as ChatMessageBranchingControls } from './chat/ChatMessages/ChatMessageBranchingControls.svelte'; export { default as ChatMessageStatistics } from './chat/ChatMessages/ChatMessageStatistics.svelte'; export { default as ChatMessageMcpPrompt } from './chat/ChatMessages/ChatMessageMcpPrompt.svelte'; +export { default as ChatMessageMcpPromptContent } from './chat/ChatMessages/ChatMessageMcpPromptContent.svelte'; export { default as ChatMessageSystem } from './chat/ChatMessages/ChatMessageSystem.svelte'; export { default as ChatMessages } from './chat/ChatMessages/ChatMessages.svelte'; export { default as CollapsibleContentBlock } from './chat/ChatMessages/CollapsibleContentBlock.svelte'; export { default as MessageBranchingControls } from './chat/ChatMessages/ChatMessageBranchingControls.svelte'; -export { default as McpPromptContent } from './chat/McpPromptContent.svelte'; - export { default as ChatScreen } from './chat/ChatScreen/ChatScreen.svelte'; -export { default as KeyValuePairs } from './misc/KeyValuePairs.svelte'; +export { default as ChatScreenForm } from './chat/ChatScreen/ChatScreenForm.svelte'; + export { default as ChatScreenHeader } from './chat/ChatScreen/ChatScreenHeader.svelte'; export { default as ChatScreenProcessingInfo } from './chat/ChatScreen/ChatScreenProcessingInfo.svelte'; @@ -66,11 +65,11 @@ export { default as ActionButton } from './misc/ActionButton.svelte'; export { default as ActionDropdown } from './misc/ActionDropdown.svelte'; export { default as BadgeChatStatistic } from './misc/BadgeChatStatistic.svelte'; export { default as BadgeInfo } from './misc/BadgeInfo.svelte'; -export { default as McpLogo } from './misc/McpLogo.svelte'; export { default as BadgeModality } from './misc/BadgeModality.svelte'; export { default as ConversationSelection } from './misc/ConversationSelection.svelte'; export { default as CopyToClipboardIcon } from './misc/CopyToClipboardIcon.svelte'; export { default as KeyboardShortcutInfo } from './misc/KeyboardShortcutInfo.svelte'; +export { default as KeyValuePairs } from './misc/KeyValuePairs.svelte'; export { default as MarkdownContent } from './misc/MarkdownContent.svelte'; export { default as RemoveButton } from './misc/RemoveButton.svelte'; export { default as SearchInput } from './misc/SearchInput.svelte'; @@ -86,7 +85,7 @@ export { default as ModelsSelector } from './models/ModelsSelector.svelte'; // MCP export { default as McpActiveServersAvatars } from './mcp/McpActiveServersAvatars.svelte'; -export { default as McpSelector } from './mcp/McpSelector.svelte'; +export { default as McpLogo } from './mcp/McpLogo.svelte'; export { default as McpSettingsSection } from './mcp/McpSettingsSection.svelte'; // Server diff --git a/tools/server/webui/src/lib/components/app/misc/McpLogo.svelte b/tools/server/webui/src/lib/components/app/mcp/McpLogo.svelte similarity index 100% rename from tools/server/webui/src/lib/components/app/misc/McpLogo.svelte rename to tools/server/webui/src/lib/components/app/mcp/McpLogo.svelte diff --git a/tools/server/webui/src/lib/components/app/mcp/McpSelector.svelte b/tools/server/webui/src/lib/components/app/mcp/McpSelector.svelte deleted file mode 100644 index f4a494c9bc..0000000000 --- a/tools/server/webui/src/lib/components/app/mcp/McpSelector.svelte +++ /dev/null @@ -1,199 +0,0 @@ - - -{#if hasMcpServers} - - {#snippet trigger()} - - {/snippet} - -
- {#if isLoading} - {#each mcpServers as server (server.id)} -
-
- - -
- -
- {/each} - {:else} - {#each filteredMcpServers as server (server.id)} - {@const healthState = mcpStore.getHealthCheckState(server.id)} - {@const hasError = healthState.status === HealthCheckStatus.Error} - {@const isEnabledForChat = isServerEnabledForChat(server.id)} - - - {/each} - {/if} -
- - {#snippet footer()} - - - Manage MCP Servers - - {/snippet} -
-{:else} - -{/if} diff --git a/tools/server/webui/tests/stories/ChatForm.stories.svelte b/tools/server/webui/tests/stories/ChatScreenForm.stories.svelte similarity index 93% rename from tools/server/webui/tests/stories/ChatForm.stories.svelte rename to tools/server/webui/tests/stories/ChatScreenForm.stories.svelte index a8a4c21b44..4c17343459 100644 --- a/tools/server/webui/tests/stories/ChatForm.stories.svelte +++ b/tools/server/webui/tests/stories/ChatScreenForm.stories.svelte @@ -1,14 +1,14 @@