mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-04 14:57:42 +00:00
fix: project new-chat keeps model spec; sidebar header + row polish
- newConversation: ignore a chatProjectId-only template when deciding to apply the default model spec, so starting a chat in a project no longer strips the conversation `spec` - useSelectMention: the Model Selector and @ command now retain the active project across endpoint/spec/preset switches; other new-chat paths still clear it - Chats header now matches the Projects header (inline chevron + a new-chat icon button) and starts a non-project chat - Project rows: use the new-chat icon for the per-project add button, render at text-sm to match the chat list, and align the row actions + hover color with conversation rows
This commit is contained in:
parent
72783348f4
commit
e1e1ebb825
4 changed files with 69 additions and 20 deletions
|
|
@ -2,13 +2,21 @@ import { useMemo, memo, type FC, useCallback, useEffect, useRef } from 'react';
|
|||
import throttle from 'lodash/throttle';
|
||||
import { ChevronDown } from 'lucide-react';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { Spinner, useMediaQuery } from '@librechat/client';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { QueryKeys } from 'librechat-data-provider';
|
||||
import { Spinner, TooltipAnchor, NewChatIcon, useMediaQuery } from '@librechat/client';
|
||||
import { List, AutoSizer, CellMeasurer, CellMeasurerCache } from 'react-virtualized';
|
||||
import type { TConversation } from 'librechat-data-provider';
|
||||
import { useLocalize, TranslationKeys, useFavorites, useShowMarketplace } from '~/hooks';
|
||||
import {
|
||||
useLocalize,
|
||||
TranslationKeys,
|
||||
useFavorites,
|
||||
useShowMarketplace,
|
||||
useNewConvo,
|
||||
} from '~/hooks';
|
||||
import FavoritesList from '~/components/Nav/Favorites/FavoritesList';
|
||||
import { useActiveJobs } from '~/data-provider';
|
||||
import { groupConversationsByDate, cn } from '~/utils';
|
||||
import { groupConversationsByDate, clearMessagesCache, cn } from '~/utils';
|
||||
import Convo from './Convo';
|
||||
import store from '~/store';
|
||||
|
||||
|
|
@ -77,20 +85,53 @@ interface ChatsHeaderProps {
|
|||
onToggle: () => void;
|
||||
}
|
||||
|
||||
const headerIconButtonClassName =
|
||||
'flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-text-secondary outline-none transition-colors hover:bg-surface-active-alt hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-black dark:focus-visible:ring-white';
|
||||
|
||||
/** Collapsible header for the Chats section */
|
||||
const ChatsHeader: FC<ChatsHeaderProps> = memo(({ isExpanded, onToggle }) => {
|
||||
const localize = useLocalize();
|
||||
const queryClient = useQueryClient();
|
||||
const { newConversation } = useNewConvo();
|
||||
const conversation = useRecoilValue(store.conversationByIndex(0));
|
||||
|
||||
const handleNewChat = useCallback(() => {
|
||||
clearMessagesCache(queryClient, conversation?.conversationId);
|
||||
queryClient.invalidateQueries([QueryKeys.messages]);
|
||||
newConversation();
|
||||
}, [conversation?.conversationId, newConversation, queryClient]);
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={onToggle}
|
||||
className="group flex w-full items-center justify-between rounded-lg px-1 py-2 text-xs font-bold text-text-secondary outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-black dark:focus-visible:ring-white"
|
||||
type="button"
|
||||
>
|
||||
<span className="select-none">{localize('com_ui_chats')}</span>
|
||||
<ChevronDown
|
||||
className={cn('h-3 w-3 transition-transform duration-200', isExpanded ? 'rotate-180' : '')}
|
||||
<div className="flex h-8 w-full items-center gap-0.5">
|
||||
<button
|
||||
onClick={onToggle}
|
||||
className="group flex min-w-0 flex-1 items-center gap-1 rounded-lg px-1 py-2 text-xs font-bold text-text-secondary outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-black dark:focus-visible:ring-white"
|
||||
type="button"
|
||||
aria-expanded={isExpanded}
|
||||
>
|
||||
<span className="select-none truncate">{localize('com_ui_chats')}</span>
|
||||
<ChevronDown
|
||||
className={cn(
|
||||
'h-3 w-3 shrink-0 transition-transform duration-200',
|
||||
isExpanded ? '' : '-rotate-90',
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</button>
|
||||
<TooltipAnchor
|
||||
description={localize('com_ui_new_chat')}
|
||||
render={
|
||||
<button
|
||||
type="button"
|
||||
aria-label={localize('com_ui_new_chat')}
|
||||
className={headerIconButtonClassName}
|
||||
onClick={handleNewChat}
|
||||
>
|
||||
<NewChatIcon className="h-4 w-4" />
|
||||
</button>
|
||||
}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import {
|
|||
FolderPlus,
|
||||
LayoutGrid,
|
||||
Pencil,
|
||||
Plus,
|
||||
Trash2,
|
||||
} from 'lucide-react';
|
||||
import { QueryKeys } from 'librechat-data-provider';
|
||||
|
|
@ -27,6 +26,7 @@ import {
|
|||
OGDialogContent,
|
||||
TooltipAnchor,
|
||||
DropdownPopup,
|
||||
NewChatIcon,
|
||||
useToastContext,
|
||||
} from '@librechat/client';
|
||||
import type { MenuItemProps } from '~/common';
|
||||
|
|
@ -308,7 +308,7 @@ function ProjectItem({
|
|||
|
||||
return (
|
||||
<li className="list-none">
|
||||
<div className="group/project-row relative flex items-center rounded-lg text-sm text-text-primary transition-colors hover:bg-surface-hover">
|
||||
<div className="group/project-row relative flex h-9 items-center rounded-lg text-sm text-text-primary transition-colors hover:bg-surface-active-alt">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setExpanded((prev) => !prev)}
|
||||
|
|
@ -326,7 +326,7 @@ function ProjectItem({
|
|||
<Folder className="h-4 w-4 shrink-0 text-text-secondary" aria-hidden="true" />
|
||||
<span className="truncate">{project.name}</span>
|
||||
</button>
|
||||
<div className="absolute right-1 top-1/2 flex -translate-y-1/2 items-center gap-0.5 rounded-md bg-surface-hover opacity-0 transition-opacity group-focus-within/project-row:opacity-100 group-hover/project-row:opacity-100 has-[[data-state=open]]:opacity-100">
|
||||
<div className="absolute right-2 top-1/2 flex -translate-y-1/2 items-center gap-0.5 rounded-md bg-surface-active-alt opacity-0 transition-opacity group-focus-within/project-row:opacity-100 group-hover/project-row:opacity-100 has-[[data-state=open]]:opacity-100">
|
||||
<TooltipAnchor
|
||||
description={localize('com_ui_new_chat_in_project', { name: project.name })}
|
||||
render={
|
||||
|
|
@ -336,7 +336,7 @@ function ProjectItem({
|
|||
className={iconButtonClassName}
|
||||
onClick={startChat}
|
||||
>
|
||||
<Plus className="h-4 w-4" aria-hidden="true" />
|
||||
<NewChatIcon className="h-4 w-4" />
|
||||
</button>
|
||||
}
|
||||
/>
|
||||
|
|
@ -451,7 +451,7 @@ const ProjectsSection = ({ toggleNav, isAuthenticated }: ProjectsSectionProps) =
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col px-3">
|
||||
<div className="flex flex-col px-3 text-sm">
|
||||
<div className="flex h-8 w-full items-center gap-0.5">
|
||||
<button
|
||||
onClick={() => setIsExpanded(!isExpanded)}
|
||||
|
|
|
|||
|
|
@ -107,7 +107,10 @@ export default function useSelectMention({
|
|||
|
||||
logger.info('conversation', 'Switching conversation to new spec', conversation);
|
||||
newConversation({
|
||||
template: { ...(template as Partial<TConversation>) },
|
||||
template: {
|
||||
...(template as Partial<TConversation>),
|
||||
chatProjectId: conversation?.chatProjectId ?? null,
|
||||
},
|
||||
preset,
|
||||
keepAddedConvos: isModular,
|
||||
});
|
||||
|
|
@ -201,7 +204,10 @@ export default function useSelectMention({
|
|||
|
||||
logger.info('conversation', 'Switching conversation to new endpoint/model', template);
|
||||
newConversation({
|
||||
template: { ...(template as Partial<TConversation>) },
|
||||
template: {
|
||||
...(template as Partial<TConversation>),
|
||||
chatProjectId: conversation?.chatProjectId ?? null,
|
||||
},
|
||||
preset: { ...kwargs, spec: null, iconURL: null, modelLabel: null, endpoint: newEndpoint },
|
||||
keepAddedConvos: isNewModular,
|
||||
});
|
||||
|
|
@ -264,6 +270,7 @@ export default function useSelectMention({
|
|||
|
||||
logger.info('conversation', 'Switching conversation to new preset', template);
|
||||
newConversation({
|
||||
template: { chatProjectId: conversation?.chatProjectId ?? null },
|
||||
preset: newPreset,
|
||||
keepAddedConvos: isModular,
|
||||
disableParams,
|
||||
|
|
|
|||
|
|
@ -327,7 +327,8 @@ const useNewConvo = (index = 0) => {
|
|||
startupConfig &&
|
||||
(startupConfig.modelSpecs?.prioritize === true ||
|
||||
(startupConfig.interface?.modelSelect ?? true) !== true ||
|
||||
(result?.last != null && Object.keys(_template).length === 0)) &&
|
||||
(result?.last != null &&
|
||||
Object.keys(_template).filter((key) => key !== 'chatProjectId').length === 0)) &&
|
||||
defaultModelSpec
|
||||
) {
|
||||
preset = getModelSpecPreset(defaultModelSpec);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue