mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-02-13 04:54:24 +01:00
🌿 feat: Fork Messages/Conversations (#2617)
* typedef for ImportBatchBuilder * feat: first pass, fork conversations * feat: fork - getMessagesUpToTargetLevel * fix: additional tests and fix getAllMessagesUpToParent * chore: arrow function return * refactor: fork 3 options * chore: remove unused genbuttons * chore: remove unused hover buttons code * feat: fork first pass * wip: fork remember setting * style: user icon * chore: move clear chats to data tab * WIP: fork UI options * feat: data-provider fork types/services/vars and use generic MutationOptions * refactor: use single param for fork option, use enum, fix mongo errors, use Date.now(), add records flag for testing, use endpoint from original convo and messages, pass originalConvo to finishConversation * feat: add fork mutation hook and consolidate type imports * refactor: use enum * feat: first pass, fork mutation * chore: add enum for target level fork option * chore: add enum for target level fork option * show toast when checking remember selection * feat: splitAtTarget * feat: split at target option * feat: navigate to new fork, show toasts, set result query data * feat: hover info for all fork options * refactor: add Messages settings tab * fix(Fork): remember text info * ci: test for single message and is target edge case * feat: additional tests for getAllMessagesUpToParent * ci: additional tests and cycle detection for getMessagesUpToTargetLevel * feat: circular dependency checks for getAllMessagesUpToParent * fix: getMessagesUpToTargetLevel circular dep. check * ci: more tests for getMessagesForConversation * style: hover text for checkbox fork items * refactor: add statefulness to conversation import
This commit is contained in:
parent
c8baceac76
commit
25fceb78b7
37 changed files with 1831 additions and 523 deletions
|
|
@ -1,101 +0,0 @@
|
|||
import { useState } from 'react';
|
||||
import type { TConversation, TMessage } from 'librechat-data-provider';
|
||||
import { Clipboard, CheckMark, EditIcon, RegenerateIcon, ContinueIcon } from '~/components/svg';
|
||||
import { useGenerations, useLocalize } from '~/hooks';
|
||||
import { cn } from '~/utils';
|
||||
|
||||
type THoverButtons = {
|
||||
isEditing: boolean;
|
||||
enterEdit: (cancel?: boolean) => void;
|
||||
copyToClipboard: (setIsCopied: React.Dispatch<React.SetStateAction<boolean>>) => void;
|
||||
conversation: TConversation | null;
|
||||
isSubmitting: boolean;
|
||||
message: TMessage;
|
||||
regenerate: () => void;
|
||||
handleContinue: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
};
|
||||
|
||||
export default function HoverButtons({
|
||||
isEditing,
|
||||
enterEdit,
|
||||
copyToClipboard,
|
||||
conversation,
|
||||
isSubmitting,
|
||||
message,
|
||||
regenerate,
|
||||
handleContinue,
|
||||
}: THoverButtons) {
|
||||
const localize = useLocalize();
|
||||
const { endpoint } = conversation ?? {};
|
||||
const [isCopied, setIsCopied] = useState(false);
|
||||
const { hideEditButton, regenerateEnabled, continueSupported } = useGenerations({
|
||||
isEditing,
|
||||
isSubmitting,
|
||||
message,
|
||||
endpoint: endpoint ?? '',
|
||||
});
|
||||
if (!conversation) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { isCreatedByUser } = message;
|
||||
|
||||
const onEdit = () => {
|
||||
if (isEditing) {
|
||||
return enterEdit(true);
|
||||
}
|
||||
enterEdit();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="visible mt-2 flex justify-center gap-3 self-end text-gray-400 md:gap-4 lg:absolute lg:right-0 lg:top-0 lg:mt-0 lg:translate-x-full lg:gap-1 lg:self-center lg:pl-2">
|
||||
<button
|
||||
className={cn(
|
||||
'hover-button rounded-md p-1 hover:bg-gray-200 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-gray-200 disabled:dark:hover:text-gray-400 md:invisible md:group-hover:visible',
|
||||
isCreatedByUser ? '' : 'active',
|
||||
hideEditButton ? 'opacity-0' : '',
|
||||
isEditing ? 'active bg-gray-200 text-gray-700 dark:bg-gray-700 dark:text-gray-200' : '',
|
||||
)}
|
||||
onClick={onEdit}
|
||||
type="button"
|
||||
title={localize('com_ui_edit')}
|
||||
disabled={hideEditButton}
|
||||
>
|
||||
<EditIcon />
|
||||
</button>
|
||||
<button
|
||||
className={cn(
|
||||
'hover-button rounded-md p-1 hover:bg-gray-200 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-gray-200 disabled:dark:hover:text-gray-400 md:invisible md:group-hover:visible',
|
||||
isCreatedByUser ? '' : 'active',
|
||||
)}
|
||||
onClick={() => copyToClipboard(setIsCopied)}
|
||||
type="button"
|
||||
title={
|
||||
isCopied ? localize('com_ui_copied_to_clipboard') : localize('com_ui_copy_to_clipboard')
|
||||
}
|
||||
>
|
||||
{isCopied ? <CheckMark /> : <Clipboard />}
|
||||
</button>
|
||||
{regenerateEnabled ? (
|
||||
<button
|
||||
className="hover-button active rounded-md p-1 hover:bg-gray-200 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-gray-200 disabled:dark:hover:text-gray-400 md:invisible md:group-hover:visible"
|
||||
onClick={regenerate}
|
||||
type="button"
|
||||
title={localize('com_ui_regenerate')}
|
||||
>
|
||||
<RegenerateIcon className="hover:text-gray-700 dark:hover:bg-gray-700 dark:hover:text-gray-200 disabled:dark:hover:text-gray-400" />
|
||||
</button>
|
||||
) : null}
|
||||
{continueSupported ? (
|
||||
<button
|
||||
className="hover-button active rounded-md p-1 hover:bg-gray-200 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-gray-200 disabled:dark:hover:text-gray-400 md:invisible md:group-hover:visible "
|
||||
onClick={handleContinue}
|
||||
type="button"
|
||||
title={localize('com_ui_continue')}
|
||||
>
|
||||
<ContinueIcon className="h-4 w-4 hover:text-gray-700 dark:hover:bg-gray-700 dark:hover:text-gray-200 disabled:dark:hover:text-gray-400" />
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue