webui: Spring Cleaning Refactor v1 (#22505)

* wip: server_tools

* feat: Integrate with `/tools` endpoint

* feat: Builtin + MCP + JSON Schema Tools WIP

* refactor

* displayName -> display_name

* snake_case everywhere

* rm redundant field

* feat: Improvements

* chore: update webui build output

* refactor: Updates after server updates

* chore: update webui build output

* change arg to --tools all

* feat: UI improvements

* chore: update webui build output

* add readme mention

* llama-gen-docs

* chore: update webui build output

* chore: update webui build output

* chore: update webui build output

* feat: Reorganize settings sections

* feat: Separate dialogs for MCP Servers Settings and Import/Export

* feat: WIP

* feat: WIP

* feat: WIP

* feat: WIP

* feat: WIP

* feat: WIP

* WIP on allozaur/20677-webui-server-tools

* feat: UI improvements

* chore: Update package lock

* chore: Run `npm audit fix`

* feat: UI WIP

* feat: UI

* refactor: Desktop Icon Strip DRY

* feat: Cleaner rendering and transition for ChatScreen

* feat: UI improvements

* feat: UI improvement

* feat: Remove MCP Server "enable" switch from Tools submenu

* chore: Run `npm audit fix`

* feat: WIP

* feat: Logic improvements

* refactor: Cleanup

* refactor: DRY

* test: Fix Chat Sidebar UI Tests

* chore: Update package lock

* refactor: Cleanup

* feat: Chat Message Action Card with Continue and Permission flow implementations

* feat: Add agentic steering messages, draft messages and improve chat UX

* fix: Search results UI

* test: Fix unit test

* feat: UI/UX improvements

* refactor: Simplify `useToolsPanel` access in components

* feat: Implement Processing Info Context API

* feat: Implement 'Go back to chat' functionality for settings

* feat: Enhance MCP Server management in Chat Form Attachments

* style: Minor UI and branding adjustments

* chore: Update webui static build output

* chore: Formatting, linting & type checks

* feat: Draft messages logic

* feat: UI improvements

* feat: Steering Messages improvements

* refactor: Cleanup

* refactor: Cleanup

* feat: Improve UI

* refactor: Settings navigation hook

* refactor: DRY code

* refactor: DRY ChatMessageUser UI components

* refactor: Desktop Icon Strip DRY

* refactor: Tools & permissions

* fix: Navigation condition

* refactor: Cleanup

* refactor: Cleanup

* refactor: Cleanup

* fix: preserve reasoning_content in agentic flow

* refactor: Storybook cleanup

* refactor: isInViewport util function

* refactor: Rename globally `onClick` to `onclick`

* chore: `npm audit fix`

* refactor: Action Icon usage

* refactor: Naming

* refactor: JS in `class` directive

* refactor: Chat components cleanup WIP

* refactor: Components structure

* refactor: Cleanup WIP

* feat: New ChatAttachmentsPreview component

* feat: UI improvements

* feat: UI improvements

* refactor: Cleanup

* refactor: ChatAttachmentsPreview UI/UX

* refactor: Remove dead code

* refactor: Cleanup

* fix: Model Name aliases displaying

* feat: Shortcut improvements

* refactor: Chat Message

* feat: Move Import/Export to settings

* refactor: Cleanup

* refactor: Cleanup

* refactor: Cleanup

* refactor: Cleanup

---------

Co-authored-by: Xuan Son Nguyen <son@huggingface.co>
This commit is contained in:
Aleksander Grygier
2026-05-01 18:36:29 +02:00
committed by GitHub
parent c3c1505392
commit ab6120cde5
167 changed files with 6978 additions and 7257 deletions
@@ -2,29 +2,29 @@ import { AttachmentType, FileTypeCategory, SpecialFileType } from '$lib/enums';
import { getFileTypeCategory, getFileTypeCategoryByExtension, isImageFile } from '$lib/utils';
import type {
AttachmentDisplayItemsOptions,
ChatUploadedFile,
DatabaseMessageExtra
ChatAttachmentDisplayItem,
ChatUploadedFile
} from '$lib/types';
/**
* Check if an uploaded file is an MCP prompt
* Check if a display item represents an MCP prompt
* (either from attachment type or uploaded file with mcpPrompt metadata)
*/
function isMcpPromptUpload(file: ChatUploadedFile): boolean {
return file.type === SpecialFileType.MCP_PROMPT && !!file.mcpPrompt;
export function isMcpPrompt(item: ChatAttachmentDisplayItem): boolean {
if (item.attachment?.type === AttachmentType.MCP_PROMPT) {
return true;
}
if (item.uploadedFile?.type === SpecialFileType.MCP_PROMPT && item.uploadedFile.mcpPrompt) {
return true;
}
return false;
}
/**
* Check if an attachment is an MCP prompt
* Check if a display item represents an MCP resource
*/
function isMcpPromptAttachment(attachment: DatabaseMessageExtra): boolean {
return attachment.type === AttachmentType.MCP_PROMPT;
}
/**
* Check if an attachment is an MCP resource
*/
function isMcpResourceAttachment(attachment: DatabaseMessageExtra): boolean {
return attachment.type === AttachmentType.MCP_RESOURCE;
export function isMcpResource(item: ChatAttachmentDisplayItem): boolean {
return item.attachment?.type === AttachmentType.MCP_RESOURCE;
}
/**
@@ -58,7 +58,6 @@ export function getAttachmentDisplayItems(
size: file.size,
preview: file.preview,
isImage: getUploadedFileCategory(file) === FileTypeCategory.IMAGE,
isMcpPrompt: isMcpPromptUpload(file),
isLoading: file.isLoading,
loadError: file.loadError,
uploadedFile: file,
@@ -69,16 +68,13 @@ export function getAttachmentDisplayItems(
// Add stored attachments (ChatMessage)
for (const [index, attachment] of attachments.entries()) {
const isImage = isImageFile(attachment);
const isMcpPrompt = isMcpPromptAttachment(attachment);
const isMcpResource = isMcpResourceAttachment(attachment);
items.push({
id: `attachment-${index}`,
name: attachment.name,
size: 'size' in attachment ? attachment.size : undefined,
preview: isImage && 'base64Url' in attachment ? attachment.base64Url : undefined,
isImage,
isMcpPrompt,
isMcpResource,
attachment,
attachmentIndex: index,
textContent: 'content' in attachment ? attachment.content : undefined
@@ -38,6 +38,7 @@ export async function parseFilesToMessageExtras(
extras.push({
type: AttachmentType.MCP_PROMPT,
name: file.name,
size: file.size,
serverName: file.mcpPrompt.serverName,
promptName: file.mcpPrompt.promptName,
content: file.textContent ?? '',
@@ -68,6 +69,7 @@ export async function parseFilesToMessageExtras(
extras.push({
type: AttachmentType.IMAGE,
name: file.name,
size: file.size,
base64Url
});
}
@@ -79,6 +81,7 @@ export async function parseFilesToMessageExtras(
extras.push({
type: AttachmentType.AUDIO,
name: file.name,
size: file.size,
base64Data: base64Data,
mimeType: file.type
});
@@ -132,6 +135,7 @@ export async function parseFilesToMessageExtras(
extras.push({
type: AttachmentType.PDF,
name: file.name,
size: file.size,
content: `PDF file with ${images.length} pages`,
images: images,
processedAsImages: true,
@@ -149,6 +153,7 @@ export async function parseFilesToMessageExtras(
extras.push({
type: AttachmentType.PDF,
name: file.name,
size: file.size,
content: content,
processedAsImages: false,
base64Data: base64Data
@@ -166,6 +171,7 @@ export async function parseFilesToMessageExtras(
extras.push({
type: AttachmentType.PDF,
name: file.name,
size: file.size,
content: content,
processedAsImages: false,
base64Data: base64Data
@@ -186,6 +192,7 @@ export async function parseFilesToMessageExtras(
extras.push({
type: AttachmentType.TEXT,
name: file.name,
size: file.size,
content: content
});
} else {
+1 -1
View File
@@ -13,7 +13,7 @@ export { apiFetch, apiFetchWithParams, apiPost, type ApiFetchOptions } from './a
export { validateApiKey } from './api-key-validation';
// Attachment utilities
export { getAttachmentDisplayItems } from './attachment-display';
export { getAttachmentDisplayItems, isMcpPrompt, isMcpResource } from './attachment-display';
export { isTextFile, isImageFile, isPdfFile, isAudioFile } from './attachment-type';
// Textarea utilities
@@ -0,0 +1,12 @@
/**
* Check if an element is within the current viewport.
*/
export function isElementInViewport(node: HTMLElement): boolean {
const rect = node.getBoundingClientRect();
return (
rect.top < window.innerHeight &&
rect.bottom > 0 &&
rect.left < window.innerWidth &&
rect.right > 0
);
}