diff --git a/client/src/components/Bookmarks/BookmarkEditDialog.tsx b/client/src/components/Bookmarks/BookmarkEditDialog.tsx
index 2764cf4b85..b166b92c24 100644
--- a/client/src/components/Bookmarks/BookmarkEditDialog.tsx
+++ b/client/src/components/Bookmarks/BookmarkEditDialog.tsx
@@ -2,10 +2,9 @@ import React, { useRef, Dispatch, SetStateAction } from 'react';
import { TConversationTag, TConversation } from 'librechat-data-provider';
import OGDialogTemplate from '~/components/ui/OGDialogTemplate';
import { useConversationTagMutation } from '~/data-provider';
+import { OGDialog, Button, Spinner } from '~/components';
import { NotificationSeverity } from '~/common';
import { useToastContext } from '~/Providers';
-import { OGDialog } from '~/components/ui';
-import { Spinner } from '~/components/svg';
import BookmarkForm from './BookmarkForm';
import { useLocalize } from '~/hooks';
import { logger } from '~/utils';
@@ -75,6 +74,7 @@ const BookmarkEditDialog = ({
}
buttons={
-
+
}
/>
diff --git a/client/src/components/Bookmarks/BookmarkForm.tsx b/client/src/components/Bookmarks/BookmarkForm.tsx
index ea35b423ca..85018d3cfb 100644
--- a/client/src/components/Bookmarks/BookmarkForm.tsx
+++ b/client/src/components/Bookmarks/BookmarkForm.tsx
@@ -8,7 +8,7 @@ import type {
TConversationTagRequest,
} from 'librechat-data-provider';
import { cn, removeFocusOutlines, defaultTextProps, logger } from '~/utils';
-import { Checkbox, Label, TextareaAutosize } from '~/components/ui';
+import { Checkbox, Label, TextareaAutosize, Input } from '~/components';
import { useBookmarkContext } from '~/Providers/BookmarkContext';
import { useConversationTagMutation } from '~/data-provider';
import { useToastContext } from '~/Providers';
@@ -100,7 +100,7 @@ const BookmarkForm = ({
-
{errors.tag && {errors.tag.message}}
-
+
@@ -143,8 +138,7 @@ const BookmarkForm = ({
id="bookmark-description"
disabled={false}
className={cn(
- defaultTextProps,
- 'flex max-h-[138px] min-h-[100px] w-full resize-none px-3 py-2',
+ 'flex h-10 max-h-[250px] min-h-[100px] w-full resize-none rounded-lg border border-input bg-transparent px-3 py-2 text-sm ring-offset-background focus-visible:outline-none',
)}
/>
diff --git a/client/src/components/Chat/Input/AudioRecorder.tsx b/client/src/components/Chat/Input/AudioRecorder.tsx
index 1c950b5180..a8754749ad 100644
--- a/client/src/components/Chat/Input/AudioRecorder.tsx
+++ b/client/src/components/Chat/Input/AudioRecorder.tsx
@@ -80,10 +80,8 @@ export default function AudioRecorder({
onClick={isListening ? handleStopRecording : handleStartRecording}
disabled={disabled}
className={cn(
- 'absolute flex h-[30px] w-[30px] items-center justify-center rounded-lg p-0.5 transition-colors hover:bg-gray-200 dark:hover:bg-gray-700',
- isRTL
- ? 'bottom-1.5 left-4 md:bottom-3 md:left-12'
- : 'bottom-1.5 right-12 md:bottom-3 md:right-12',
+ 'absolute flex size-[35px] items-center justify-center rounded-full p-1 transition-colors hover:bg-surface-hover',
+ isRTL ? 'bottom-2 left-2' : 'bottom-2 right-2',
)}
description={localize('com_ui_use_micrphone')}
>
diff --git a/client/src/components/Chat/Input/ChatForm.tsx b/client/src/components/Chat/Input/ChatForm.tsx
index fafa17c34d..a4a0ca61af 100644
--- a/client/src/components/Chat/Input/ChatForm.tsx
+++ b/client/src/components/Chat/Input/ChatForm.tsx
@@ -156,7 +156,7 @@ const ChatForm = ({ index = 0 }) => {
/>
)}
-
+
{endpoint && (
@@ -181,7 +181,7 @@ const ChatForm = ({ index = 0 }) => {
endpointSupportsFiles && !isUploadDisabled
? 'pl-10 md:pl-[55px]'
: 'pl-3 md:pl-4',
- 'm-0 w-full resize-none border-0 bg-transparent py-[10px] placeholder-black/50 focus:ring-0 focus-visible:ring-0 dark:bg-transparent dark:placeholder-white/50 md:py-3.5 ',
+ 'md:py-3.5- m-0 w-full resize-none bg-surface-tertiary py-[13px] placeholder-black/50 dark:placeholder-white/50 [&:has(textarea:focus)]:shadow-[0_2px_6px_rgba(0,0,0,.05)]',
SpeechToText && !isRTL ? 'pr-20 md:pr-[85px]' : 'pr-10 md:pr-12',
'max-h-[65vh] md:max-h-[75vh]',
removeFocusRings,
@@ -189,22 +189,6 @@ const ChatForm = ({ index = 0 }) => {
/>
)}
- {(isSubmitting || isSubmittingAdded) && (showStopButton || showStopAdded) ? (
-
- ) : (
- endpoint && (
-
- )
- )}
{SpeechToText && (
{
)}
{TextToSpeech && automaticPlayback && }
+
+ {(isSubmitting || isSubmittingAdded) && (showStopButton || showStopAdded) ? (
+
+ ) : (
+ endpoint && (
+
+ )
+ )}
+
diff --git a/client/src/components/Chat/Input/Files/AttachFile.tsx b/client/src/components/Chat/Input/Files/AttachFile.tsx
index 1344c2ba34..e02aeae092 100644
--- a/client/src/components/Chat/Input/Files/AttachFile.tsx
+++ b/client/src/components/Chat/Input/Files/AttachFile.tsx
@@ -17,29 +17,22 @@ const AttachFile = ({
const isUploadDisabled = disabled ?? false;
return (
-
+
+
+
+
+
);
};
diff --git a/client/src/components/Chat/Input/Files/FileFormWrapper.tsx b/client/src/components/Chat/Input/Files/FileFormWrapper.tsx
index 81fd9f0258..230b303615 100644
--- a/client/src/components/Chat/Input/Files/FileFormWrapper.tsx
+++ b/client/src/components/Chat/Input/Files/FileFormWrapper.tsx
@@ -13,19 +13,17 @@ import AttachFile from './AttachFile';
import FileRow from './FileRow';
import store from '~/store';
-function FileFormWrapper({ children, disableInputs } : {
+function FileFormWrapper({
+ children,
+ disableInputs,
+}: {
disableInputs: boolean;
children?: React.ReactNode;
}) {
const { handleFileChange, abortUpload } = useFileHandling();
const chatDirection = useRecoilValue(store.chatDirection).toLowerCase();
- const {
- files,
- setFiles,
- conversation,
- setFilesLoading,
- } = useChatContext();
+ const { files, setFiles, conversation, setFilesLoading } = useChatContext();
const { data: fileConfig = defaultFileConfig } = useGetFileConfig({
select: (data) => mergeFileConfig(data),
});
@@ -33,30 +31,30 @@ function FileFormWrapper({ children, disableInputs } : {
const isRTL = chatDirection === 'rtl';
const { endpoint: _endpoint, endpointType } = conversation ?? { endpoint: null };
- const endpointFileConfig = fileConfig.endpoints[_endpoint ?? ''] as EndpointFileConfig | undefined;
+ const endpointFileConfig = fileConfig.endpoints[_endpoint ?? ''] as
+ | EndpointFileConfig
+ | undefined;
const endpointSupportsFiles: boolean = supportsFiles[endpointType ?? _endpoint ?? ''] ?? false;
const isUploadDisabled = (disableInputs || endpointFileConfig?.disabled) ?? false;
- return (<>
- (
-
- {children}
-
+ return (
+ <>
+ (
+ {children}
+ )}
+ />
+ {children}
+ {endpointSupportsFiles && !isUploadDisabled && (
+
)}
- />
- {children}
- {endpointSupportsFiles && !isUploadDisabled && }
- >);
+ >
+ );
}
-export default memo(FileFormWrapper);
\ No newline at end of file
+export default memo(FileFormWrapper);
diff --git a/client/src/components/Chat/Input/SendButton.tsx b/client/src/components/Chat/Input/SendButton.tsx
index 4b80f367ee..870d62d312 100644
--- a/client/src/components/Chat/Input/SendButton.tsx
+++ b/client/src/components/Chat/Input/SendButton.tsx
@@ -9,46 +9,40 @@ import { cn } from '~/utils';
type SendButtonProps = {
disabled: boolean;
control: Control<{ text: string }>;
- isRTL: boolean;
};
const SubmitButton = React.memo(
- forwardRef(
- (props: { disabled: boolean; isRTL: boolean }, ref: React.ForwardedRef) => {
- const localize = useLocalize();
- return (
-
-
-
-
-
- }
- >
- );
- },
- ),
+ forwardRef((props: { disabled: boolean }, ref: React.ForwardedRef) => {
+ const localize = useLocalize();
+ return (
+
+
+
+
+
+ }
+ >
+ );
+ }),
);
const SendButton = React.memo(
forwardRef((props: SendButtonProps, ref: React.ForwardedRef) => {
const data = useWatch({ control: props.control });
- return ;
+ return ;
}),
);
diff --git a/client/src/components/Chat/Input/StopButton.tsx b/client/src/components/Chat/Input/StopButton.tsx
index 28ac9bbff5..6c785811cd 100644
--- a/client/src/components/Chat/Input/StopButton.tsx
+++ b/client/src/components/Chat/Input/StopButton.tsx
@@ -1,36 +1,37 @@
+import { TooltipAnchor } from '~/components/ui';
+import { useLocalize } from '~/hooks';
import { cn } from '~/utils';
-export default function StopButton({ stop, setShowStopButton, isRTL }) {
+export default function StopButton({ stop, setShowStopButton }) {
+ const localize = useLocalize();
+
return (
-
-
-
+
+
+ }
+ >
);
}
diff --git a/client/src/components/Chat/Input/TextareaHeader.tsx b/client/src/components/Chat/Input/TextareaHeader.tsx
index e4df93c993..d4aa3f0cc7 100644
--- a/client/src/components/Chat/Input/TextareaHeader.tsx
+++ b/client/src/components/Chat/Input/TextareaHeader.tsx
@@ -13,7 +13,7 @@ export default function TextareaHeader({
return null;
}
return (
-
+
);
diff --git a/client/src/components/Input/SetKeyDialog/InputWithLabel.tsx b/client/src/components/Input/SetKeyDialog/InputWithLabel.tsx
index a13975b33b..9517f91737 100644
--- a/client/src/components/Input/SetKeyDialog/InputWithLabel.tsx
+++ b/client/src/components/Input/SetKeyDialog/InputWithLabel.tsx
@@ -29,6 +29,7 @@ const InputWithLabel: FC
= forwardRef((props, ref) => {
)}
+
= forwardRef((props, ref) => {
onChange={onChange}
ref={ref}
placeholder={`${localize('com_endpoint_config_value')} ${label}`}
- className={cn(
- defaultTextProps,
- 'flex h-10 max-h-10 w-full resize-none px-3 py-2',
- removeFocusOutlines,
- inputClassName,
- )}
+ className={cn('flex h-10 max-h-10 w-full resize-none px-3 py-2')}
/>
>
);
diff --git a/client/src/components/Input/SetKeyDialog/SetKeyDialog.tsx b/client/src/components/Input/SetKeyDialog/SetKeyDialog.tsx
index b5ecb3b7c7..fc371d73a3 100644
--- a/client/src/components/Input/SetKeyDialog/SetKeyDialog.tsx
+++ b/client/src/components/Input/SetKeyDialog/SetKeyDialog.tsx
@@ -3,9 +3,9 @@ import { useForm, FormProvider } from 'react-hook-form';
import { EModelEndpoint, alternateName, isAssistantsEndpoint } from 'librechat-data-provider';
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
import type { TDialogProps } from '~/common';
-import DialogTemplate from '~/components/ui/DialogTemplate';
+import OGDialogTemplate from '~/components/ui/OGDialogTemplate';
import { RevokeKeysButton } from '~/components/Nav';
-import { Dialog, Dropdown } from '~/components/ui';
+import { OGDialog, Dropdown } from '~/components/ui';
import { useUserKey, useLocalize } from '~/hooks';
import { useToastContext } from '~/Providers';
import CustomConfig from './CustomEndpoint';
@@ -160,10 +160,11 @@ const SetKeyDialog = ({
const config = endpointsConfig?.[endpoint];
return (
-
+
);
};
diff --git a/client/src/components/Nav/AccountSettings.tsx b/client/src/components/Nav/AccountSettings.tsx
index b6f09f65fd..50678c848e 100644
--- a/client/src/components/Nav/AccountSettings.tsx
+++ b/client/src/components/Nav/AccountSettings.tsx
@@ -30,7 +30,7 @@ function AccountSettings() {
diff --git a/client/src/components/Nav/Bookmarks/BookmarkNav.tsx b/client/src/components/Nav/Bookmarks/BookmarkNav.tsx
index d0fae61c46..452a97a7de 100644
--- a/client/src/components/Nav/Bookmarks/BookmarkNav.tsx
+++ b/client/src/components/Nav/Bookmarks/BookmarkNav.tsx
@@ -41,7 +41,7 @@ const BookmarkNav: FC
= ({ tags, setTags, isSmallScreen }: Boo
className={cn(
'mt-text-sm flex h-10 w-full items-center gap-2 rounded-lg p-2 text-sm transition-colors duration-200 hover:bg-surface-hover',
open ? 'bg-surface-hover' : '',
- isSmallScreen ? 'h-14 rounded-2xl' : '',
+ isSmallScreen ? 'h-12' : '',
)}
data-testid="bookmark-menu"
>
diff --git a/client/src/components/Nav/ClearConvos.tsx b/client/src/components/Nav/ClearConvos.tsx
deleted file mode 100644
index 310899f35c..0000000000
--- a/client/src/components/Nav/ClearConvos.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import { useState } from 'react';
-import { useClearConversationsMutation } from 'librechat-data-provider/react-query';
-import { useLocalize, useConversation, useConversations } from '~/hooks';
-import DialogTemplate from '~/components/ui/DialogTemplate';
-import { ClearChatsButton } from './SettingsTabs';
-import { Dialog } from '~/components/ui';
-
-const ClearConvos = ({ open, onOpenChange }) => {
- const { newConversation } = useConversation();
- const { refreshConversations } = useConversations();
- const clearConvosMutation = useClearConversationsMutation();
- const [confirmClear, setConfirmClear] = useState(false);
- const localize = useLocalize();
-
- // Clear all conversations
- const clearConvos = () => {
- if (confirmClear) {
- clearConvosMutation.mutate(
- {},
- {
- onSuccess: () => {
- newConversation();
- refreshConversations();
- },
- },
- );
- setConfirmClear(false);
- } else {
- setConfirmClear(true);
- }
- };
-
- return (
-
- );
-};
-
-export default ClearConvos;
diff --git a/client/src/components/Nav/Nav.tsx b/client/src/components/Nav/Nav.tsx
index acf2284b39..ffc2bbadce 100644
--- a/client/src/components/Nav/Nav.tsx
+++ b/client/src/components/Nav/Nav.tsx
@@ -168,36 +168,22 @@ const Nav = ({
onMouseLeave={handleMouseLeave}
ref={containerRef}
>
- {isSmallScreen == true ? (
-
- {isSearchEnabled === true && (
-
- )}
- {hasAccessToBookmarks === true && (
+
+ {isSearchEnabled === true && (
+
+ )}
- )}
-
- ) : (
-
- {isSearchEnabled === true && (
-
- )}
-
- >
- }
- />
- )}
+ >
+ }
+ />
{
@@ -57,10 +58,12 @@ export default function NewChat({
index = 0,
toggleNav,
subHeaders,
+ isSmallScreen,
}: {
index?: number;
toggleNav: () => void;
subHeaders?: React.ReactNode;
+ isSmallScreen: boolean;
}) {
/** Note: this component needs an explicit index passed if using more than one */
const { newConversation: newConvo } = useNewConvo(index);
@@ -86,7 +89,10 @@ export default function NewChat({
tabIndex={0}
data-testid="nav-new-chat"
onClick={clickHandler}
- className="group flex h-10 items-center gap-2 rounded-lg px-2 font-medium transition-colors duration-200 hover:bg-surface-hover"
+ className={cn(
+ 'group flex h-10 items-center gap-2 rounded-lg px-2 font-medium transition-colors duration-200 hover:bg-surface-hover',
+ isSmallScreen ? 'h-14' : '',
+ )}
aria-label={localize('com_ui_new_chat')}
>
diff --git a/client/src/components/Nav/Settings.tsx b/client/src/components/Nav/Settings.tsx
index 4adfc8be5a..19f8fe13e7 100644
--- a/client/src/components/Nav/Settings.tsx
+++ b/client/src/components/Nav/Settings.tsx
@@ -76,11 +76,11 @@ export default function Settings({ open, onOpenChange }: TDialogProps) {
diff --git a/client/src/components/Nav/SettingsTabs/Account/Avatar.tsx b/client/src/components/Nav/SettingsTabs/Account/Avatar.tsx
index eb04d3f068..f18b7a88bc 100644
--- a/client/src/components/Nav/SettingsTabs/Account/Avatar.tsx
+++ b/client/src/components/Nav/SettingsTabs/Account/Avatar.tsx
@@ -5,16 +5,17 @@ import AvatarEditor from 'react-avatar-editor';
import { fileConfig as defaultFileConfig, mergeFileConfig } from 'librechat-data-provider';
import type { TUser } from 'librechat-data-provider';
import {
+ Slider,
+ Button,
+ Spinner,
OGDialog,
OGDialogContent,
OGDialogHeader,
OGDialogTitle,
OGDialogTrigger,
- Slider,
-} from '~/components/ui';
+} from '~/components';
import { useUploadAvatarMutation, useGetFileConfig } from '~/data-provider';
import { useToastContext } from '~/Providers';
-import { Spinner } from '~/components/svg';
import { cn, formatBytes } from '~/utils';
import { useLocalize } from '~/hooks';
import store from '~/store';
@@ -130,10 +131,7 @@ function Avatar() {
-
+
{image ? localize('com_ui_preview') : localize('com_ui_upload_image')}
@@ -174,10 +172,10 @@ function Avatar() {
-
)}
{localize('com_ui_upload')}
-
+
>
) : (
-
+
{localize('com_ui_drag_drop')}
-
{
const localize = useLocalize();
@@ -15,14 +23,8 @@ const DeleteAccount = ({ disabled = false }: { title?: string; disabled?: boolea
});
const [isDialogOpen, setDialogOpen] = useState
(false);
- const [deleteInput, setDeleteInput] = useState('');
- const [emailInput, setEmailInput] = useState('');
const [isLocked, setIsLocked] = useState(true);
- const onClick = useCallback(() => {
- setDialogOpen(true);
- }, []);
-
const handleDeleteUser = () => {
if (!isLocked) {
deleteUser(undefined);
@@ -30,47 +32,38 @@ const DeleteAccount = ({ disabled = false }: { title?: string; disabled?: boolea
};
const handleInputChange = useCallback(
- (newEmailInput: string, newDeleteInput: string) => {
+ (newEmailInput: string) => {
const isEmailCorrect =
- newEmailInput.trim().toLowerCase() === user?.email?.trim().toLowerCase();
- const isDeleteInputCorrect = newDeleteInput === 'DELETE';
- setIsLocked(!(isEmailCorrect && isDeleteInputCorrect));
+ newEmailInput.trim().toLowerCase() === user?.email.trim().toLowerCase();
+ setIsLocked(!isEmailCorrect);
},
[user?.email],
);
return (
<>
-
- {localize('com_nav_delete_account')}
-
-
-
+
+
>
);
};
@@ -113,17 +92,10 @@ const renderInput = (
onChange: (e: React.ChangeEvent) => void,
) => (
-
-
+
+
);
@@ -135,12 +107,8 @@ const renderDeleteButton = (
) => (
{isLocked ? (
<>
-
+
{localize('com_ui_locked')}
>
) : (
<>
-
+
{localize('com_nav_delete_account_button')}
>
)}
diff --git a/client/src/components/Nav/SettingsTabs/Data/ClearChats.tsx b/client/src/components/Nav/SettingsTabs/Data/ClearChats.tsx
index 4fc2dadd8e..745768518a 100644
--- a/client/src/components/Nav/SettingsTabs/Data/ClearChats.tsx
+++ b/client/src/components/Nav/SettingsTabs/Data/ClearChats.tsx
@@ -1,29 +1,58 @@
-import type { TDangerButtonProps } from '~/common';
-import DangerButton from '../DangerButton';
+import React, { useState } from 'react';
+import { useClearConversationsMutation } from 'librechat-data-provider/react-query';
+import { Label, Button, OGDialog, OGDialogTrigger, Spinner } from '~/components';
+import { useConversation, useConversations, useLocalize } from '~/hooks';
+import OGDialogTemplate from '~/components/ui/OGDialogTemplate';
+
+export const ClearChats = () => {
+ const localize = useLocalize();
+ const [open, setOpen] = useState(false);
+ const { newConversation } = useConversation();
+ const { refreshConversations } = useConversations();
+ const clearConvosMutation = useClearConversationsMutation();
+
+ const clearConvos = () => {
+ clearConvosMutation.mutate(
+ {},
+ {
+ onSuccess: () => {
+ newConversation();
+ refreshConversations();
+ },
+ },
+ );
+ };
-export const ClearChatsButton = ({
- confirmClear,
- className = '',
- showText = true,
- mutation,
- onClick,
-}: Pick<
- TDangerButtonProps,
- 'confirmClear' | 'mutation' | 'className' | 'showText' | 'onClick'
->) => {
return (
-
+
+
+
+
+ setOpen(true)}
+ >
+ {localize('com_ui_delete')}
+
+
+
+ {localize('com_nav_clear_conversation_confirm_message')}
+
+ }
+ selection={{
+ selectHandler: clearConvos,
+ selectClasses:
+ 'bg-destructive text-white transition-all duration-200 hover:bg-destructive/80',
+ selectText: clearConvosMutation.isLoading ? : localize('com_ui_delete'),
+ }}
+ />
+
+
);
};
diff --git a/client/src/components/Nav/SettingsTabs/Data/ClearChatsButton.spec.tsx b/client/src/components/Nav/SettingsTabs/Data/ClearChatsButton.spec.tsx
deleted file mode 100644
index fbf82fd902..0000000000
--- a/client/src/components/Nav/SettingsTabs/Data/ClearChatsButton.spec.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import 'test/matchMedia.mock';
-import React from 'react';
-import { render, fireEvent } from '@testing-library/react';
-import '@testing-library/jest-dom/extend-expect';
-import { ClearChatsButton } from './ClearChats';
-import { RecoilRoot } from 'recoil';
-
-describe('ClearChatsButton', () => {
- let mockOnClick;
-
- beforeEach(() => {
- mockOnClick = jest.fn();
- });
-
- it('renders correctly', () => {
- const { getByText } = render(
-
-
- ,
- );
-
- expect(getByText('Clear all chats')).toBeInTheDocument();
- expect(getByText('Clear')).toBeInTheDocument();
- });
-
- it('renders confirm clear when confirmClear is true', () => {
- const { getByText } = render(
-
-
- ,
- );
-
- expect(getByText('Confirm Clear')).toBeInTheDocument();
- });
-
- it('calls onClick when the button is clicked', () => {
- const { getByText } = render(
-
-
- ,
- );
-
- fireEvent.click(getByText('Clear'));
-
- expect(mockOnClick).toHaveBeenCalled();
- });
-});
diff --git a/client/src/components/Nav/SettingsTabs/Data/Data.tsx b/client/src/components/Nav/SettingsTabs/Data/Data.tsx
index 6897a4a0b4..18c30d14a6 100644
--- a/client/src/components/Nav/SettingsTabs/Data/Data.tsx
+++ b/client/src/components/Nav/SettingsTabs/Data/Data.tsx
@@ -1,10 +1,9 @@
import React, { useState, useRef } from 'react';
-import { useClearConversationsMutation } from 'librechat-data-provider/react-query';
-import { useConversation, useConversations, useOnClickOutside } from '~/hooks';
-import { RevokeKeysButton } from './RevokeKeysButton';
-import { DeleteCacheButton } from './DeleteCacheButton';
import ImportConversations from './ImportConversations';
-import { ClearChatsButton } from './ClearChats';
+import { RevokeAllKeys } from './RevokeAllKeys';
+import { DeleteCache } from './DeleteCache';
+import { useOnClickOutside } from '~/hooks';
+import { ClearChats } from './ClearChats';
import SharedLinks from './SharedLinks';
function Data() {
@@ -12,28 +11,6 @@ function Data() {
const [confirmClearConvos, setConfirmClearConvos] = useState(false);
useOnClickOutside(dataTabRef, () => confirmClearConvos && setConfirmClearConvos(false), []);
- const { newConversation } = useConversation();
- const { refreshConversations } = useConversations();
- const clearConvosMutation = useClearConversationsMutation();
-
- const clearConvos = () => {
- if (confirmClearConvos) {
- console.log('Clearing conversations...');
- setConfirmClearConvos(false);
- clearConvosMutation.mutate(
- {},
- {
- onSuccess: () => {
- newConversation();
- refreshConversations();
- },
- },
- );
- } else {
- setConfirmClearConvos(true);
- }
- };
-
return (
@@ -43,18 +20,13 @@ function Data() {
-
+
-
+
-
+
);
diff --git a/client/src/components/Nav/SettingsTabs/Data/DeleteCache.tsx b/client/src/components/Nav/SettingsTabs/Data/DeleteCache.tsx
new file mode 100644
index 0000000000..a2d36da586
--- /dev/null
+++ b/client/src/components/Nav/SettingsTabs/Data/DeleteCache.tsx
@@ -0,0 +1,65 @@
+import React, { useState, useCallback, useRef, useEffect } from 'react';
+import { Label, Button, OGDialog, OGDialogTrigger, Spinner } from '~/components';
+import OGDialogTemplate from '~/components/ui/OGDialogTemplate';
+import { useOnClickOutside, useLocalize } from '~/hooks';
+
+export const DeleteCache = ({ disabled = false }: { disabled?: boolean }) => {
+ const localize = useLocalize();
+ const [open, setOpen] = useState(false);
+ const [isCacheEmpty, setIsCacheEmpty] = useState(true);
+ const [confirmClear, setConfirmClear] = useState(false);
+ const [isLoading, setIsLoading] = useState(false);
+ const contentRef = useRef(null);
+ useOnClickOutside(contentRef, () => confirmClear && setConfirmClear(false), []);
+
+ const checkCache = useCallback(async () => {
+ const cache = await caches.open('tts-responses');
+ const keys = await cache.keys();
+ setIsCacheEmpty(keys.length === 0);
+ }, []);
+
+ useEffect(() => {
+ checkCache();
+ }, [checkCache]);
+
+ const revokeAllUserKeys = useCallback(async () => {
+ setIsLoading(true);
+ const cache = await caches.open('tts-responses');
+ await cache.keys().then((keys) => Promise.all(keys.map((key) => cache.delete(key))));
+ setIsLoading(false);
+ }, []);
+
+ return (
+
+
+
+
+ setOpen(true)}
+ disabled={disabled || isCacheEmpty}
+ >
+ {localize('com_ui_delete')}
+
+
+
+ {localize('com_nav_clear_cache_confirm_message')}
+
+ }
+ selection={{
+ selectHandler: revokeAllUserKeys,
+ selectClasses:
+ 'bg-destructive text-white transition-all duration-200 hover:bg-destructive/80',
+ selectText: isLoading ? : localize('com_ui_delete'),
+ }}
+ />
+
+
+ );
+};
diff --git a/client/src/components/Nav/SettingsTabs/Data/DeleteCacheButton.tsx b/client/src/components/Nav/SettingsTabs/Data/DeleteCacheButton.tsx
deleted file mode 100644
index 84e444f203..0000000000
--- a/client/src/components/Nav/SettingsTabs/Data/DeleteCacheButton.tsx
+++ /dev/null
@@ -1,53 +0,0 @@
-import React, { useState, useCallback, useRef, useEffect } from 'react';
-import { useOnClickOutside } from '~/hooks';
-import DangerButton from '../DangerButton';
-
-export const DeleteCacheButton = ({
- showText = true,
- disabled = false,
-}: {
- showText?: boolean;
- disabled?: boolean;
-}) => {
- const [confirmClear, setConfirmClear] = useState(false);
- const [isCacheEmpty, setIsCacheEmpty] = useState(true);
- const contentRef = useRef(null);
- useOnClickOutside(contentRef, () => confirmClear && setConfirmClear(false), []);
-
- const checkCache = useCallback(async () => {
- const cache = await caches.open('tts-responses');
- const keys = await cache.keys();
- setIsCacheEmpty(keys.length === 0);
- }, []);
-
- useEffect(() => {
- checkCache();
- }, [confirmClear]);
-
- const revokeAllUserKeys = useCallback(async () => {
- if (confirmClear) {
- const cache = await caches.open('tts-responses');
- await cache.keys().then((keys) => Promise.all(keys.map((key) => cache.delete(key))));
-
- setConfirmClear(false);
- } else {
- setConfirmClear(true);
- }
- }, [confirmClear]);
-
- return (
-
- );
-};
diff --git a/client/src/components/Nav/SettingsTabs/Data/RevokeAllKeys.tsx b/client/src/components/Nav/SettingsTabs/Data/RevokeAllKeys.tsx
new file mode 100644
index 0000000000..1c03bc58f5
--- /dev/null
+++ b/client/src/components/Nav/SettingsTabs/Data/RevokeAllKeys.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import { RevokeKeysButton } from './RevokeKeysButton';
+import { Label } from '~/components/ui';
+import { useLocalize } from '~/hooks';
+
+export const RevokeAllKeys = () => {
+ const localize = useLocalize();
+
+ return (
+
+
+
+
+ );
+};
diff --git a/client/src/components/Nav/SettingsTabs/Data/RevokeKeysButton.tsx b/client/src/components/Nav/SettingsTabs/Data/RevokeKeysButton.tsx
index 1d5dd82956..806ab8fbf4 100644
--- a/client/src/components/Nav/SettingsTabs/Data/RevokeKeysButton.tsx
+++ b/client/src/components/Nav/SettingsTabs/Data/RevokeKeysButton.tsx
@@ -2,64 +2,77 @@ import {
useRevokeAllUserKeysMutation,
useRevokeUserKeyMutation,
} from 'librechat-data-provider/react-query';
-import React, { useState, useCallback, useRef } from 'react';
-import { useOnClickOutside } from '~/hooks';
-import DangerButton from '../DangerButton';
+import React, { useState } from 'react';
+import { Button, Label, OGDialog, OGDialogTrigger, Spinner } from '~/components';
+import OGDialogTemplate from '~/components/ui/OGDialogTemplate';
+import { useLocalize } from '~/hooks';
export const RevokeKeysButton = ({
- showText = true,
endpoint = '',
all = false,
disabled = false,
+ setDialogOpen,
}: {
- showText?: boolean;
endpoint?: string;
all?: boolean;
disabled?: boolean;
+ setDialogOpen?: (open: boolean) => void;
}) => {
- const [confirmClear, setConfirmClear] = useState(false);
+ const localize = useLocalize();
+ const [open, setOpen] = useState(false);
const revokeKeyMutation = useRevokeUserKeyMutation(endpoint);
const revokeKeysMutation = useRevokeAllUserKeysMutation();
- const contentRef = useRef(null);
- useOnClickOutside(contentRef, () => confirmClear && setConfirmClear(false), []);
-
- const revokeAllUserKeys = useCallback(() => {
- if (confirmClear) {
- revokeKeysMutation.mutate({});
- setConfirmClear(false);
- } else {
- setConfirmClear(true);
- }
- }, [confirmClear, revokeKeysMutation]);
-
- const revokeUserKey = useCallback(() => {
- if (!endpoint) {
+ const handleSuccess = () => {
+ if (!setDialogOpen) {
return;
- } else if (confirmClear) {
- revokeKeyMutation.mutate({});
- setConfirmClear(false);
- } else {
- setConfirmClear(true);
}
- }, [confirmClear, revokeKeyMutation, endpoint]);
- const onClick = all ? revokeAllUserKeys : revokeUserKey;
+ setDialogOpen(false);
+ };
+
+ const onClick = () => {
+ if (all) {
+ revokeKeysMutation.mutate({});
+ } else {
+ revokeKeyMutation.mutate({}, { onSuccess: handleSuccess });
+ }
+ };
+
+ const dialogTitle = all
+ ? localize('com_ui_revoke_keys')
+ : localize('com_ui_revoke_key_endpoint', endpoint);
+
+ const dialogMessage = all
+ ? localize('com_ui_revoke_keys_confirm')
+ : localize('com_ui_revoke_key_confirm');
+
+ const isLoading = revokeKeyMutation.isLoading || revokeKeysMutation.isLoading;
return (
-
+
+
+ setOpen(true)}
+ disabled={disabled}
+ >
+ {localize('com_ui_revoke')}
+
+
+ {dialogMessage}}
+ selection={{
+ selectHandler: onClick,
+ selectClasses:
+ 'bg-destructive text-white transition-all duration-200 hover:bg-destructive/80',
+ selectText: isLoading ? : localize('com_ui_revoke'),
+ }}
+ />
+
);
};
diff --git a/client/src/components/Nav/index.ts b/client/src/components/Nav/index.ts
index 5770793712..6ed5de4453 100644
--- a/client/src/components/Nav/index.ts
+++ b/client/src/components/Nav/index.ts
@@ -1,6 +1,5 @@
export * from './ExportConversation';
export * from './SettingsTabs/';
-export { default as ClearConvos } from './ClearConvos';
export { default as MobileNav } from './MobileNav';
export { default as Nav } from './Nav';
export { default as NavLink } from './NavLink';
diff --git a/client/src/components/SidePanel/Agents/FileSearch.tsx b/client/src/components/SidePanel/Agents/FileSearch.tsx
index 84263f3566..9e4c061bd3 100644
--- a/client/src/components/SidePanel/Agents/FileSearch.tsx
+++ b/client/src/components/SidePanel/Agents/FileSearch.tsx
@@ -78,7 +78,7 @@ export default function FileSearch({
diff --git a/client/src/components/SidePanel/Agents/ShareAgent.tsx b/client/src/components/SidePanel/Agents/ShareAgent.tsx
index f4182900d8..5c2a7888c5 100644
--- a/client/src/components/SidePanel/Agents/ShareAgent.tsx
+++ b/client/src/components/SidePanel/Agents/ShareAgent.tsx
@@ -5,6 +5,7 @@ import { Permissions } from 'librechat-data-provider';
import { useGetStartupConfig } from 'librechat-data-provider/react-query';
import type { TStartupConfig, AgentUpdateParams } from 'librechat-data-provider';
import {
+ Button,
Switch,
OGDialog,
OGDialogTitle,
@@ -146,7 +147,7 @@ export default function ShareAgent({
-
+
{localize(
'com_ui_share_var',
@@ -255,13 +256,14 @@ export default function ShareAgent({
-
{localize('com_ui_save')}
-
+
diff --git a/client/src/components/SidePanel/Bookmarks/BookmarkPanel.tsx b/client/src/components/SidePanel/Bookmarks/BookmarkPanel.tsx
index aebe235467..5d30859d08 100644
--- a/client/src/components/SidePanel/Bookmarks/BookmarkPanel.tsx
+++ b/client/src/components/SidePanel/Bookmarks/BookmarkPanel.tsx
@@ -18,8 +18,8 @@ const BookmarkPanel = () => {
-
setOpen(!open)}>
-
+ setOpen(!open)}>
+
{localize('com_ui_bookmarks_new')}
diff --git a/client/src/components/ui/Button.tsx b/client/src/components/ui/Button.tsx
index 64989f4d1a..9b6a6aaf5c 100644
--- a/client/src/components/ui/Button.tsx
+++ b/client/src/components/ui/Button.tsx
@@ -9,12 +9,13 @@ const buttonVariants = cva(
variants: {
variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
- destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
+ destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/80',
outline:
'text-text-primary border border-input bg-background hover:bg-accent hover:text-accent-foreground',
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline',
+ submit: 'bg-surface-submit text-text-primary hover:bg-surface-submit/90',
},
size: {
default: 'h-10 px-4 py-2',
diff --git a/client/src/components/ui/Input.tsx b/client/src/components/ui/Input.tsx
index 042f6a5690..adc3b422c1 100644
--- a/client/src/components/ui/Input.tsx
+++ b/client/src/components/ui/Input.tsx
@@ -8,7 +8,7 @@ const Input = React.forwardRef
(({ className, ...pr
return (
void;
selectClasses?: string;
- selectText?: string;
+ selectText?: string | ReactNode;
};
type DialogTemplateProps = {
@@ -81,7 +81,7 @@ const OGDialogTemplate = forwardRef((props: DialogTemplateProps, ref: Ref
{selectText}
diff --git a/client/src/components/ui/OriginalDialog.tsx b/client/src/components/ui/OriginalDialog.tsx
index f68746b9ff..b9abd9e9e4 100644
--- a/client/src/components/ui/OriginalDialog.tsx
+++ b/client/src/components/ui/OriginalDialog.tsx
@@ -41,7 +41,7 @@ const DialogContent = React.forwardRef<
=> {
return request.get(`${endpoints.files()}/config`);
};
-export const uploadImage = (data: FormData, signal?: AbortSignal | null): Promise => {
+export const uploadImage = (
+ data: FormData,
+ signal?: AbortSignal | null,
+): Promise => {
const requestConfig = signal ? { signal } : undefined;
return request.postMultiPart(endpoints.images(), data, requestConfig);
};