From 6e8ca967999967e1a22c18f658e51fbaee542354 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 25 May 2025 01:23:12 +0400 Subject: [PATCH] enh: archived chats modal --- backend/open_webui/models/chats.py | 13 +- backend/open_webui/routers/chats.py | 14 +- src/lib/apis/chats/index.ts | 15 +- .../layout/ArchivedChatsModal.svelte | 21 ++- src/lib/components/layout/ChatsModal.svelte | 140 +++++++++++++----- 5 files changed, 153 insertions(+), 50 deletions(-) diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index 9d28cc35a..437bf1e22 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -392,7 +392,18 @@ class ChatTable: if query_key: query = query.filter(Chat.title.ilike(f"%{query_key}%")) - query = query.order_by(Chat.updated_at.desc()) + order_by = filter.get("order_by") + direction = filter.get("direction") + + if order_by and direction and getattr(Chat, order_by): + if direction.lower() == "asc": + query = query.order_by(getattr(Chat, order_by).asc()) + elif direction.lower() == "desc": + query = query.order_by(getattr(Chat, order_by).desc()) + else: + raise ValueError("Invalid direction for ordering") + else: + query = query.order_by(Chat.updated_at.desc()) if skip: query = query.offset(skip) diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index 4bf06bd22..8dc049aec 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -269,6 +269,8 @@ async def get_all_user_chats_in_db(user=Depends(get_admin_user)): async def get_archived_session_user_chat_list( page: Optional[int] = None, query: Optional[str] = None, + order_by: Optional[str] = None, + direction: Optional[str] = None, user=Depends(get_verified_user), ): if page is None: @@ -277,13 +279,19 @@ async def get_archived_session_user_chat_list( limit = 60 skip = (page - 1) * limit + filter = {} + if query: + filter["query"] = query + if order_by: + filter["order_by"] = order_by + if direction: + filter["direction"] = direction + chat_list = [ ChatTitleIdResponse(**chat.model_dump()) for chat in Chats.get_archived_chat_list_by_user_id( user.id, - { - "query": query if query else None, - }, + filter=filter, skip=skip, limit=limit, ) diff --git a/src/lib/apis/chats/index.ts b/src/lib/apis/chats/index.ts index 2906f3485..756128613 100644 --- a/src/lib/apis/chats/index.ts +++ b/src/lib/apis/chats/index.ts @@ -145,13 +145,22 @@ export const getChatListByUserId = async (token: string = '', userId: string) => })); }; -export const getArchivedChatList = async (token: string = '', page: number = 1, query?: string) => { +export const getArchivedChatList = async ( + token: string = '', + page: number = 1, + filter?: object +) => { let error = null; const searchParams = new URLSearchParams(); searchParams.append('page', `${page}`); - if (query) { - searchParams.append('query', query); + + if (filter) { + Object.entries(filter).forEach(([key, value]) => { + if (value !== undefined && value !== null) { + searchParams.append(key, value.toString()); + } + }); } const res = await fetch(`${WEBUI_API_BASE_URL}/chats/archived?${searchParams.toString()}`, { diff --git a/src/lib/components/layout/ArchivedChatsModal.svelte b/src/lib/components/layout/ArchivedChatsModal.svelte index 8e762f8de..f2f927feb 100644 --- a/src/lib/components/layout/ArchivedChatsModal.svelte +++ b/src/lib/components/layout/ArchivedChatsModal.svelte @@ -18,6 +18,8 @@ let page = 1; let query = ''; + let orderBy = 'updated_at'; + let direction = 'desc'; let allChatsLoaded = false; let chatListLoading = false; @@ -25,7 +27,14 @@ let showUnarchiveAllConfirmDialog = false; - $: if (query !== null) { + let filter = {}; + $: filter = { + ...(query ? { query } : {}), + ...(orderBy ? { order_by: orderBy } : {}), + ...(direction ? { direction } : {}) + }; + + $: if (filter !== null) { searchHandler(); } @@ -40,10 +49,10 @@ chatList = null; if (query === '') { - chatList = await getArchivedChatList(localStorage.token, page); + chatList = await getArchivedChatList(localStorage.token, page, filter); } else { searchDebounceTimeout = setTimeout(async () => { - chatList = await getArchivedChatList(localStorage.token, page, query); + chatList = await getArchivedChatList(localStorage.token, page, filter); }, 500); } @@ -61,9 +70,9 @@ let newChatList = []; if (query) { - newChatList = await getArchivedChatList(localStorage.token, page, query); + newChatList = await getArchivedChatList(localStorage.token, page, filter); } else { - newChatList = await getArchivedChatList(localStorage.token, page); + newChatList = await getArchivedChatList(localStorage.token, page, filter); } // once the bottom of the list has been reached (no results) there is no need to continue querying @@ -124,6 +133,8 @@ { + if (orderBy === key) { + direction = direction === 'asc' ? 'desc' : 'asc'; + } else { + orderBy = key; + direction = 'asc'; + } + }; + const deleteHandler = async (chatId) => { const res = await deleteChatById(localStorage.token, chatId).catch((error) => { toast.error(`${error}`); @@ -111,6 +125,54 @@
{#if chatList}
+ {#if chatList.length > 0} +
+ + +
+ {/if}
{#if chatList.length === 0}
0 && chat.time_range !== chatList[idx - 1].time_range)} + {#if (idx === 0 || (idx > 0 && chat.time_range !== chatList[idx - 1].time_range)) && chat?.time_range}
- (show = false)}> + (show = false)}>
{chat?.title}
-
- {dayjs(chat?.updated_at * 1000).calendar()} -
+
+ -
- {#if unarchiveHandler} - +
+ {#if unarchiveHandler} + + + + {/if} + + - {/if} - - - - +
{/each}