From 4fa3a748277b61f226fc5cfcaef845b9d6be1c62 Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Mon, 29 Jun 2026 05:58:30 -0400 Subject: [PATCH] fix(chat): prevent sortable sidebar drags from triggering file upload overlay (#25675) Add a custom MIME type (application/x-open-webui-drag) to intentional chat and folder drag sources. The onDragOver handler in MessageInput now checks for this type instead of the generic text/plain, which SortableJS also sets during reorder operations for pinned menu items (Notes, Workspace) and pinned Models. --- src/lib/components/chat/MessageInput.svelte | 9 +++++++-- src/lib/components/common/Folder.svelte | 4 ++++ src/lib/components/layout/Sidebar/ChatItem.svelte | 1 + src/lib/components/layout/Sidebar/RecursiveFolder.svelte | 5 +++++ 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/lib/components/chat/MessageInput.svelte b/src/lib/components/chat/MessageInput.svelte index 607075aa2a..e689ed4001 100644 --- a/src/lib/components/chat/MessageInput.svelte +++ b/src/lib/components/chat/MessageInput.svelte @@ -857,8 +857,13 @@ const onDragOver = (e: DragEvent) => { e.preventDefault(); - // Check if a file or a sidebar chat item is being dragged. - if (e.dataTransfer?.types?.includes('Files') || e.dataTransfer?.types?.includes('text/plain')) { + // Check if a file or a sidebar chat/folder item is being dragged. + // Use a custom MIME type to distinguish intentional drags from SortableJS reorder drags + // (e.g. Notes, Workspace, pinned Models), which also set 'text/plain'. + if ( + e.dataTransfer?.types?.includes('Files') || + e.dataTransfer?.types?.includes('application/x-open-webui-drag') + ) { dragged = true; } else { dragged = false; diff --git a/src/lib/components/common/Folder.svelte b/src/lib/components/common/Folder.svelte index 45c2386d89..93ec72763e 100644 --- a/src/lib/components/common/Folder.svelte +++ b/src/lib/components/common/Folder.svelte @@ -88,6 +88,10 @@ } finally { draggedOver = false; } + + // Only process the first non-file item; all share the same + // text/plain payload, so continuing would duplicate the drop. + break; } } } diff --git a/src/lib/components/layout/Sidebar/ChatItem.svelte b/src/lib/components/layout/Sidebar/ChatItem.svelte index 2dd5def8e1..0e7c2bf181 100644 --- a/src/lib/components/layout/Sidebar/ChatItem.svelte +++ b/src/lib/components/layout/Sidebar/ChatItem.svelte @@ -266,6 +266,7 @@ id: id }) ); + event.dataTransfer.setData('application/x-open-webui-drag', ''); dragged = true; itemElement.style.opacity = '0.5'; // Optional: Visual cue to show it's being dragged diff --git a/src/lib/components/layout/Sidebar/RecursiveFolder.svelte b/src/lib/components/layout/Sidebar/RecursiveFolder.svelte index 085bafa395..0f401b5abd 100644 --- a/src/lib/components/layout/Sidebar/RecursiveFolder.svelte +++ b/src/lib/components/layout/Sidebar/RecursiveFolder.svelte @@ -206,6 +206,10 @@ } catch (error) { console.log('Error parsing dataTransfer:', error); } + + // Only process the first non-file item; all share the same + // text/plain payload, so continuing would duplicate the move. + break; } } } @@ -243,6 +247,7 @@ id: folderId }) ); + event.dataTransfer.setData('application/x-open-webui-drag', ''); dragged = true; folderElement.style.opacity = '0.5'; // Optional: Visual cue to show it's being dragged