mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-04 14:57:42 +00:00
fix: Handle project search and stale ids
This commit is contained in:
parent
3d50d2619b
commit
b1addcad5d
2 changed files with 67 additions and 10 deletions
|
|
@ -151,6 +151,7 @@ const ProjectConversations: FC<ProjectConversationsProps> = ({
|
|||
const search = useRecoilValue(store.search);
|
||||
const isSmallScreen = useMediaQuery('(max-width: 768px)');
|
||||
const [expandedSectionId, setExpandedSectionId] = useState<string | null>(null);
|
||||
const isSearching = Boolean(search.debouncedQuery);
|
||||
|
||||
const projectSortBy = mode === 'recentProjects' ? 'lastConversationAt' : 'name';
|
||||
const projectSortDirection = mode === 'recentProjects' ? 'desc' : 'asc';
|
||||
|
|
@ -179,14 +180,14 @@ const ProjectConversations: FC<ProjectConversationsProps> = ({
|
|||
isLoading: isConversationsLoading,
|
||||
} = useConversationsInfiniteQuery(
|
||||
{
|
||||
projectId: expandedSectionId ?? undefined,
|
||||
projectId: isSearching ? undefined : (expandedSectionId ?? undefined),
|
||||
tags: tags.length === 0 ? undefined : tags,
|
||||
sortBy: chatSortBy,
|
||||
sortDirection: 'desc',
|
||||
search: search.debouncedQuery || undefined,
|
||||
},
|
||||
{
|
||||
enabled: isAuthenticated && isChatsExpanded && expandedSectionId != null,
|
||||
enabled: isAuthenticated && isChatsExpanded && (isSearching || expandedSectionId != null),
|
||||
staleTime: 30000,
|
||||
cacheTime: 300000,
|
||||
},
|
||||
|
|
@ -236,6 +237,29 @@ const ProjectConversations: FC<ProjectConversationsProps> = ({
|
|||
return items;
|
||||
}
|
||||
|
||||
if (isSearching) {
|
||||
if (isConversationsLoading) {
|
||||
items.push({ type: 'loading', key: 'loading-search-conversations' });
|
||||
return items;
|
||||
}
|
||||
|
||||
if (conversations.length === 0) {
|
||||
items.push({ type: 'empty', title: localize('com_ui_no_results_found') });
|
||||
return items;
|
||||
}
|
||||
|
||||
groupedConversations.forEach(([groupName, convos]) => {
|
||||
items.push({ type: 'date', groupName });
|
||||
convos.forEach((convo) => items.push({ type: 'convo', convo }));
|
||||
});
|
||||
|
||||
if (isFetchingNextConversationPage) {
|
||||
items.push({ type: 'loading', key: 'loading-more-search-conversations' });
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
sections.forEach((section) => {
|
||||
const isExpanded = expandedSectionId === section.id;
|
||||
items.push({ type: 'section', section, isExpanded });
|
||||
|
|
@ -278,6 +302,7 @@ const ProjectConversations: FC<ProjectConversationsProps> = ({
|
|||
}, [
|
||||
sections,
|
||||
isChatsExpanded,
|
||||
isSearching,
|
||||
expandedSectionId,
|
||||
isConversationsLoading,
|
||||
conversations.length,
|
||||
|
|
@ -309,18 +334,18 @@ const ProjectConversations: FC<ProjectConversationsProps> = ({
|
|||
return 'project-chats-header';
|
||||
}
|
||||
if (item.type === 'date') {
|
||||
return `project-date-${expandedSectionId}-${item.groupName}`;
|
||||
return `project-date-${isSearching ? 'search' : expandedSectionId}-${item.groupName}`;
|
||||
}
|
||||
if (item.type === 'convo') {
|
||||
return `project-convo-${item.convo.conversationId}`;
|
||||
}
|
||||
if (item.type === 'empty') {
|
||||
return `project-empty-${expandedSectionId}`;
|
||||
return `project-empty-${isSearching ? 'search' : expandedSectionId}`;
|
||||
}
|
||||
return item.key;
|
||||
},
|
||||
}),
|
||||
[expandedSectionId, rowHeight],
|
||||
[expandedSectionId, isSearching, rowHeight],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -372,7 +397,11 @@ const ProjectConversations: FC<ProjectConversationsProps> = ({
|
|||
if (!isChatsExpanded) {
|
||||
return;
|
||||
}
|
||||
if (expandedSectionId && conversationHasNextPage && !isFetchingNextConversationPage) {
|
||||
if (
|
||||
(isSearching || expandedSectionId) &&
|
||||
conversationHasNextPage &&
|
||||
!isFetchingNextConversationPage
|
||||
) {
|
||||
fetchNextConversationPage();
|
||||
return;
|
||||
}
|
||||
|
|
@ -381,6 +410,7 @@ const ProjectConversations: FC<ProjectConversationsProps> = ({
|
|||
}
|
||||
}, [
|
||||
expandedSectionId,
|
||||
isSearching,
|
||||
conversationHasNextPage,
|
||||
isFetchingNextConversationPage,
|
||||
fetchNextConversationPage,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import type { FilterQuery, Model, SortOrder } from 'mongoose';
|
||||
import { RetentionMode } from 'librechat-data-provider';
|
||||
import { isValidObjectIdString } from '~/utils/objectId';
|
||||
import { createTempChatExpirationDate } from '~/utils/tempChatRetention';
|
||||
import { buildRetentionVisibilityFilter, createFallbackRetentionDate } from '~/utils/retention';
|
||||
import { tenantSafeBulkWrite } from '~/utils/tenantBulkWrite';
|
||||
import logger from '~/config/winston';
|
||||
import type { AppConfig, IConversation } from '~/types';
|
||||
import type { AppConfig, IChatProjectDocument, IConversation } from '~/types';
|
||||
import {
|
||||
refreshChatProjectStatsForUser,
|
||||
updateChatProjectLastConversationForUser,
|
||||
|
|
@ -213,6 +214,26 @@ export function createConversationMethods(
|
|||
|
||||
const messages = await getMessages({ conversationId, user: userId }, '_id');
|
||||
const update: Record<string, unknown> = { ...convo, messages, user: userId };
|
||||
const unsetFields: Record<string, number> = { ...(metadata?.unsetFields ?? {}) };
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(update, 'chatProjectId') && update.chatProjectId) {
|
||||
const chatProjectId = typeof update.chatProjectId === 'string' ? update.chatProjectId : '';
|
||||
let isValidChatProject = isValidObjectIdString(chatProjectId);
|
||||
|
||||
if (isValidChatProject) {
|
||||
const ChatProject = mongoose.models.ChatProject as Model<IChatProjectDocument>;
|
||||
const project = await ChatProject.exists({
|
||||
_id: new mongoose.Types.ObjectId(chatProjectId),
|
||||
user: userId,
|
||||
});
|
||||
isValidChatProject = project != null;
|
||||
}
|
||||
|
||||
if (!isValidChatProject) {
|
||||
delete update.chatProjectId;
|
||||
unsetFields.chatProjectId = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (newConversationId) {
|
||||
update.conversationId = newConversationId;
|
||||
|
|
@ -253,8 +274,8 @@ export function createConversationMethods(
|
|||
}
|
||||
|
||||
const updateOperation: Record<string, unknown> = { $set: update };
|
||||
if (metadata?.unsetFields && Object.keys(metadata.unsetFields).length > 0) {
|
||||
updateOperation.$unset = metadata.unsetFields;
|
||||
if (Object.keys(unsetFields).length > 0) {
|
||||
updateOperation.$unset = unsetFields;
|
||||
}
|
||||
if (createdAtOnInsert) {
|
||||
updateOperation.$setOnInsert = { createdAt: createdAtOnInsert };
|
||||
|
|
@ -302,9 +323,15 @@ export function createConversationMethods(
|
|||
}
|
||||
|
||||
if (conversation.chatProjectId) {
|
||||
const isRetentionVisibilityUpdate =
|
||||
typeof update.isTemporary === 'boolean' ||
|
||||
Object.prototype.hasOwnProperty.call(convo, 'expiredAt') ||
|
||||
Object.prototype.hasOwnProperty.call(unsetFields, 'isTemporary') ||
|
||||
Object.prototype.hasOwnProperty.call(unsetFields, 'expiredAt');
|
||||
const shouldRefreshProjectStats =
|
||||
typeof update.isArchived === 'boolean' ||
|
||||
Object.prototype.hasOwnProperty.call(metadata?.unsetFields ?? {}, 'isArchived');
|
||||
Object.prototype.hasOwnProperty.call(unsetFields, 'isArchived') ||
|
||||
isRetentionVisibilityUpdate;
|
||||
|
||||
if (shouldRefreshProjectStats) {
|
||||
await refreshChatProjectStatsForUser(mongoose, userId, conversation.chatProjectId);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue