### What problem does this PR solve? Feat: Deleting files in batches. #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.19.0
| @@ -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} | |||
| @@ -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> | |||
| ); | |||
| } | |||
| @@ -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 }; | |||
| } | |||
| @@ -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' | |||
| >; | |||