mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 16:30:15 +01:00
Revert "⌨️ feat: Add Shift-Key Shortcuts for Instant Conversation Actions (#10732)"
This reverts commit 41c0a96d39.
This commit is contained in:
parent
dcd9273700
commit
03ced7a894
4 changed files with 43 additions and 176 deletions
|
|
@ -6,7 +6,7 @@ import { useToastContext, useMediaQuery } from '@librechat/client';
|
|||
import type { TConversation } from 'librechat-data-provider';
|
||||
import { useUpdateConversationMutation } from '~/data-provider';
|
||||
import EndpointIcon from '~/components/Endpoints/EndpointIcon';
|
||||
import { useNavigateToConvo, useLocalize, useShiftKey } from '~/hooks';
|
||||
import { useNavigateToConvo, useLocalize } from '~/hooks';
|
||||
import { useGetEndpointsQuery } from '~/data-provider';
|
||||
import { NotificationSeverity } from '~/common';
|
||||
import { ConvoOptions } from './ConvoOptions';
|
||||
|
|
@ -31,7 +31,6 @@ export default function Conversation({ conversation, retainView, toggleNav }: Co
|
|||
const updateConvoMutation = useUpdateConversationMutation(currentConvoId ?? '');
|
||||
const activeConvos = useRecoilValue(store.allConversationsSelector);
|
||||
const isSmallScreen = useMediaQuery('(max-width: 768px)');
|
||||
const isShiftHeld = useShiftKey();
|
||||
const { conversationId, title = '' } = conversation;
|
||||
|
||||
const [titleInput, setTitleInput] = useState(title || '');
|
||||
|
|
@ -195,9 +194,8 @@ export default function Conversation({ conversation, retainView, toggleNav }: Co
|
|||
className={cn(
|
||||
'mr-2 flex origin-left',
|
||||
isPopoverActive || isActiveConvo
|
||||
? 'pointer-events-auto scale-x-100 opacity-100'
|
||||
: 'pointer-events-none max-w-0 scale-x-0 opacity-0 group-focus-within:pointer-events-auto group-focus-within:max-w-[60px] group-focus-within:scale-x-100 group-focus-within:opacity-100 group-hover:pointer-events-auto group-hover:max-w-[60px] group-hover:scale-x-100 group-hover:opacity-100',
|
||||
(isPopoverActive || isActiveConvo) && (isShiftHeld ? 'max-w-[60px]' : 'max-w-[28px]'),
|
||||
? 'pointer-events-auto max-w-[28px] scale-x-100 opacity-100'
|
||||
: 'pointer-events-none max-w-0 scale-x-0 opacity-0 group-focus-within:pointer-events-auto group-focus-within:max-w-[28px] group-focus-within:scale-x-100 group-focus-within:opacity-100 group-hover:pointer-events-auto group-hover:max-w-[28px] group-hover:scale-x-100 group-hover:opacity-100',
|
||||
)}
|
||||
// Removing aria-hidden to fix accessibility issue: ARIA hidden element must not be focusable or contain focusable elements
|
||||
// but not sure what its original purpose was, so leaving the property commented out until it can be cleared safe to delete.
|
||||
|
|
|
|||
|
|
@ -1,19 +1,15 @@
|
|||
import { useState, useId, useRef, memo, useCallback, useMemo } from 'react';
|
||||
import * as Ariakit from '@ariakit/react';
|
||||
import { useParams, useNavigate } from 'react-router-dom';
|
||||
import { QueryKeys } from 'librechat-data-provider';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { DropdownPopup, Spinner, useToastContext } from '@librechat/client';
|
||||
import { Ellipsis, Share2, CopyPlus, Archive, Pen, Trash } from 'lucide-react';
|
||||
import type { MouseEvent } from 'react';
|
||||
import type { TMessage } from 'librechat-data-provider';
|
||||
import {
|
||||
useDuplicateConversationMutation,
|
||||
useDeleteConversationMutation,
|
||||
useGetStartupConfig,
|
||||
useArchiveConvoMutation,
|
||||
} from '~/data-provider';
|
||||
import { useLocalize, useNavigateToConvo, useNewConvo, useShiftKey } from '~/hooks';
|
||||
import { useLocalize, useNavigateToConvo, useNewConvo } from '~/hooks';
|
||||
import { NotificationSeverity } from '~/common';
|
||||
import { useChatContext } from '~/Providers';
|
||||
import DeleteButton from './DeleteButton';
|
||||
|
|
@ -38,8 +34,6 @@ function ConvoOptions({
|
|||
isActiveConvo: boolean;
|
||||
}) {
|
||||
const localize = useLocalize();
|
||||
const queryClient = useQueryClient();
|
||||
const isShiftHeld = useShiftKey();
|
||||
const { index } = useChatContext();
|
||||
const { data: startupConfig } = useGetStartupConfig();
|
||||
const { navigateToConvo } = useNavigateToConvo(index);
|
||||
|
|
@ -58,28 +52,6 @@ function ConvoOptions({
|
|||
|
||||
const archiveConvoMutation = useArchiveConvoMutation();
|
||||
|
||||
const deleteMutation = useDeleteConversationMutation({
|
||||
onSuccess: () => {
|
||||
if (currentConvoId === conversationId || currentConvoId === 'new') {
|
||||
newConversation();
|
||||
navigate('/c/new', { replace: true });
|
||||
}
|
||||
retainView();
|
||||
showToast({
|
||||
message: localize('com_ui_convo_delete_success'),
|
||||
severity: NotificationSeverity.SUCCESS,
|
||||
showIcon: true,
|
||||
});
|
||||
},
|
||||
onError: () => {
|
||||
showToast({
|
||||
message: localize('com_ui_convo_delete_error'),
|
||||
severity: NotificationSeverity.ERROR,
|
||||
showIcon: true,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const duplicateConversation = useDuplicateConversationMutation({
|
||||
onSuccess: (data) => {
|
||||
navigateToConvo(data.conversation);
|
||||
|
|
@ -105,7 +77,6 @@ function ConvoOptions({
|
|||
|
||||
const isDuplicateLoading = duplicateConversation.isLoading;
|
||||
const isArchiveLoading = archiveConvoMutation.isLoading;
|
||||
const isDeleteLoading = deleteMutation.isLoading;
|
||||
|
||||
const shareHandler = useCallback(() => {
|
||||
setShowShareDialog(true);
|
||||
|
|
@ -115,70 +86,47 @@ function ConvoOptions({
|
|||
setShowDeleteDialog(true);
|
||||
}, []);
|
||||
|
||||
const handleInstantDelete = useCallback(
|
||||
(e: MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
const convoId = conversationId ?? '';
|
||||
if (!convoId) {
|
||||
return;
|
||||
}
|
||||
const handleArchiveClick = useCallback(async () => {
|
||||
const convoId = conversationId ?? '';
|
||||
if (!convoId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const messages = queryClient.getQueryData<TMessage[]>([QueryKeys.messages, convoId]);
|
||||
const thread_id = messages?.[messages.length - 1]?.thread_id;
|
||||
const endpoint = messages?.[messages.length - 1]?.endpoint;
|
||||
|
||||
deleteMutation.mutate({ conversationId: convoId, thread_id, endpoint, source: 'button' });
|
||||
},
|
||||
[conversationId, deleteMutation, queryClient],
|
||||
);
|
||||
|
||||
const handleArchiveClick = useCallback(
|
||||
async (e?: MouseEvent) => {
|
||||
e?.stopPropagation();
|
||||
const convoId = conversationId ?? '';
|
||||
if (!convoId) {
|
||||
return;
|
||||
}
|
||||
|
||||
archiveConvoMutation.mutate(
|
||||
{ conversationId: convoId, isArchived: true },
|
||||
{
|
||||
onSuccess: () => {
|
||||
setAnnouncement(localize('com_ui_convo_archived'));
|
||||
setTimeout(() => {
|
||||
setAnnouncement('');
|
||||
}, 10000);
|
||||
|
||||
if (currentConvoId === convoId || currentConvoId === 'new') {
|
||||
newConversation();
|
||||
navigate('/c/new', { replace: true });
|
||||
}
|
||||
|
||||
retainView();
|
||||
setIsPopoverActive(false);
|
||||
},
|
||||
onError: () => {
|
||||
showToast({
|
||||
message: localize('com_ui_archive_error'),
|
||||
severity: NotificationSeverity.ERROR,
|
||||
showIcon: true,
|
||||
});
|
||||
},
|
||||
archiveConvoMutation.mutate(
|
||||
{ conversationId: convoId, isArchived: true },
|
||||
{
|
||||
onSuccess: () => {
|
||||
setAnnouncement(localize('com_ui_convo_archived'));
|
||||
setTimeout(() => {
|
||||
setAnnouncement('');
|
||||
}, 10000);
|
||||
if (currentConvoId === convoId || currentConvoId === 'new') {
|
||||
newConversation();
|
||||
navigate('/c/new', { replace: true });
|
||||
}
|
||||
retainView();
|
||||
setIsPopoverActive(false);
|
||||
},
|
||||
);
|
||||
},
|
||||
[
|
||||
conversationId,
|
||||
currentConvoId,
|
||||
archiveConvoMutation,
|
||||
navigate,
|
||||
newConversation,
|
||||
retainView,
|
||||
setIsPopoverActive,
|
||||
showToast,
|
||||
localize,
|
||||
],
|
||||
);
|
||||
onError: () => {
|
||||
showToast({
|
||||
message: localize('com_ui_archive_error'),
|
||||
severity: NotificationSeverity.ERROR,
|
||||
showIcon: true,
|
||||
});
|
||||
},
|
||||
},
|
||||
);
|
||||
}, [
|
||||
conversationId,
|
||||
currentConvoId,
|
||||
archiveConvoMutation,
|
||||
navigate,
|
||||
newConversation,
|
||||
retainView,
|
||||
setIsPopoverActive,
|
||||
showToast,
|
||||
localize,
|
||||
]);
|
||||
|
||||
const handleDuplicateClick = useCallback(() => {
|
||||
duplicateConversation.mutate({
|
||||
|
|
@ -250,44 +198,6 @@ function ConvoOptions({
|
|||
],
|
||||
);
|
||||
|
||||
const buttonClassName = cn(
|
||||
'inline-flex h-7 w-7 items-center justify-center rounded-md border-none p-0 text-sm font-medium ring-ring-primary transition-all duration-200 ease-in-out focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:opacity-50',
|
||||
isActiveConvo === true || isPopoverActive
|
||||
? 'opacity-100'
|
||||
: 'opacity-0 focus:opacity-100 group-focus-within:opacity-100 group-hover:opacity-100 data-[open]:opacity-100',
|
||||
);
|
||||
|
||||
if (isShiftHeld) {
|
||||
return (
|
||||
<div className="flex items-center gap-0.5">
|
||||
<button
|
||||
aria-label={localize('com_ui_archive')}
|
||||
className={cn(buttonClassName, 'hover:bg-surface-hover')}
|
||||
onClick={handleArchiveClick}
|
||||
disabled={isArchiveLoading}
|
||||
>
|
||||
{isArchiveLoading ? (
|
||||
<Spinner className="size-4" />
|
||||
) : (
|
||||
<Archive className="icon-md text-text-secondary" aria-hidden={true} />
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
aria-label={localize('com_ui_delete')}
|
||||
className={cn(buttonClassName, 'hover:bg-surface-hover')}
|
||||
onClick={handleInstantDelete}
|
||||
disabled={isDeleteLoading}
|
||||
>
|
||||
{isDeleteLoading ? (
|
||||
<Spinner className="size-4" />
|
||||
) : (
|
||||
<Trash className="icon-md text-text-secondary" aria-hidden={true} />
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<span className="sr-only" aria-live="polite" aria-atomic="true">
|
||||
|
|
|
|||
|
|
@ -1,2 +1 @@
|
|||
export * from './useLazyEffect';
|
||||
export { default as useShiftKey } from './useShiftKey';
|
||||
|
|
|
|||
|
|
@ -1,40 +0,0 @@
|
|||
import { useState, useEffect } from 'react';
|
||||
|
||||
/**
|
||||
* Hook to track whether the shift key is currently being held down
|
||||
* @returns boolean indicating if shift key is pressed
|
||||
*/
|
||||
export default function useShiftKey(): boolean {
|
||||
const [isShiftHeld, setIsShiftHeld] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Shift') {
|
||||
setIsShiftHeld(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleKeyUp = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Shift') {
|
||||
setIsShiftHeld(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Reset shift state when window loses focus
|
||||
const handleBlur = () => {
|
||||
setIsShiftHeld(false);
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
window.addEventListener('keyup', handleKeyUp);
|
||||
window.addEventListener('blur', handleBlur);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyDown);
|
||||
window.removeEventListener('keyup', handleKeyUp);
|
||||
window.removeEventListener('blur', handleBlur);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return isShiftHeld;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue