From 75208935d7d6475342fcd10208daac9640baf8e5 Mon Sep 17 00:00:00 2001 From: Timothy Jaeryang Baek Date: Sun, 25 May 2025 01:44:53 +0400 Subject: [PATCH] refac: user chat list modal --- backend/open_webui/models/chats.py | 23 +- backend/open_webui/routers/chats.py | 23 +- src/lib/apis/chats/index.ts | 41 ++- .../components/admin/Users/UserList.svelte | 5 +- .../Users/UserList/UserChatsModal.svelte | 261 ++++++------------ src/lib/components/layout/ChatsModal.svelte | 2 +- 6 files changed, 166 insertions(+), 189 deletions(-) diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index 437bf1e22..0ac53a023 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -417,6 +417,7 @@ class ChatTable: self, user_id: str, include_archived: bool = False, + filter: Optional[dict] = None, skip: int = 0, limit: int = 50, ) -> list[ChatModel]: @@ -425,7 +426,23 @@ class ChatTable: if not include_archived: query = query.filter_by(archived=False) - query = query.order_by(Chat.updated_at.desc()) + if filter: + query_key = filter.get("query") + if query_key: + query = query.filter(Chat.title.ilike(f"%{query_key}%")) + + 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) @@ -566,7 +583,9 @@ class ChatTable: search_text = search_text.lower().strip() if not search_text: - return self.get_chat_list_by_user_id(user_id, include_archived, skip, limit) + return self.get_chat_list_by_user_id( + user_id, include_archived, filter={}, skip=skip, limit=limit + ) search_text_words = search_text.split(" ") diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index 8dc049aec..98628642c 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -76,17 +76,34 @@ async def delete_all_user_chats(request: Request, user=Depends(get_verified_user @router.get("/list/user/{user_id}", response_model=list[ChatTitleIdResponse]) async def get_user_chat_list_by_user_id( user_id: str, + page: Optional[int] = None, + query: Optional[str] = None, + order_by: Optional[str] = None, + direction: Optional[str] = None, user=Depends(get_admin_user), - skip: int = 0, - limit: int = 50, ): if not ENABLE_ADMIN_CHAT_ACCESS: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) + + if page is None: + page = 1 + + 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 + return Chats.get_chat_list_by_user_id( - user_id, include_archived=True, skip=skip, limit=limit + user_id, include_archived=True, filter=filter, skip=skip, limit=limit ) diff --git a/src/lib/apis/chats/index.ts b/src/lib/apis/chats/index.ts index 756128613..9d24b3971 100644 --- a/src/lib/apis/chats/index.ts +++ b/src/lib/apis/chats/index.ts @@ -111,17 +111,37 @@ export const getChatList = async (token: string = '', page: number | null = null })); }; -export const getChatListByUserId = async (token: string = '', userId: string) => { +export const getChatListByUserId = async ( + token: string = '', + userId: string, + page: number = 1, + filter?: object +) => { let error = null; - const res = await fetch(`${WEBUI_API_BASE_URL}/chats/list/user/${userId}`, { - method: 'GET', - headers: { - Accept: 'application/json', - 'Content-Type': 'application/json', - ...(token && { authorization: `Bearer ${token}` }) + const searchParams = new URLSearchParams(); + + searchParams.append('page', `${page}`); + + 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/list/user/${userId}?${searchParams.toString()}`, + { + method: 'GET', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/json', + ...(token && { authorization: `Bearer ${token}` }) + } } - }) + ) .then(async (res) => { if (!res.ok) throw await res.json(); return res.json(); @@ -188,7 +208,10 @@ export const getArchivedChatList = async ( throw error; } - return res; + return res.map((chat) => ({ + ...chat, + time_range: getTimeRange(chat.updated_at) + })); }; export const getAllChats = async (token: string) => { diff --git a/src/lib/components/admin/Users/UserList.svelte b/src/lib/components/admin/Users/UserList.svelte index 61816780b..31eec1fbd 100644 --- a/src/lib/components/admin/Users/UserList.svelte +++ b/src/lib/components/admin/Users/UserList.svelte @@ -165,7 +165,10 @@ getUserList(); }} /> - + +{#if selectedUser} + +{/if} {#if ($config?.license_metadata?.seats ?? null) !== null && total && total > $config?.license_metadata?.seats}
diff --git a/src/lib/components/admin/Users/UserList/UserChatsModal.svelte b/src/lib/components/admin/Users/UserList/UserChatsModal.svelte index ca9edd261..83856a4c2 100644 --- a/src/lib/components/admin/Users/UserList/UserChatsModal.svelte +++ b/src/lib/components/admin/Users/UserList/UserChatsModal.svelte @@ -1,10 +1,10 @@ - { - if (chatToDelete) { - deleteChatHandler(chatToDelete); - chatToDelete = null; - } + { + init(); }} -/> - - -
-
- {$i18n.t("{{user}}'s Chats", { user: user.name })} -
- -
- -
-
- {#if chats} - {#if chats.length > 0} -
-
- - - - - - - - - {#each chats.sort((a, b) => { - if (a[sortKey] < b[sortKey]) return sortOrder === 'asc' ? -1 : 1; - if (a[sortKey] > b[sortKey]) return sortOrder === 'asc' ? 1 : -1; - return 0; - }) as chat, idx} - - - - - - - - {/each} - -
setSortKey('title')} - > - {$i18n.t('Title')} - {#if sortKey === 'title'} - {sortOrder === 'asc' ? '▲' : '▼'} - {:else} - - {/if} - -
- -
- {chat.title} -
-
-
-
- - - -
-
-
- -
- {:else} -
- {user.name} - {$i18n.t('has no conversations.')} -
- {/if} - {:else} - - {/if} -
-
-
+ loadHandler={loadMoreChats} +>
diff --git a/src/lib/components/layout/ChatsModal.svelte b/src/lib/components/layout/ChatsModal.svelte index df9ab8078..e3cba7652 100644 --- a/src/lib/components/layout/ChatsModal.svelte +++ b/src/lib/components/layout/ChatsModal.svelte @@ -140,7 +140,7 @@ {#if chatList}
{#if chatList.length > 0} -
+