diff --git a/surfsense_backend/app/routes/chats_routes.py b/surfsense_backend/app/routes/chats_routes.py index 2813201e7..26af68149 100644 --- a/surfsense_backend/app/routes/chats_routes.py +++ b/surfsense_backend/app/routes/chats_routes.py @@ -319,15 +319,19 @@ async def read_chats( "You don't have permission to read chats in this search space", ) # Select specific fields excluding messages - query = select( - Chat.id, - Chat.type, - Chat.title, - Chat.initial_connectors, - Chat.search_space_id, - Chat.created_at, - Chat.state_version, - ).filter(Chat.search_space_id == search_space_id) + query = ( + select( + Chat.id, + Chat.type, + Chat.title, + Chat.initial_connectors, + Chat.search_space_id, + Chat.created_at, + Chat.state_version, + ) + .filter(Chat.search_space_id == search_space_id) + .order_by(Chat.created_at.desc()) + ) else: # Get chats from all search spaces user has membership in query = ( @@ -343,6 +347,7 @@ async def read_chats( .join(SearchSpace) .join(SearchSpaceMembership) .filter(SearchSpaceMembership.user_id == user.id) + .order_by(Chat.created_at.desc()) ) result = await session.execute(query.offset(skip).limit(limit)) diff --git a/surfsense_web/atoms/chats/chat-mutation.atoms.ts b/surfsense_web/atoms/chats/chat-mutation.atoms.ts index 798bfcd2f..c761a706f 100644 --- a/surfsense_web/atoms/chats/chat-mutation.atoms.ts +++ b/surfsense_web/atoms/chats/chat-mutation.atoms.ts @@ -27,12 +27,21 @@ export const deleteChatMutationAtom = atomWithMutation((get) => { onSuccess: (_, request: DeleteChatRequest) => { toast.success("Chat deleted successfully"); + // Optimistically update the current query queryClient.setQueryData( cacheKeys.chats.globalQueryParams(chatsQueryParams), (oldData: ChatSummary[]) => { - return oldData.filter((chat) => chat.id !== request.id); + return oldData?.filter((chat) => chat.id !== request.id) ?? []; } ); + // Invalidate all chat queries to ensure consistency across components + queryClient.invalidateQueries({ + queryKey: ["chats"], + }); + // Also invalidate the "all-chats" query used by AllChatsSidebar + queryClient.invalidateQueries({ + queryKey: ["all-chats"], + }); }, }; }); @@ -50,8 +59,14 @@ export const createChatMutationAtom = atomWithMutation((get) => { }, onSuccess: () => { + // Invalidate ALL chat queries to ensure sidebar and other components refresh + // Using a partial key match to avoid stale closure issues with specific query params queryClient.invalidateQueries({ - queryKey: cacheKeys.chats.globalQueryParams(chatsQueryParams), + queryKey: ["chats"], + }); + // Also invalidate the "all-chats" query used by AllChatsSidebar + queryClient.invalidateQueries({ + queryKey: ["all-chats"], }); }, }; diff --git a/surfsense_web/components/sidebar/AppSidebarProvider.tsx b/surfsense_web/components/sidebar/AppSidebarProvider.tsx index bb7ccedc9..393d86b74 100644 --- a/surfsense_web/components/sidebar/AppSidebarProvider.tsx +++ b/surfsense_web/components/sidebar/AppSidebarProvider.tsx @@ -58,7 +58,7 @@ export function AppSidebarProvider({ useEffect(() => { setChatsQueryParams((prev) => ({ ...prev, search_space_id: searchSpaceId, skip: 0, limit: 4 })); - }, [searchSpaceId]); + }, [searchSpaceId, setChatsQueryParams]); const { data: searchSpace, diff --git a/surfsense_web/lib/query-client/cache-keys.ts b/surfsense_web/lib/query-client/cache-keys.ts index a8eecb605..7eae21e05 100644 --- a/surfsense_web/lib/query-client/cache-keys.ts +++ b/surfsense_web/lib/query-client/cache-keys.ts @@ -10,7 +10,14 @@ export const cacheKeys = { chats: { activeChat: (chatId: string) => ["active-chat", chatId] as const, globalQueryParams: (queries: GetChatsRequest["queryParams"]) => - ["chats", ...(queries ? Object.values(queries) : [])] as const, + [ + "chats", + queries?.search_space_id, + queries?.limit, + queries?.skip, + queries?.page, + queries?.page_size, + ] as const, }, podcasts: { globalQueryParams: (queries: GetPodcastsRequest["queryParams"]) =>