From db92ef292fe74580b256164d7597bad3a6a6776b Mon Sep 17 00:00:00 2001 From: G30 <50341825+silentoplayz@users.noreply.github.com> Date: Sun, 26 Jul 2026 18:43:34 -0400 Subject: [PATCH] fix: unarchive chats moved into folders and refresh sidebar folders after menu moves (#27485) --- backend/open_webui/models/chats.py | 5 +++++ src/lib/components/chat/Chat.svelte | 4 +++- src/lib/components/layout/Sidebar.svelte | 13 ++++++++++++- src/lib/stores/chatList.ts | 18 ++++++++++++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index b2e252f588..2162755b49 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -1885,6 +1885,11 @@ class ChatTable: chat.updated_at = int(time.time()) chat.last_read_at = int(time.time()) chat.pinned = False + if folder_id is not None: + # Folder listings only show unarchived chats, so moving an archived + # chat into a folder would otherwise have no visible effect: the chat + # stays in the archived list and never appears in the folder. + chat.archived = False await session.commit() return ChatModel.model_validate(chat) except Exception: diff --git a/src/lib/components/chat/Chat.svelte b/src/lib/components/chat/Chat.svelte index 4f0cfa9ee3..f1bc26ffd9 100644 --- a/src/lib/components/chat/Chat.svelte +++ b/src/lib/components/chat/Chat.svelte @@ -48,7 +48,7 @@ chatRequestQueues, desktopEvent } from '$lib/stores'; - import { refreshChatList } from '$lib/stores/chatList'; + import { refreshChatList, refreshFolderChatLists } from '$lib/stores/chatList'; import { WEBUI_API_BASE_URL } from '$lib/constants'; @@ -3566,6 +3566,7 @@ if (res) { await refreshChatList(localStorage.token, { refreshPinned: true }); + await refreshFolderChatLists(); toast.success($i18n.t('Chat moved successfully')); } @@ -3580,6 +3581,7 @@ initNewChat(); await goto('/'); await refreshChatList(localStorage.token, { refreshPinned: true }); + await refreshFolderChatLists(); toast.success($i18n.t('Chat archived.')); } catch (error) { console.error('Error archiving chat:', error); diff --git a/src/lib/components/layout/Sidebar.svelte b/src/lib/components/layout/Sidebar.svelte index 63abd53729..6d6a2896f7 100644 --- a/src/lib/components/layout/Sidebar.svelte +++ b/src/lib/components/layout/Sidebar.svelte @@ -27,7 +27,12 @@ WEBUI_NAME, sidebarWidth } from '$lib/stores'; - import { loadNextChatListPage, refreshChatList, setChatActive } from '$lib/stores/chatList'; + import { + loadNextChatListPage, + refreshChatList, + registerFolderRefreshHandler, + setChatActive + } from '$lib/stores/chatList'; import { onMount, getContext, tick, onDestroy } from 'svelte'; const i18n = getContext('i18n'); @@ -649,6 +654,10 @@ socketInstance?.on('events', chatActiveEventHandler); socketInstance?.on('connect', refreshChatRows); + const unregisterFolderRefreshHandler = registerFolderRefreshHandler(() => + Promise.all(Object.values(folderRegistry).map((folder) => folder?.setFolderItems?.())) + ); + await tick(); initPinnedMenuSortable(); @@ -672,6 +681,8 @@ socketInstance?.off('events', chatActiveEventHandler); socketInstance?.off('connect', refreshChatRows); + + unregisterFolderRefreshHandler(); }; }); diff --git a/src/lib/stores/chatList.ts b/src/lib/stores/chatList.ts index 55b7aa1162..7baddd2262 100644 --- a/src/lib/stores/chatList.ts +++ b/src/lib/stores/chatList.ts @@ -61,6 +61,24 @@ export const refreshChatList = async ( return { accepted: true, allLoaded }; }; +// The sidebar's folders keep their chat lists in local component state, refreshed +// through a registry of per-folder callbacks that only the sidebar can reach. +// Handlers registered here let other components (e.g. the open chat's menu) +// request that refresh without a reference to the sidebar. +type FolderRefreshHandler = () => unknown; +const folderRefreshHandlers = new Set(); + +export const registerFolderRefreshHandler = (handler: FolderRefreshHandler) => { + folderRefreshHandlers.add(handler); + return () => { + folderRefreshHandlers.delete(handler); + }; +}; + +export const refreshFolderChatLists = async () => { + await Promise.all([...folderRefreshHandlers].map((handler) => handler())); +}; + export const loadNextChatListPage = async (token: string = ''): Promise => { if (!paginationReady || allLoaded || loadingNextPage) { return { accepted: false, allLoaded };