mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-19 09:50:15 +01:00
🔃 refactor: Streamline Navigation, Message Loading UX (#7118)
* chore: fix logging for illegal target endpoints in getEndpointFromSetup * fix: prevent querying agent by ID for ephemeral agents * refactor: reorder variable declarations in MessagesView for clarity * fix: localize 'nothing found' message in MessagesView * refactor: streamline navigation logic and enhance loading spinner component in ChatView * refactor: simplify loading spinner logic in ChatView component * fix: ensure message queries are invalidated after new conversation creation in HeaderNewChat, MobileNav, and NewChat components * 🐛 First run dev mode will have error occur. 🐛 First run dev mode will have error occur. * fix font-size localstorage presist bug * Don't ping meilisearch if the search is disabled via env var * simplify logic in search/enable endpoint * refactor: simplify enable endpoint condition check * feat: add useIdChangeEffect hook and integrate it into ChatRoute --------- Co-authored-by: Ne0 <20765145+zeeklog@users.noreply.github.com> Co-authored-by: TinyTin <garychangcn@hotmail.com> Co-authored-by: Denis Palnitsky <denis.palnitsky@zendesk.com>
This commit is contained in:
parent
fc30482f65
commit
0e8041bcac
17 changed files with 80 additions and 131 deletions
|
|
@ -18,7 +18,7 @@ export default function useSelectAgent() {
|
|||
);
|
||||
|
||||
const agentQuery = useGetAgentByIdQuery(selectedAgentId ?? '', {
|
||||
enabled: !!(selectedAgentId ?? ''),
|
||||
enabled: !!(selectedAgentId ?? '') && selectedAgentId !== Constants.EPHEMERAL_AGENT_ID,
|
||||
});
|
||||
|
||||
const updateConversation = useCallback(
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@ export { default as useChatHelpers } from './useChatHelpers';
|
|||
export { default as useAddedHelpers } from './useAddedHelpers';
|
||||
export { default as useAddedResponse } from './useAddedResponse';
|
||||
export { default as useChatFunctions } from './useChatFunctions';
|
||||
export { default as useIdChangeEffect } from './useIdChangeEffect';
|
||||
export { default as useFocusChatEffect } from './useFocusChatEffect';
|
||||
|
|
|
|||
21
client/src/hooks/Chat/useIdChangeEffect.ts
Normal file
21
client/src/hooks/Chat/useIdChangeEffect.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import { useEffect, useRef } from 'react';
|
||||
import { useResetRecoilState } from 'recoil';
|
||||
import { logger } from '~/utils';
|
||||
import store from '~/store';
|
||||
|
||||
/**
|
||||
* Hook to reset artifacts when the conversation ID changes
|
||||
* @param conversationId - The current conversation ID
|
||||
*/
|
||||
export default function useIdChangeEffect(conversationId: string) {
|
||||
const lastConvoId = useRef<string | null>(null);
|
||||
const resetArtifacts = useResetRecoilState(store.artifactsState);
|
||||
|
||||
useEffect(() => {
|
||||
if (conversationId !== lastConvoId.current) {
|
||||
logger.log('conversation', 'Conversation ID change');
|
||||
resetArtifacts();
|
||||
}
|
||||
lastConvoId.current = conversationId;
|
||||
}, [conversationId, resetArtifacts]);
|
||||
}
|
||||
|
|
@ -1,13 +1,7 @@
|
|||
import { useSetRecoilState } from 'recoil';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useSetRecoilState, useResetRecoilState } from 'recoil';
|
||||
import {
|
||||
QueryKeys,
|
||||
Constants,
|
||||
dataService,
|
||||
EModelEndpoint,
|
||||
LocalStorageKeys,
|
||||
} from 'librechat-data-provider';
|
||||
import { QueryKeys, Constants } from 'librechat-data-provider';
|
||||
import type { TConversation, TEndpointsConfig, TModelsConfig } from 'librechat-data-provider';
|
||||
import { buildDefaultConvo, getDefaultEndpoint, getEndpointField, logger } from '~/utils';
|
||||
import store from '~/store';
|
||||
|
|
@ -16,48 +10,28 @@ const useNavigateToConvo = (index = 0) => {
|
|||
const navigate = useNavigate();
|
||||
const queryClient = useQueryClient();
|
||||
const clearAllConversations = store.useClearConvoState();
|
||||
const resetArtifacts = useResetRecoilState(store.artifactsState);
|
||||
const setSubmission = useSetRecoilState(store.submissionByIndex(index));
|
||||
const clearAllLatestMessages = store.useClearLatestMessages(`useNavigateToConvo ${index}`);
|
||||
const { hasSetConversation, setConversation } = store.useCreateConversationAtom(index);
|
||||
|
||||
const fetchFreshData = async (conversationId?: string | null) => {
|
||||
if (!conversationId) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const data = await queryClient.fetchQuery([QueryKeys.conversation, conversationId], () =>
|
||||
dataService.getConversationById(conversationId),
|
||||
);
|
||||
logger.log('conversation', 'Fetched fresh conversation data', data);
|
||||
await queryClient.invalidateQueries([QueryKeys.messages, conversationId]);
|
||||
setConversation(data);
|
||||
navigate(`/c/${conversationId ?? Constants.NEW_CONVO}`, { state: { focusChat: true } });
|
||||
} catch (error) {
|
||||
console.error('Error fetching conversation data on navigation', error);
|
||||
}
|
||||
};
|
||||
|
||||
const navigateToConvo = (
|
||||
conversation?: TConversation | null,
|
||||
_resetLatestMessage = true,
|
||||
/** Likely need to remove this since it happens after fetching conversation data */
|
||||
invalidateMessages = false,
|
||||
options?: {
|
||||
resetLatestMessage?: boolean;
|
||||
currentConvoId?: string;
|
||||
},
|
||||
) => {
|
||||
if (!conversation) {
|
||||
logger.warn('conversation', 'Conversation not provided to `navigateToConvo`');
|
||||
return;
|
||||
}
|
||||
const { resetLatestMessage = true, currentConvoId } = options || {};
|
||||
logger.log('conversation', 'Navigating to conversation', conversation);
|
||||
hasSetConversation.current = true;
|
||||
setSubmission(null);
|
||||
if (_resetLatestMessage) {
|
||||
if (resetLatestMessage) {
|
||||
clearAllLatestMessages();
|
||||
}
|
||||
if (invalidateMessages && conversation.conversationId != null && conversation.conversationId) {
|
||||
queryClient.setQueryData([QueryKeys.messages, Constants.NEW_CONVO], []);
|
||||
queryClient.invalidateQueries([QueryKeys.messages, conversation.conversationId]);
|
||||
}
|
||||
|
||||
let convo = { ...conversation };
|
||||
const endpointsConfig = queryClient.getQueryData<TEndpointsConfig>([QueryKeys.endpoints]);
|
||||
|
|
@ -84,51 +58,13 @@ const useNavigateToConvo = (index = 0) => {
|
|||
});
|
||||
}
|
||||
clearAllConversations(true);
|
||||
resetArtifacts();
|
||||
setConversation(convo);
|
||||
if (convo.conversationId !== Constants.NEW_CONVO && convo.conversationId) {
|
||||
queryClient.invalidateQueries([QueryKeys.conversation, convo.conversationId]);
|
||||
fetchFreshData(convo.conversationId);
|
||||
} else {
|
||||
navigate(`/c/${convo.conversationId ?? Constants.NEW_CONVO}`, { state: { focusChat: true } });
|
||||
}
|
||||
};
|
||||
|
||||
const navigateWithLastTools = (
|
||||
conversation?: TConversation | null,
|
||||
_resetLatestMessage?: boolean,
|
||||
invalidateMessages?: boolean,
|
||||
) => {
|
||||
if (!conversation) {
|
||||
logger.warn('conversation', 'Conversation not provided to `navigateToConvo`');
|
||||
return;
|
||||
}
|
||||
// set conversation to the new conversation
|
||||
if (conversation.endpoint === EModelEndpoint.gptPlugins) {
|
||||
let lastSelectedTools = [];
|
||||
try {
|
||||
lastSelectedTools =
|
||||
JSON.parse(localStorage.getItem(LocalStorageKeys.LAST_TOOLS) ?? '') ?? [];
|
||||
} catch (e) {
|
||||
logger.error('conversation', 'Error parsing last selected tools', e);
|
||||
}
|
||||
const hasTools = (conversation.tools?.length ?? 0) > 0;
|
||||
navigateToConvo(
|
||||
{
|
||||
...conversation,
|
||||
tools: hasTools ? conversation.tools : lastSelectedTools,
|
||||
},
|
||||
_resetLatestMessage,
|
||||
invalidateMessages,
|
||||
);
|
||||
} else {
|
||||
navigateToConvo(conversation, _resetLatestMessage, invalidateMessages);
|
||||
}
|
||||
queryClient.setQueryData([QueryKeys.messages, currentConvoId], []);
|
||||
navigate(`/c/${convo.conversationId ?? Constants.NEW_CONVO}`, { state: { focusChat: true } });
|
||||
};
|
||||
|
||||
return {
|
||||
navigateToConvo,
|
||||
navigateWithLastTools,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -58,10 +58,14 @@ export const ThemeProvider = ({ initialTheme, children }) => {
|
|||
if (fontSize == null) {
|
||||
setFontSize('text-base');
|
||||
applyFontSize('text-base');
|
||||
localStorage.setItem('fontSize', 'text-base');
|
||||
localStorage.setItem('fontSize', JSON.stringify('text-base'));
|
||||
return;
|
||||
}
|
||||
applyFontSize(JSON.parse(fontSize));
|
||||
try {
|
||||
applyFontSize(JSON.parse(fontSize));
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
// Reason: This effect should only run once, and `setFontSize` is a stable function
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue