mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
### What problem does this PR solve? Feat: Deleting files in batches. #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
47
web/src/components/bulk-operate-bar.tsx
Normal file
47
web/src/components/bulk-operate-bar.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { ReactNode, useCallback } from 'react';
|
||||
import { ConfirmDeleteDialog } from './confirm-delete-dialog';
|
||||
|
||||
export type BulkOperateItemType = {
|
||||
id: string;
|
||||
label: ReactNode;
|
||||
icon: ReactNode;
|
||||
onClick(): void;
|
||||
};
|
||||
|
||||
type BulkOperateBarProps = { list: BulkOperateItemType[] };
|
||||
|
||||
export function BulkOperateBar({ list }: BulkOperateBarProps) {
|
||||
const isDeleteItem = useCallback((id: string) => {
|
||||
return id === 'delete';
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Card className="mb-4">
|
||||
<CardContent className="p-1">
|
||||
<ul className="flex gap-2">
|
||||
{list.map((x) => (
|
||||
<li
|
||||
key={x.id}
|
||||
className={cn({ ['text-text-delete-red']: isDeleteItem(x.id) })}
|
||||
>
|
||||
<ConfirmDeleteDialog
|
||||
hidden={!isDeleteItem(x.id)}
|
||||
onOk={x.onClick}
|
||||
>
|
||||
<Button
|
||||
variant={'ghost'}
|
||||
onClick={isDeleteItem(x.id) ? () => {} : x.onClick}
|
||||
>
|
||||
{x.icon} {x.label}
|
||||
</Button>
|
||||
</ConfirmDeleteDialog>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@ -16,15 +16,21 @@ interface IProps {
|
||||
title?: string;
|
||||
onOk?: (...args: any[]) => any;
|
||||
onCancel?: (...args: any[]) => any;
|
||||
hidden?: boolean;
|
||||
}
|
||||
|
||||
export function ConfirmDeleteDialog({
|
||||
children,
|
||||
title,
|
||||
onOk,
|
||||
hidden = false,
|
||||
}: IProps & PropsWithChildren) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (hidden) {
|
||||
return children;
|
||||
}
|
||||
|
||||
return (
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>{children}</AlertDialogTrigger>
|
||||
|
||||
@ -1,9 +1,18 @@
|
||||
import { IFolder } from '@/interfaces/database/file-manager';
|
||||
import {
|
||||
IFetchFileListResult,
|
||||
IFolder,
|
||||
} from '@/interfaces/database/file-manager';
|
||||
import fileManagerService from '@/services/file-manager-service';
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { message } from 'antd';
|
||||
import { useDebounce } from 'ahooks';
|
||||
import { PaginationProps, message } from 'antd';
|
||||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSearchParams } from 'umi';
|
||||
import {
|
||||
useGetPaginationWithRouter,
|
||||
useHandleSearchChange,
|
||||
} from './logic-hooks';
|
||||
import { useSetPaginationParams } from './route-hook';
|
||||
|
||||
export const enum FileApiAction {
|
||||
@ -12,6 +21,7 @@ export const enum FileApiAction {
|
||||
MoveFile = 'moveFile',
|
||||
CreateFolder = 'createFolder',
|
||||
FetchParentFolderList = 'fetchParentFolderList',
|
||||
DeleteFile = 'deleteFile',
|
||||
}
|
||||
|
||||
export const useGetFolderId = () => {
|
||||
@ -136,3 +146,85 @@ export const useFetchParentFolderList = () => {
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
export interface IListResult {
|
||||
searchString: string;
|
||||
handleInputChange: React.ChangeEventHandler<HTMLInputElement>;
|
||||
pagination: PaginationProps;
|
||||
setPagination: (pagination: { page: number; pageSize: number }) => void;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
export const useFetchFileList = () => {
|
||||
const { searchString, handleInputChange } = useHandleSearchChange();
|
||||
const { pagination, setPagination } = useGetPaginationWithRouter();
|
||||
const id = useGetFolderId();
|
||||
const debouncedSearchString = useDebounce(searchString, { wait: 500 });
|
||||
|
||||
const { data, isFetching: loading } = useQuery<IFetchFileListResult>({
|
||||
queryKey: [
|
||||
FileApiAction.FetchFileList,
|
||||
{
|
||||
id,
|
||||
debouncedSearchString,
|
||||
...pagination,
|
||||
},
|
||||
],
|
||||
initialData: { files: [], parent_folder: {} as IFolder, total: 0 },
|
||||
gcTime: 0,
|
||||
queryFn: async () => {
|
||||
const { data } = await fileManagerService.listFile({
|
||||
parent_id: id,
|
||||
keywords: debouncedSearchString,
|
||||
page_size: pagination.pageSize,
|
||||
page: pagination.current,
|
||||
});
|
||||
|
||||
return data?.data;
|
||||
},
|
||||
});
|
||||
|
||||
const onInputChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(
|
||||
(e) => {
|
||||
setPagination({ page: 1 });
|
||||
handleInputChange(e);
|
||||
},
|
||||
[handleInputChange, setPagination],
|
||||
);
|
||||
|
||||
return {
|
||||
...data,
|
||||
searchString,
|
||||
handleInputChange: onInputChange,
|
||||
pagination: { ...pagination, total: data?.total },
|
||||
setPagination,
|
||||
loading,
|
||||
};
|
||||
};
|
||||
|
||||
export const useDeleteFile = () => {
|
||||
const { setPaginationParams } = useSetPaginationParams();
|
||||
const queryClient = useQueryClient();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const {
|
||||
data,
|
||||
isPending: loading,
|
||||
mutateAsync,
|
||||
} = useMutation({
|
||||
mutationKey: [FileApiAction.DeleteFile],
|
||||
mutationFn: async (params: { fileIds: string[]; parentId: string }) => {
|
||||
const { data } = await fileManagerService.removeFile(params);
|
||||
if (data.code === 0) {
|
||||
message.success(t('message.deleted'));
|
||||
setPaginationParams(1); // TODO: There should be a better way to paginate the request list
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [FileApiAction.FetchFileList],
|
||||
});
|
||||
}
|
||||
return data.code;
|
||||
},
|
||||
});
|
||||
|
||||
return { data, loading, deleteFile: mutateAsync };
|
||||
};
|
||||
|
||||
@ -31,3 +31,9 @@ export interface IFolder {
|
||||
update_time: number;
|
||||
source_type: string;
|
||||
}
|
||||
|
||||
export type IFetchFileListResult = {
|
||||
files: IFile[];
|
||||
parent_folder: IFolder;
|
||||
total: number;
|
||||
};
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
import { BulkOperateBar } from '@/components/bulk-operate-bar';
|
||||
import { FileUploadDialog } from '@/components/file-upload-dialog';
|
||||
import ListFilterBar from '@/components/list-filter-bar';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Upload } from 'lucide-react';
|
||||
import { DatasetTable } from './dataset-table';
|
||||
import { useBulkOperateDataset } from './use-bulk-operate-dataset';
|
||||
import { useHandleUploadDocument } from './use-upload-document';
|
||||
|
||||
export default function Dataset() {
|
||||
@ -13,6 +15,8 @@ export default function Dataset() {
|
||||
onDocumentUploadOk,
|
||||
documentUploadLoading,
|
||||
} = useHandleUploadDocument();
|
||||
const { list } = useBulkOperateDataset();
|
||||
|
||||
return (
|
||||
<section className="p-8">
|
||||
<ListFilterBar title="Files">
|
||||
@ -25,8 +29,8 @@ export default function Dataset() {
|
||||
Upload file
|
||||
</Button>
|
||||
</ListFilterBar>
|
||||
<BulkOperateBar list={list}></BulkOperateBar>
|
||||
<DatasetTable></DatasetTable>
|
||||
|
||||
{documentUploadVisible && (
|
||||
<FileUploadDialog
|
||||
hideModal={hideDocumentUploadModal}
|
||||
|
||||
41
web/src/pages/dataset/dataset/use-bulk-operate-dataset.tsx
Normal file
41
web/src/pages/dataset/dataset/use-bulk-operate-dataset.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import { Ban, CircleCheck, CircleX, Play, Trash2 } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export function useBulkOperateDataset() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const list = [
|
||||
{
|
||||
id: 'enabled',
|
||||
label: t('knowledgeDetails.enabled'),
|
||||
icon: <CircleCheck />,
|
||||
onClick: () => {},
|
||||
},
|
||||
{
|
||||
id: 'disabled',
|
||||
label: t('knowledgeDetails.disabled'),
|
||||
icon: <Ban />,
|
||||
onClick: () => {},
|
||||
},
|
||||
{
|
||||
id: 'run',
|
||||
label: t('knowledgeDetails.run'),
|
||||
icon: <Play />,
|
||||
onClick: () => {},
|
||||
},
|
||||
{
|
||||
id: 'cancel',
|
||||
label: t('knowledgeDetails.cancel'),
|
||||
icon: <CircleX />,
|
||||
onClick: () => {},
|
||||
},
|
||||
{
|
||||
id: 'delete',
|
||||
label: t('common.delete'),
|
||||
icon: <Trash2 />,
|
||||
onClick: () => {},
|
||||
},
|
||||
];
|
||||
|
||||
return { list };
|
||||
}
|
||||
@ -5,6 +5,7 @@ import { useFetchNextKnowledgeListByPage } from '@/hooks/use-knowledge-request';
|
||||
import { pick } from 'lodash';
|
||||
import { Plus } from 'lucide-react';
|
||||
import { PropsWithChildren, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { DatasetCard } from './dataset-card';
|
||||
import { DatasetCreatingDialog } from './dataset-creating-dialog';
|
||||
import { DatasetsFilterPopover } from './datasets-filter-popover';
|
||||
@ -13,6 +14,7 @@ import { useSaveKnowledge } from './hooks';
|
||||
import { useRenameDataset } from './use-rename-dataset';
|
||||
|
||||
export default function Datasets() {
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
visible,
|
||||
hideModal,
|
||||
@ -63,8 +65,8 @@ export default function Datasets() {
|
||||
>
|
||||
<Button variant={'tertiary'} size={'sm'} onClick={showModal}>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
{t('knowledgeList.createKnowledgeBase')}
|
||||
</Button>
|
||||
Create dataset
|
||||
</ListFilterBar>
|
||||
<div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-6 2xl:grid-cols-8">
|
||||
{kbs.map((dataset) => {
|
||||
|
||||
@ -17,12 +17,12 @@ import {
|
||||
UseHandleConnectToKnowledgeReturnType,
|
||||
UseRenameCurrentFileReturnType,
|
||||
} from './hooks';
|
||||
import { UseMoveDocumentReturnType } from './use-move-file';
|
||||
import { UseMoveDocumentShowType } from './use-move-file';
|
||||
|
||||
type IProps = Pick<CellContext<IFile, unknown>, 'row'> &
|
||||
Pick<UseHandleConnectToKnowledgeReturnType, 'showConnectToKnowledgeModal'> &
|
||||
Pick<UseRenameCurrentFileReturnType, 'showFileRenameModal'> &
|
||||
Pick<UseMoveDocumentReturnType, 'showMoveFileModal'>;
|
||||
UseMoveDocumentShowType;
|
||||
|
||||
export function ActionCell({
|
||||
row,
|
||||
|
||||
@ -3,6 +3,8 @@
|
||||
import {
|
||||
ColumnDef,
|
||||
ColumnFiltersState,
|
||||
OnChangeFn,
|
||||
RowSelectionState,
|
||||
SortingState,
|
||||
VisibilityState,
|
||||
flexRender,
|
||||
@ -33,7 +35,7 @@ import {
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from '@/components/ui/tooltip';
|
||||
import { useFetchFileList } from '@/hooks/file-manager-hooks';
|
||||
import { useFetchFileList } from '@/hooks/use-file-request';
|
||||
import { IFile } from '@/interfaces/database/file-manager';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { formatFileSize } from '@/utils/common-util';
|
||||
@ -44,18 +46,33 @@ import { useTranslation } from 'react-i18next';
|
||||
import { ActionCell } from './action-cell';
|
||||
import { useHandleConnectToKnowledge, useRenameCurrentFile } from './hooks';
|
||||
import { LinkToDatasetDialog } from './link-to-dataset-dialog';
|
||||
import { MoveDialog } from './move-dialog';
|
||||
import { useHandleMoveFile } from './use-move-file';
|
||||
import { UseMoveDocumentShowType } from './use-move-file';
|
||||
import { useNavigateToOtherFolder } from './use-navigate-to-folder';
|
||||
|
||||
export function FilesTable() {
|
||||
type FilesTableProps = Pick<
|
||||
ReturnType<typeof useFetchFileList>,
|
||||
'files' | 'loading' | 'pagination' | 'setPagination' | 'total'
|
||||
> & {
|
||||
rowSelection: RowSelectionState;
|
||||
setRowSelection: OnChangeFn<RowSelectionState>;
|
||||
} & UseMoveDocumentShowType;
|
||||
|
||||
export function FilesTable({
|
||||
files,
|
||||
total,
|
||||
pagination,
|
||||
setPagination,
|
||||
loading,
|
||||
rowSelection,
|
||||
setRowSelection,
|
||||
showMoveFileModal,
|
||||
}: FilesTableProps) {
|
||||
const [sorting, setSorting] = React.useState<SortingState>([]);
|
||||
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
||||
[],
|
||||
);
|
||||
const [columnVisibility, setColumnVisibility] =
|
||||
React.useState<VisibilityState>({});
|
||||
const [rowSelection, setRowSelection] = React.useState({});
|
||||
const { t } = useTranslation('translation', {
|
||||
keyPrefix: 'fileManager',
|
||||
});
|
||||
@ -77,16 +94,6 @@ export function FilesTable() {
|
||||
fileRenameLoading,
|
||||
} = useRenameCurrentFile();
|
||||
|
||||
const {
|
||||
showMoveFileModal,
|
||||
moveFileVisible,
|
||||
onMoveFileOk,
|
||||
hideMoveFileModal,
|
||||
moveFileLoading,
|
||||
} = useHandleMoveFile();
|
||||
|
||||
const { pagination, data, loading, setPagination } = useFetchFileList();
|
||||
|
||||
const columns: ColumnDef<IFile>[] = [
|
||||
{
|
||||
id: 'select',
|
||||
@ -244,7 +251,7 @@ export function FilesTable() {
|
||||
}, [pagination]);
|
||||
|
||||
const table = useReactTable({
|
||||
data: data?.files || [],
|
||||
data: files || [],
|
||||
columns,
|
||||
onSortingChange: setSorting,
|
||||
onColumnFiltersChange: setColumnFilters,
|
||||
@ -277,7 +284,7 @@ export function FilesTable() {
|
||||
rowSelection,
|
||||
pagination: currentPagination,
|
||||
},
|
||||
rowCount: data?.total ?? 0,
|
||||
rowCount: total ?? 0,
|
||||
debugTable: true,
|
||||
});
|
||||
|
||||
@ -333,8 +340,8 @@ export function FilesTable() {
|
||||
</div>
|
||||
<div className="flex items-center justify-end space-x-2 py-4">
|
||||
<div className="flex-1 text-sm text-muted-foreground">
|
||||
{table.getFilteredSelectedRowModel().rows.length} of {data?.total}{' '}
|
||||
row(s) selected.
|
||||
{table.getFilteredSelectedRowModel().rows.length} of {total} row(s)
|
||||
selected.
|
||||
</div>
|
||||
<div className="space-x-2">
|
||||
<Button
|
||||
@ -371,13 +378,6 @@ export function FilesTable() {
|
||||
loading={fileRenameLoading}
|
||||
></RenameDialog>
|
||||
)}
|
||||
{moveFileVisible && (
|
||||
<MoveDialog
|
||||
hideModal={hideMoveFileModal}
|
||||
onOk={onMoveFileOk}
|
||||
loading={moveFileLoading}
|
||||
></MoveDialog>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { useSetModalState, useShowDeleteConfirm } from '@/hooks/common-hooks';
|
||||
import { useSetModalState } from '@/hooks/common-hooks';
|
||||
import {
|
||||
useConnectToKnowledge,
|
||||
useDeleteFile,
|
||||
useRenameFile,
|
||||
} from '@/hooks/file-manager-hooks';
|
||||
import { IFile } from '@/interfaces/database/file-manager';
|
||||
@ -77,29 +76,6 @@ export type UseRenameCurrentFileReturnType = ReturnType<
|
||||
typeof useRenameCurrentFile
|
||||
>;
|
||||
|
||||
export const useHandleDeleteFile = (
|
||||
fileIds: string[],
|
||||
setSelectedRowKeys: (keys: string[]) => void,
|
||||
) => {
|
||||
const { deleteFile: removeDocument } = useDeleteFile();
|
||||
const showDeleteConfirm = useShowDeleteConfirm();
|
||||
const parentId = useGetFolderId();
|
||||
|
||||
const handleRemoveFile = () => {
|
||||
showDeleteConfirm({
|
||||
onOk: async () => {
|
||||
const code = await removeDocument({ fileIds, parentId });
|
||||
if (code === 0) {
|
||||
setSelectedRowKeys([]);
|
||||
}
|
||||
return;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return { handleRemoveFile };
|
||||
};
|
||||
|
||||
export const useHandleConnectToKnowledge = () => {
|
||||
const {
|
||||
visible: connectToKnowledgeVisible,
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { BulkOperateBar } from '@/components/bulk-operate-bar';
|
||||
import { FileUploadDialog } from '@/components/file-upload-dialog';
|
||||
import ListFilterBar from '@/components/list-filter-bar';
|
||||
import { Button } from '@/components/ui/button';
|
||||
@ -8,12 +9,19 @@ import {
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { useFetchFileList } from '@/hooks/use-file-request';
|
||||
import { RowSelectionState } from '@tanstack/react-table';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { Upload } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { CreateFolderDialog } from './create-folder-dialog';
|
||||
import { FileBreadcrumb } from './file-breadcrumb';
|
||||
import { FilesTable } from './files-table';
|
||||
import { MoveDialog } from './move-dialog';
|
||||
import { useBulkOperateFile } from './use-bulk-operate-file';
|
||||
import { useHandleCreateFolder } from './use-create-folder';
|
||||
import { useHandleMoveFile } from './use-move-file';
|
||||
import { useHandleUploadFile } from './use-upload-file';
|
||||
|
||||
export default function Files() {
|
||||
@ -34,6 +42,33 @@ export default function Files() {
|
||||
onFolderCreateOk,
|
||||
} = useHandleCreateFolder();
|
||||
|
||||
const {
|
||||
pagination,
|
||||
files,
|
||||
total,
|
||||
loading,
|
||||
setPagination,
|
||||
searchString,
|
||||
handleInputChange,
|
||||
} = useFetchFileList();
|
||||
|
||||
const {
|
||||
showMoveFileModal,
|
||||
moveFileVisible,
|
||||
onMoveFileOk,
|
||||
hideMoveFileModal,
|
||||
moveFileLoading,
|
||||
} = useHandleMoveFile();
|
||||
|
||||
const [rowSelection, setRowSelection] = useState<RowSelectionState>({});
|
||||
|
||||
const { list } = useBulkOperateFile({
|
||||
files,
|
||||
rowSelection,
|
||||
showMoveFileModal,
|
||||
setRowSelection,
|
||||
});
|
||||
|
||||
const leftPanel = (
|
||||
<div>
|
||||
<FileBreadcrumb></FileBreadcrumb>
|
||||
@ -42,7 +77,12 @@ export default function Files() {
|
||||
|
||||
return (
|
||||
<section className="p-8">
|
||||
<ListFilterBar leftPanel={leftPanel}>
|
||||
<ListFilterBar
|
||||
leftPanel={leftPanel}
|
||||
searchString={searchString}
|
||||
onSearchChange={handleInputChange}
|
||||
showFilter={false}
|
||||
>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant={'tertiary'} size={'sm'}>
|
||||
@ -61,7 +101,17 @@ export default function Files() {
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</ListFilterBar>
|
||||
<FilesTable></FilesTable>
|
||||
{!isEmpty(rowSelection) && <BulkOperateBar list={list}></BulkOperateBar>}
|
||||
<FilesTable
|
||||
files={files}
|
||||
total={total}
|
||||
pagination={pagination}
|
||||
setPagination={setPagination}
|
||||
loading={loading}
|
||||
rowSelection={rowSelection}
|
||||
setRowSelection={setRowSelection}
|
||||
showMoveFileModal={showMoveFileModal}
|
||||
></FilesTable>
|
||||
{fileUploadVisible && (
|
||||
<FileUploadDialog
|
||||
hideModal={hideFileUploadModal}
|
||||
@ -77,6 +127,14 @@ export default function Files() {
|
||||
onOk={onFolderCreateOk}
|
||||
></CreateFolderDialog>
|
||||
)}
|
||||
|
||||
{moveFileVisible && (
|
||||
<MoveDialog
|
||||
hideModal={hideMoveFileModal}
|
||||
onOk={onMoveFileOk}
|
||||
loading={moveFileLoading}
|
||||
></MoveDialog>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
53
web/src/pages/files/use-bulk-operate-file.tsx
Normal file
53
web/src/pages/files/use-bulk-operate-file.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import { IFile } from '@/interfaces/database/file-manager';
|
||||
import { OnChangeFn, RowSelectionState } from '@tanstack/react-table';
|
||||
import { FolderInput, Trash2 } from 'lucide-react';
|
||||
import { useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useHandleDeleteFile } from './use-delete-file';
|
||||
import { UseMoveDocumentShowType } from './use-move-file';
|
||||
|
||||
export function useBulkOperateFile({
|
||||
files,
|
||||
rowSelection,
|
||||
showMoveFileModal,
|
||||
setRowSelection,
|
||||
}: {
|
||||
files: IFile[];
|
||||
rowSelection: RowSelectionState;
|
||||
setRowSelection: OnChangeFn<RowSelectionState>;
|
||||
} & UseMoveDocumentShowType) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const selectedIds = useMemo(() => {
|
||||
const indexes = Object.keys(rowSelection);
|
||||
return files
|
||||
.filter((x, idx) => indexes.some((y) => Number(y) === idx))
|
||||
.map((x) => x.id);
|
||||
}, [files, rowSelection]);
|
||||
|
||||
const { handleRemoveFile } = useHandleDeleteFile();
|
||||
|
||||
const list = [
|
||||
{
|
||||
id: 'move',
|
||||
label: t('common.move'),
|
||||
icon: <FolderInput />,
|
||||
onClick: () => {
|
||||
showMoveFileModal(selectedIds);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'delete',
|
||||
label: t('common.delete'),
|
||||
icon: <Trash2 />,
|
||||
onClick: async () => {
|
||||
const code = await handleRemoveFile(selectedIds);
|
||||
if (code === 0) {
|
||||
setRowSelection({});
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return { list };
|
||||
}
|
||||
19
web/src/pages/files/use-delete-file.ts
Normal file
19
web/src/pages/files/use-delete-file.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { useDeleteFile } from '@/hooks/use-file-request';
|
||||
import { useCallback } from 'react';
|
||||
import { useGetFolderId } from './hooks';
|
||||
|
||||
export const useHandleDeleteFile = () => {
|
||||
const { deleteFile: removeDocument } = useDeleteFile();
|
||||
const parentId = useGetFolderId();
|
||||
|
||||
const handleRemoveFile = useCallback(
|
||||
async (fileIds: string[]) => {
|
||||
const code = await removeDocument({ fileIds, parentId });
|
||||
|
||||
return code;
|
||||
},
|
||||
[parentId, removeDocument],
|
||||
);
|
||||
|
||||
return { handleRemoveFile };
|
||||
};
|
||||
@ -2,49 +2,52 @@ import { useSetModalState } from '@/hooks/common-hooks';
|
||||
import { useMoveFile } from '@/hooks/use-file-request';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
export const useHandleMoveFile = () =>
|
||||
// setSelectedRowKeys: (keys: string[]) => void,
|
||||
{
|
||||
const {
|
||||
visible: moveFileVisible,
|
||||
hideModal: hideMoveFileModal,
|
||||
showModal: showMoveFileModal,
|
||||
} = useSetModalState();
|
||||
const { moveFile, loading } = useMoveFile();
|
||||
const [sourceFileIds, setSourceFileIds] = useState<string[]>([]);
|
||||
export const useHandleMoveFile = () => {
|
||||
const {
|
||||
visible: moveFileVisible,
|
||||
hideModal: hideMoveFileModal,
|
||||
showModal: showMoveFileModal,
|
||||
} = useSetModalState();
|
||||
const { moveFile, loading } = useMoveFile();
|
||||
const [sourceFileIds, setSourceFileIds] = useState<string[]>([]);
|
||||
|
||||
const onMoveFileOk = useCallback(
|
||||
async (targetFolderId: string) => {
|
||||
const ret = await moveFile({
|
||||
src_file_ids: sourceFileIds,
|
||||
dest_file_id: targetFolderId,
|
||||
});
|
||||
const onMoveFileOk = useCallback(
|
||||
async (targetFolderId: string) => {
|
||||
const ret = await moveFile({
|
||||
src_file_ids: sourceFileIds,
|
||||
dest_file_id: targetFolderId,
|
||||
});
|
||||
|
||||
if (ret === 0) {
|
||||
// setSelectedRowKeys([]);
|
||||
hideMoveFileModal();
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
[moveFile, hideMoveFileModal, sourceFileIds],
|
||||
);
|
||||
if (ret === 0) {
|
||||
// setSelectedRowKeys([]);
|
||||
hideMoveFileModal();
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
[moveFile, hideMoveFileModal, sourceFileIds],
|
||||
);
|
||||
|
||||
const handleShowMoveFileModal = useCallback(
|
||||
(ids: string[]) => {
|
||||
setSourceFileIds(ids);
|
||||
showMoveFileModal();
|
||||
},
|
||||
[showMoveFileModal],
|
||||
);
|
||||
const handleShowMoveFileModal = useCallback(
|
||||
(ids: string[]) => {
|
||||
setSourceFileIds(ids);
|
||||
showMoveFileModal();
|
||||
},
|
||||
[showMoveFileModal],
|
||||
);
|
||||
|
||||
return {
|
||||
initialValue: '',
|
||||
moveFileLoading: loading,
|
||||
onMoveFileOk,
|
||||
moveFileVisible,
|
||||
hideMoveFileModal,
|
||||
showMoveFileModal: handleShowMoveFileModal,
|
||||
};
|
||||
return {
|
||||
initialValue: '',
|
||||
moveFileLoading: loading,
|
||||
onMoveFileOk,
|
||||
moveFileVisible,
|
||||
hideMoveFileModal,
|
||||
showMoveFileModal: handleShowMoveFileModal,
|
||||
};
|
||||
};
|
||||
|
||||
export type UseMoveDocumentReturnType = ReturnType<typeof useHandleMoveFile>;
|
||||
|
||||
export type UseMoveDocumentShowType = Pick<
|
||||
ReturnType<typeof useHandleMoveFile>,
|
||||
'showMoveFileModal'
|
||||
>;
|
||||
|
||||
Reference in New Issue
Block a user