mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 00:40:14 +01:00
🔖 fix: Remove Local State from Bookmark Menu (#5181)
* chore: remove redundant * fix: bookmark menu statefulness by removing local state
This commit is contained in:
parent
7c61115a88
commit
766657da83
5 changed files with 24 additions and 26 deletions
|
|
@ -2,7 +2,7 @@ import { useRecoilState } from 'recoil';
|
||||||
import { Settings2 } from 'lucide-react';
|
import { Settings2 } from 'lucide-react';
|
||||||
import { Root, Anchor } from '@radix-ui/react-popover';
|
import { Root, Anchor } from '@radix-ui/react-popover';
|
||||||
import { useState, useEffect, useMemo } from 'react';
|
import { useState, useEffect, useMemo } from 'react';
|
||||||
import { tPresetUpdateSchema, EModelEndpoint, isParamEndpoint } from 'librechat-data-provider';
|
import { tConvoUpdateSchema, EModelEndpoint, isParamEndpoint } from 'librechat-data-provider';
|
||||||
import type { TPreset, TInterfaceConfig } from 'librechat-data-provider';
|
import type { TPreset, TInterfaceConfig } from 'librechat-data-provider';
|
||||||
import { EndpointSettings, SaveAsPresetDialog, AlternativeSettings } from '~/components/Endpoints';
|
import { EndpointSettings, SaveAsPresetDialog, AlternativeSettings } from '~/components/Endpoints';
|
||||||
import { PluginStoreDialog, TooltipAnchor } from '~/components';
|
import { PluginStoreDialog, TooltipAnchor } from '~/components';
|
||||||
|
|
@ -123,7 +123,7 @@ export default function HeaderOptions({
|
||||||
open={saveAsDialogShow}
|
open={saveAsDialogShow}
|
||||||
onOpenChange={setSaveAsDialogShow}
|
onOpenChange={setSaveAsDialogShow}
|
||||||
preset={
|
preset={
|
||||||
tPresetUpdateSchema.parse({
|
tConvoUpdateSchema.parse({
|
||||||
...conversation,
|
...conversation,
|
||||||
}) as TPreset
|
}) as TPreset
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,15 +27,14 @@ const BookmarkMenu: FC = () => {
|
||||||
const conversation = useRecoilValue(store.conversationByIndex(0)) || undefined;
|
const conversation = useRecoilValue(store.conversationByIndex(0)) || undefined;
|
||||||
const conversationId = conversation?.conversationId ?? '';
|
const conversationId = conversation?.conversationId ?? '';
|
||||||
const updateConvoTags = useBookmarkSuccess(conversationId);
|
const updateConvoTags = useBookmarkSuccess(conversationId);
|
||||||
|
const tags = conversation?.tags;
|
||||||
|
|
||||||
const menuId = useId();
|
const menuId = useId();
|
||||||
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
||||||
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
||||||
const [tags, setTags] = useState<string[]>(conversation?.tags || []);
|
|
||||||
|
|
||||||
const mutation = useTagConversationMutation(conversationId, {
|
const mutation = useTagConversationMutation(conversationId, {
|
||||||
onSuccess: (newTags: string[], vars) => {
|
onSuccess: (newTags: string[], vars) => {
|
||||||
setTags(newTags);
|
|
||||||
updateConvoTags(newTags);
|
updateConvoTags(newTags);
|
||||||
const tagElement = document.getElementById(vars.tag);
|
const tagElement = document.getElementById(vars.tag);
|
||||||
console.log('tagElement', tagElement);
|
console.log('tagElement', tagElement);
|
||||||
|
|
@ -82,12 +81,13 @@ const BookmarkMenu: FC = () => {
|
||||||
const allTags =
|
const allTags =
|
||||||
queryClient.getQueryData<TConversationTag[]>([QueryKeys.conversationTags]) ?? [];
|
queryClient.getQueryData<TConversationTag[]>([QueryKeys.conversationTags]) ?? [];
|
||||||
const existingTags = allTags.map((t) => t.tag);
|
const existingTags = allTags.map((t) => t.tag);
|
||||||
const filteredTags = tags.filter((t) => existingTags.includes(t));
|
const filteredTags = tags?.filter((t) => existingTags.includes(t));
|
||||||
|
|
||||||
logger.log('tag_mutation', 'BookmarkMenu - handleSubmit: tags after filtering', filteredTags);
|
logger.log('tag_mutation', 'BookmarkMenu - handleSubmit: tags after filtering', filteredTags);
|
||||||
const newTags = filteredTags.includes(tag)
|
const newTags =
|
||||||
? filteredTags.filter((t) => t !== tag)
|
filteredTags?.includes(tag) === true
|
||||||
: [...filteredTags, tag];
|
? filteredTags.filter((t) => t !== tag)
|
||||||
|
: [...(filteredTags ?? []), tag];
|
||||||
|
|
||||||
logger.log('tag_mutation', 'BookmarkMenu - handleSubmit: tags after', newTags);
|
logger.log('tag_mutation', 'BookmarkMenu - handleSubmit: tags after', newTags);
|
||||||
mutation.mutate({
|
mutation.mutate({
|
||||||
|
|
@ -115,16 +115,17 @@ const BookmarkMenu: FC = () => {
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
for (const tag of data) {
|
for (const tag of data) {
|
||||||
const isSelected = tags.includes(tag.tag);
|
const isSelected = tags?.includes(tag.tag);
|
||||||
items.push({
|
items.push({
|
||||||
id: tag.tag,
|
id: tag.tag,
|
||||||
hideOnClick: false,
|
|
||||||
label: tag.tag,
|
label: tag.tag,
|
||||||
icon: isSelected ? (
|
hideOnClick: false,
|
||||||
<BookmarkFilledIcon className="size-4" />
|
icon:
|
||||||
) : (
|
isSelected === true ? (
|
||||||
<BookmarkIcon className="size-4" />
|
<BookmarkFilledIcon className="size-4" />
|
||||||
),
|
) : (
|
||||||
|
<BookmarkIcon className="size-4" />
|
||||||
|
),
|
||||||
onClick: () => handleSubmit(tag.tag),
|
onClick: () => handleSubmit(tag.tag),
|
||||||
disabled: mutation.isLoading,
|
disabled: mutation.isLoading,
|
||||||
});
|
});
|
||||||
|
|
@ -142,7 +143,7 @@ const BookmarkMenu: FC = () => {
|
||||||
if (mutation.isLoading) {
|
if (mutation.isLoading) {
|
||||||
return <Spinner aria-label="Spinner" />;
|
return <Spinner aria-label="Spinner" />;
|
||||||
}
|
}
|
||||||
if (tags.length > 0) {
|
if ((tags?.length ?? 0) > 0) {
|
||||||
return <BookmarkFilledIcon className="icon-sm" aria-label="Filled Bookmark" />;
|
return <BookmarkFilledIcon className="icon-sm" aria-label="Filled Bookmark" />;
|
||||||
}
|
}
|
||||||
return <BookmarkIcon className="icon-sm" aria-label="Bookmark" />;
|
return <BookmarkIcon className="icon-sm" aria-label="Bookmark" />;
|
||||||
|
|
@ -155,6 +156,7 @@ const BookmarkMenu: FC = () => {
|
||||||
menuId={menuId}
|
menuId={menuId}
|
||||||
isOpen={isMenuOpen}
|
isOpen={isMenuOpen}
|
||||||
setIsOpen={setIsMenuOpen}
|
setIsOpen={setIsMenuOpen}
|
||||||
|
keyPrefix={`${conversationId}-bookmark-`}
|
||||||
trigger={
|
trigger={
|
||||||
<TooltipAnchor
|
<TooltipAnchor
|
||||||
description={localize('com_ui_bookmarks_add')}
|
description={localize('com_ui_bookmarks_add')}
|
||||||
|
|
@ -177,8 +179,8 @@ const BookmarkMenu: FC = () => {
|
||||||
/>
|
/>
|
||||||
<BookmarkEditDialog
|
<BookmarkEditDialog
|
||||||
tags={tags}
|
tags={tags}
|
||||||
setTags={setTags}
|
|
||||||
open={isDialogOpen}
|
open={isDialogOpen}
|
||||||
|
setTags={updateConvoTags}
|
||||||
setOpen={setIsDialogOpen}
|
setOpen={setIsDialogOpen}
|
||||||
triggerRef={newBookmarkRef}
|
triggerRef={newBookmarkRef}
|
||||||
conversationId={conversationId}
|
conversationId={conversationId}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useMemo, useState, useEffect, useCallback } from 'react';
|
import React, { useMemo, useState, useEffect, useCallback } from 'react';
|
||||||
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
|
||||||
import { getSettingsKeys, tPresetUpdateSchema } from 'librechat-data-provider';
|
import { getSettingsKeys, tConvoUpdateSchema } from 'librechat-data-provider';
|
||||||
import type { TPreset } from 'librechat-data-provider';
|
import type { TPreset } from 'librechat-data-provider';
|
||||||
import { SaveAsPresetDialog } from '~/components/Endpoints';
|
import { SaveAsPresetDialog } from '~/components/Endpoints';
|
||||||
import { useSetIndexOptions, useLocalize } from '~/hooks';
|
import { useSetIndexOptions, useLocalize } from '~/hooks';
|
||||||
|
|
@ -106,7 +106,7 @@ export default function Parameters() {
|
||||||
}, [parameters, setConversation]);
|
}, [parameters, setConversation]);
|
||||||
|
|
||||||
const openDialog = useCallback(() => {
|
const openDialog = useCallback(() => {
|
||||||
const newPreset = tPresetUpdateSchema.parse({
|
const newPreset = tConvoUpdateSchema.parse({
|
||||||
...conversation,
|
...conversation,
|
||||||
}) as TPreset;
|
}) as TPreset;
|
||||||
setPreset(newPreset);
|
setPreset(newPreset);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import type * as t from '~/common';
|
||||||
import { cn } from '~/utils';
|
import { cn } from '~/utils';
|
||||||
|
|
||||||
interface DropdownProps {
|
interface DropdownProps {
|
||||||
|
keyPrefix?: string;
|
||||||
trigger: React.ReactNode;
|
trigger: React.ReactNode;
|
||||||
items: t.MenuItemProps[];
|
items: t.MenuItemProps[];
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
|
|
@ -20,6 +21,7 @@ interface DropdownProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const DropdownPopup: React.FC<DropdownProps> = ({
|
const DropdownPopup: React.FC<DropdownProps> = ({
|
||||||
|
keyPrefix,
|
||||||
trigger,
|
trigger,
|
||||||
items,
|
items,
|
||||||
isOpen,
|
isOpen,
|
||||||
|
|
@ -53,7 +55,7 @@ const DropdownPopup: React.FC<DropdownProps> = ({
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Ariakit.MenuItem
|
<Ariakit.MenuItem
|
||||||
key={index}
|
key={`${keyPrefix ?? ''}${index}`}
|
||||||
id={item.id}
|
id={item.id}
|
||||||
className={cn(
|
className={cn(
|
||||||
'group flex w-full cursor-pointer items-center gap-2 rounded-lg px-3 py-3.5 text-sm text-text-primary outline-none transition-colors duration-200 hover:bg-surface-hover focus:bg-surface-hover md:px-2.5 md:py-2',
|
'group flex w-full cursor-pointer items-center gap-2 rounded-lg px-3 py-3.5 text-sm text-text-primary outline-none transition-colors duration-200 hover:bg-surface-hover focus:bg-surface-hover md:px-2.5 md:py-2',
|
||||||
|
|
|
||||||
|
|
@ -630,12 +630,6 @@ export const tConvoUpdateSchema = tConversationSchema.merge(
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const tPresetUpdateSchema = tConversationSchema.merge(
|
|
||||||
z.object({
|
|
||||||
endpoint: extendedModelEndpointSchema.nullable(),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
export type TPreset = z.infer<typeof tPresetSchema>;
|
export type TPreset = z.infer<typeof tPresetSchema>;
|
||||||
|
|
||||||
export type TSetOption = (
|
export type TSetOption = (
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue