mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-18 09:20:15 +01:00
✨ feat: Implement Conversation Duplication & UI Improvements (#5036)
* feat(ui): enhance conversation components and add duplication - feat: add conversation duplication functionality - fix: resolve OGDialogTemplate display issues - style: improve mobile dropdown component design - chore: standardize shared link title formatting * style: update active item background color in select-item * feat(conversation): add duplicate conversation functionality and UI integration * feat(conversation): enable title renaming on double-click and improve input focus styles * fix(conversation): remove "(Copy)" suffix from duplicated conversation title in logging * fix(RevokeKeysButton): correct className duration property for smoother transitions * refactor(conversation): ensure proper parent-child relationships and timestamps when message cloning --------- Co-authored-by: Marco Beretta <81851188+berry-13@users.noreply.github.com>
This commit is contained in:
parent
649c7a6032
commit
e8bde332c2
24 changed files with 717 additions and 85 deletions
|
|
@ -1,9 +1,11 @@
|
|||
import { useState, useId } from 'react';
|
||||
import * as Ariakit from '@ariakit/react';
|
||||
import { Ellipsis, Share2, Archive, Pen, Trash } from 'lucide-react';
|
||||
import * as Menu from '@ariakit/react/menu';
|
||||
import { Ellipsis, Share2, Copy, Archive, Pen, Trash } from 'lucide-react';
|
||||
import { useGetStartupConfig } from 'librechat-data-provider/react-query';
|
||||
import type { MouseEvent } from 'react';
|
||||
import { useLocalize, useArchiveHandler } from '~/hooks';
|
||||
import { useLocalize, useArchiveHandler, useNavigateToConvo } from '~/hooks';
|
||||
import { useToastContext, useChatContext } from '~/Providers';
|
||||
import { useDuplicateConversationMutation } from '~/data-provider';
|
||||
import { DropdownPopup } from '~/components/ui';
|
||||
import DeleteButton from './DeleteButton';
|
||||
import ShareButton from './ShareButton';
|
||||
|
|
@ -12,7 +14,6 @@ import { cn } from '~/utils';
|
|||
export default function ConvoOptions({
|
||||
conversationId,
|
||||
title,
|
||||
renaming,
|
||||
retainView,
|
||||
renameHandler,
|
||||
isPopoverActive,
|
||||
|
|
@ -21,7 +22,6 @@ export default function ConvoOptions({
|
|||
}: {
|
||||
conversationId: string | null;
|
||||
title: string | null;
|
||||
renaming: boolean;
|
||||
retainView: () => void;
|
||||
renameHandler: (e: MouseEvent) => void;
|
||||
isPopoverActive: boolean;
|
||||
|
|
@ -29,10 +29,37 @@ export default function ConvoOptions({
|
|||
isActiveConvo: boolean;
|
||||
}) {
|
||||
const localize = useLocalize();
|
||||
const { index } = useChatContext();
|
||||
const { data: startupConfig } = useGetStartupConfig();
|
||||
const archiveHandler = useArchiveHandler(conversationId, true, retainView);
|
||||
const { navigateToConvo } = useNavigateToConvo(index);
|
||||
const { showToast } = useToastContext();
|
||||
const [showShareDialog, setShowShareDialog] = useState(false);
|
||||
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
|
||||
const archiveHandler = useArchiveHandler(conversationId, true, retainView);
|
||||
|
||||
const duplicateConversation = useDuplicateConversationMutation({
|
||||
onSuccess: (data) => {
|
||||
if (data != null) {
|
||||
navigateToConvo(data.conversation);
|
||||
showToast({
|
||||
message: localize('com_ui_duplication_success'),
|
||||
status: 'success',
|
||||
});
|
||||
}
|
||||
},
|
||||
onMutate: () => {
|
||||
showToast({
|
||||
message: localize('com_ui_duplication_processing'),
|
||||
status: 'info',
|
||||
});
|
||||
},
|
||||
onError: () => {
|
||||
showToast({
|
||||
message: localize('com_ui_duplication_error'),
|
||||
status: 'error',
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const shareHandler = () => {
|
||||
setIsPopoverActive(false);
|
||||
|
|
@ -44,27 +71,39 @@ export default function ConvoOptions({
|
|||
setShowDeleteDialog(true);
|
||||
};
|
||||
|
||||
const duplicateHandler = () => {
|
||||
setIsPopoverActive(false);
|
||||
duplicateConversation.mutate({
|
||||
conversationId: conversationId ?? '',
|
||||
});
|
||||
};
|
||||
|
||||
const dropdownItems = [
|
||||
{
|
||||
label: localize('com_ui_rename'),
|
||||
onClick: renameHandler,
|
||||
icon: <Pen className="icon-md mr-2 text-text-secondary" />,
|
||||
},
|
||||
{
|
||||
label: localize('com_ui_share'),
|
||||
onClick: shareHandler,
|
||||
icon: <Share2 className="icon-md mr-2 text-text-secondary" />,
|
||||
icon: <Share2 className="icon-sm mr-2 text-text-primary" />,
|
||||
show: startupConfig && startupConfig.sharedLinksEnabled,
|
||||
},
|
||||
{
|
||||
label: localize('com_ui_rename'),
|
||||
onClick: renameHandler,
|
||||
icon: <Pen className="icon-sm mr-2 text-text-primary" />,
|
||||
},
|
||||
{
|
||||
label: localize('com_ui_duplicate'),
|
||||
onClick: duplicateHandler,
|
||||
icon: <Copy className="icon-sm mr-2 text-text-primary" />,
|
||||
},
|
||||
{
|
||||
label: localize('com_ui_archive'),
|
||||
onClick: archiveHandler,
|
||||
icon: <Archive className="icon-md mr-2 text-text-secondary" />,
|
||||
icon: <Archive className="icon-sm mr-2 text-text-primary" />,
|
||||
},
|
||||
{
|
||||
label: localize('com_ui_delete'),
|
||||
onClick: deleteHandler,
|
||||
icon: <Trash className="icon-md mr-2 text-text-secondary" />,
|
||||
icon: <Trash className="icon-sm mr-2 text-text-primary" />,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
@ -76,7 +115,7 @@ export default function ConvoOptions({
|
|||
isOpen={isPopoverActive}
|
||||
setIsOpen={setIsPopoverActive}
|
||||
trigger={
|
||||
<Ariakit.MenuButton
|
||||
<Menu.MenuButton
|
||||
id="conversation-menu-button"
|
||||
aria-label={localize('com_nav_convo_menu_options')}
|
||||
className={cn(
|
||||
|
|
@ -84,11 +123,10 @@ export default function ConvoOptions({
|
|||
isActiveConvo === true
|
||||
? 'opacity-100'
|
||||
: 'opacity-0 focus:opacity-100 group-focus-within:opacity-100 group-hover:opacity-100 data-[open]:opacity-100',
|
||||
renaming === true ? 'pointer-events-none opacity-0' : '',
|
||||
)}
|
||||
>
|
||||
<Ellipsis className="icon-md text-text-secondary" aria-hidden={true} />
|
||||
</Ariakit.MenuButton>
|
||||
</Menu.MenuButton>
|
||||
}
|
||||
items={dropdownItems}
|
||||
menuId={menuId}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue