mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-19 09:50:15 +01:00
🔍 refactor: Search & Message Retrieval (#6903)
* refactor: conversation search fetch * refactor: Message and Convo fetch with paramters and search * refactor: update search states and cleanup old store states * refactor: re-enable search API; fix: search conversation * fix: message's convo fetch * fix: redirect when searching * chore: use logger instead of console * fix: search message loading * feat: small optimizations * feat(Message): remove cache for search path * fix: handle delete of all archivedConversation and sharedLinks * chore: cleanup * fix: search messages * style: update ConvoOptions styles * refactor(SearchButtons): streamline conversation fetching and remove unused state * fix: ensure messages are invalidated after fetching conversation data * fix: add iconURL to conversation query selection --------- Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
parent
851938e7a6
commit
88f4ad7c47
30 changed files with 489 additions and 576 deletions
|
|
@ -1,7 +1,7 @@
|
|||
export { default as useSearch } from './useSearch';
|
||||
export { default as usePresets } from './usePresets';
|
||||
export { default as useGetSender } from './useGetSender';
|
||||
export { default as useDefaultConvo } from './useDefaultConvo';
|
||||
export { default as useSearchEnabled } from './useSearchEnabled';
|
||||
export { default as useGenerateConvo } from './useGenerateConvo';
|
||||
export { default as useDebouncedInput } from './useDebouncedInput';
|
||||
export { default as useBookmarkSuccess } from './useBookmarkSuccess';
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ const useNavigateToConvo = (index = 0) => {
|
|||
dataService.getConversationById(conversationId),
|
||||
);
|
||||
logger.log('conversation', 'Fetched fresh conversation data', data);
|
||||
await queryClient.invalidateQueries([QueryKeys.messages, conversationId]);
|
||||
setConversation(data);
|
||||
} catch (error) {
|
||||
console.error('Error fetching conversation data on navigation', error);
|
||||
|
|
@ -38,6 +39,7 @@ const useNavigateToConvo = (index = 0) => {
|
|||
const navigateToConvo = (
|
||||
conversation?: TConversation | null,
|
||||
_resetLatestMessage = true,
|
||||
/** Likely need to remove this since it happens after fetching conversation data */
|
||||
invalidateMessages = false,
|
||||
) => {
|
||||
if (!conversation) {
|
||||
|
|
|
|||
|
|
@ -1,102 +0,0 @@
|
|||
import { useEffect, useCallback, useState } from 'react';
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { useNavigate, useLocation } from 'react-router-dom';
|
||||
import type { UseInfiniteQueryResult } from '@tanstack/react-query';
|
||||
import type { SearchConversationListResponse } from 'librechat-data-provider';
|
||||
import { useSearchInfiniteQuery, useGetSearchEnabledQuery } from '~/data-provider';
|
||||
import useNewConvo from '~/hooks/useNewConvo';
|
||||
import store from '~/store';
|
||||
|
||||
export interface UseSearchMessagesResult {
|
||||
searchQuery: string;
|
||||
searchQueryRes: UseInfiniteQueryResult<SearchConversationListResponse, unknown> | undefined;
|
||||
}
|
||||
|
||||
export default function useSearchMessages({
|
||||
isAuthenticated,
|
||||
}: {
|
||||
isAuthenticated: boolean;
|
||||
}): UseSearchMessagesResult {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const { switchToConversation } = useNewConvo();
|
||||
const searchPlaceholderConversation = useCallback(() => {
|
||||
switchToConversation({
|
||||
conversationId: 'search',
|
||||
title: 'Search',
|
||||
endpoint: null,
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
});
|
||||
}, [switchToConversation]);
|
||||
|
||||
const searchQuery = useRecoilValue(store.searchQuery);
|
||||
const setIsSearchEnabled = useSetRecoilState(store.isSearchEnabled);
|
||||
|
||||
const [debouncedSearchQuery, setDebouncedSearchQuery] = useState(searchQuery);
|
||||
|
||||
useEffect(() => {
|
||||
const handler = setTimeout(() => {
|
||||
setDebouncedSearchQuery(searchQuery);
|
||||
}, 350); // 350ms debounce
|
||||
return () => clearTimeout(handler);
|
||||
}, [searchQuery]);
|
||||
|
||||
const searchEnabledQuery = useGetSearchEnabledQuery({ enabled: isAuthenticated });
|
||||
const searchQueryRes = useSearchInfiniteQuery(
|
||||
{ nextCursor: null, search: debouncedSearchQuery, pageSize: 20 },
|
||||
{ enabled: isAuthenticated && !!debouncedSearchQuery },
|
||||
) as UseInfiniteQueryResult<SearchConversationListResponse, unknown> | undefined;
|
||||
|
||||
useEffect(() => {
|
||||
if (searchQuery && searchQuery.length > 0) {
|
||||
navigate('/search', { replace: true });
|
||||
return;
|
||||
}
|
||||
|
||||
if (location.pathname && location.pathname.includes('/c/')) {
|
||||
return;
|
||||
}
|
||||
navigate('/c/new', { replace: true });
|
||||
/* Disabled eslint rule because we don't want to run this effect when location changes */
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [navigate, searchQuery]);
|
||||
|
||||
useEffect(() => {
|
||||
if (searchEnabledQuery.data === true) {
|
||||
setIsSearchEnabled(searchEnabledQuery.data);
|
||||
} else if (searchEnabledQuery.isError) {
|
||||
console.error('Failed to get search enabled', searchEnabledQuery.error);
|
||||
}
|
||||
}, [
|
||||
searchEnabledQuery.data,
|
||||
searchEnabledQuery.error,
|
||||
searchEnabledQuery.isError,
|
||||
setIsSearchEnabled,
|
||||
]);
|
||||
|
||||
const onSearchSuccess = useCallback(
|
||||
() => searchPlaceholderConversation(),
|
||||
[searchPlaceholderConversation],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
// we use isInitialLoading here instead of isLoading because query is disabled by default
|
||||
if (searchQueryRes?.data) {
|
||||
onSearchSuccess();
|
||||
}
|
||||
}, [searchQueryRes?.data, searchQueryRes?.isInitialLoading, onSearchSuccess]);
|
||||
|
||||
const setIsSearchTyping = useSetRecoilState(store.isSearchTyping);
|
||||
|
||||
useEffect(() => {
|
||||
if (!searchQueryRes?.isLoading && !searchQueryRes?.isFetching) {
|
||||
setIsSearchTyping(false);
|
||||
}
|
||||
}, [searchQueryRes?.isLoading, searchQueryRes?.isFetching, setIsSearchTyping]);
|
||||
|
||||
return {
|
||||
searchQuery,
|
||||
searchQueryRes,
|
||||
};
|
||||
}
|
||||
20
client/src/hooks/Conversations/useSearchEnabled.ts
Normal file
20
client/src/hooks/Conversations/useSearchEnabled.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import { useEffect } from 'react';
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { useGetSearchEnabledQuery } from '~/data-provider';
|
||||
import { logger } from '~/utils';
|
||||
import store from '~/store';
|
||||
|
||||
export default function useSearchEnabled(isAuthenticated: boolean) {
|
||||
const setSearch = useSetRecoilState(store.search);
|
||||
const searchEnabledQuery = useGetSearchEnabledQuery({ enabled: isAuthenticated });
|
||||
|
||||
useEffect(() => {
|
||||
if (searchEnabledQuery.data === true) {
|
||||
setSearch((prev) => ({ ...prev, enabled: searchEnabledQuery.data }));
|
||||
} else if (searchEnabledQuery.isError) {
|
||||
logger.error('Failed to get search enabled: ', searchEnabledQuery.error);
|
||||
}
|
||||
}, [searchEnabledQuery.data, searchEnabledQuery.error, searchEnabledQuery.isError, setSearch]);
|
||||
|
||||
return searchEnabledQuery;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue