diff --git a/client/src/components/Chat/Input/Files/Table/DataTable.tsx b/client/src/components/Chat/Input/Files/Table/DataTable.tsx index 31e7296af3..c8c3190bcb 100644 --- a/client/src/components/Chat/Input/Files/Table/DataTable.tsx +++ b/client/src/components/Chat/Input/Files/Table/DataTable.tsx @@ -1,5 +1,6 @@ import { useState } from 'react'; import { ListFilter } from 'lucide-react'; +import { useSetRecoilState } from 'recoil'; import { flexRender, getCoreRowModel, @@ -36,6 +37,7 @@ import { TrashIcon, Spinner } from '~/components/svg'; import useLocalize from '~/hooks/useLocalize'; import { useMediaQuery } from '~/hooks'; import { cn } from '~/utils'; +import store from '~/store'; interface DataTableProps { columns: ColumnDef[]; @@ -60,12 +62,14 @@ type Style = { export default function DataTable({ columns, data }: DataTableProps) { const localize = useLocalize(); const [isDeleting, setIsDeleting] = useState(false); + const setFiles = useSetRecoilState(store.filesByIndex(0)); + const { deleteFiles } = useDeleteFilesFromTable(() => setIsDeleting(false)); + const [rowSelection, setRowSelection] = useState({}); const [sorting, setSorting] = useState([]); const isSmallScreen = useMediaQuery('(max-width: 768px)'); const [columnFilters, setColumnFilters] = useState([]); const [columnVisibility, setColumnVisibility] = useState({}); - const { deleteFiles } = useDeleteFilesFromTable(() => setIsDeleting(false)); const table = useReactTable({ data, @@ -96,7 +100,7 @@ export default function DataTable({ columns, data }: DataTablePro const filesToDelete = table .getFilteredSelectedRowModel() .rows.map((row) => row.original); - deleteFiles({ files: filesToDelete as TFile[] }); + deleteFiles({ files: filesToDelete as TFile[], setFiles }); setRowSelection({}); }} disabled={!table.getFilteredSelectedRowModel().rows.length || isDeleting} @@ -218,13 +222,10 @@ export default function DataTable({ columns, data }: DataTablePro
- {localize( - 'com_files_number_selected', - { - 0: `${table.getFilteredSelectedRowModel().rows.length}`, - 1: `${table.getFilteredRowModel().rows.length}`, - }, - )} + {localize('com_files_number_selected', { + 0: `${table.getFilteredSelectedRowModel().rows.length}`, + 1: `${table.getFilteredRowModel().rows.length}`, + })} {`${table.getFilteredSelectedRowModel().rows.length}/${ diff --git a/client/src/components/Chat/Messages/Content/Parts/Attachment.tsx b/client/src/components/Chat/Messages/Content/Parts/Attachment.tsx index d6b9b00b2c..43e7eeb19e 100644 --- a/client/src/components/Chat/Messages/Content/Parts/Attachment.tsx +++ b/client/src/components/Chat/Messages/Content/Parts/Attachment.tsx @@ -6,12 +6,12 @@ import Image from '~/components/Chat/Messages/Content/Image'; import { useAttachmentLink } from './LogLink'; import { cn } from '~/utils'; -const FileAttachment = memo(({ attachment }: { attachment: TAttachment }) => { +const FileAttachment = memo(({ attachment }: { attachment: Partial }) => { const { handleDownload } = useAttachmentLink({ - href: attachment.filepath, - filename: attachment.filename, + href: attachment.filepath ?? '', + filename: attachment.filename ?? '', }); - const extension = attachment.filename.split('.').pop(); + const extension = attachment.filename?.split('.').pop(); const [isVisible, setIsVisible] = useState(false); useEffect(() => { @@ -19,6 +19,9 @@ const FileAttachment = memo(({ attachment }: { attachment: TAttachment }) => { return () => clearTimeout(timer); }, []); + if (!attachment.filepath) { + return null; + } return (
; + } else if (!attachment.filepath) { + return null; } return ; } @@ -119,9 +124,11 @@ export function AttachmentGroup({ attachments }: { attachments?: TAttachment[] } <> {fileAttachments.length > 0 && (
- {fileAttachments.map((attachment, index) => ( - - ))} + {fileAttachments.map((attachment, index) => + attachment.filepath ? ( + + ) : null, + )}
)} {imageAttachments.length > 0 && ( diff --git a/client/src/components/Files/ActionButton.tsx b/client/src/components/Files/ActionButton.tsx index 854d152ce2..03f58da6c8 100644 --- a/client/src/components/Files/ActionButton.tsx +++ b/client/src/components/Files/ActionButton.tsx @@ -1,19 +1,21 @@ import React from 'react'; -import { CrossIcon } from '~/components/svg'; import { Button } from '~/components/ui'; +import { useLocalize } from '~/hooks'; type ActionButtonProps = { onClick: () => void; }; export default function ActionButton({ onClick }: ActionButtonProps) { + const localize = useLocalize(); return (
); diff --git a/client/src/components/Files/FileList/DataTableFile.tsx b/client/src/components/Files/FileList/DataTableFile.tsx index 281e9cec1d..d64699e2ea 100644 --- a/client/src/components/Files/FileList/DataTableFile.tsx +++ b/client/src/components/Files/FileList/DataTableFile.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { ListFilter } from 'lucide-react'; +import { useSetRecoilState } from 'recoil'; import { flexRender, getCoreRowModel, @@ -18,24 +19,25 @@ import { FileContext } from 'librechat-data-provider'; import type { AugmentedColumnDef } from '~/common'; import type { TFile } from 'librechat-data-provider'; import { - Button, Input, Table, + Button, + TableRow, TableBody, TableCell, TableHead, TableHeader, - TableRow, DropdownMenu, - DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuTrigger, + DropdownMenuCheckboxItem, } from '~/components/ui'; +import ActionButton from '~/components/Files/ActionButton'; import { useDeleteFilesFromTable } from '~/hooks/Files'; import { TrashIcon, Spinner } from '~/components/svg'; -import useLocalize from '~/hooks/useLocalize'; -import ActionButton from '../ActionButton'; import UploadFileButton from './UploadFileButton'; +import useLocalize from '~/hooks/useLocalize'; +import store from '~/store'; interface DataTableProps { columns: ColumnDef[]; @@ -57,12 +59,14 @@ export default function DataTableFile({ data, }: DataTableProps) { const localize = useLocalize(); + const setFiles = useSetRecoilState(store.filesByIndex(0)); const [isDeleting, setIsDeleting] = React.useState(false); + const { deleteFiles } = useDeleteFilesFromTable(() => setIsDeleting(false)); + const [rowSelection, setRowSelection] = React.useState({}); const [sorting, setSorting] = React.useState([]); const [columnFilters, setColumnFilters] = React.useState([]); const [columnVisibility, setColumnVisibility] = React.useState({}); - const { deleteFiles } = useDeleteFilesFromTable(() => setIsDeleting(false)); const table = useReactTable({ data, @@ -87,7 +91,7 @@ export default function DataTableFile({ <>

- Files + {localize('com_ui_files')}

@@ -103,7 +107,7 @@ export default function DataTableFile({ const filesToDelete = table .getFilteredSelectedRowModel() .rows.map((row) => row.original); - deleteFiles({ files: filesToDelete as TFile[] }); + deleteFiles({ files: filesToDelete as TFile[], setFiles }); setRowSelection({}); }} className="ml-1 gap-2 dark:hover:bg-gray-850/25 sm:ml-0" @@ -242,13 +246,11 @@ export default function DataTableFile({
-
- {localize( - 'com_files_number_selected', { - 0: `${table.getFilteredSelectedRowModel().rows.length}`, - 1: `${table.getFilteredRowModel().rows.length}`, - }, - )} +
+ {localize('com_files_number_selected', { + 0: `${table.getFilteredSelectedRowModel().rows.length}`, + 1: `${table.getFilteredRowModel().rows.length}`, + })}