diff --git a/web/src/hooks/file-manager-hooks.ts b/web/src/hooks/file-manager-hooks.ts index 4f643b565..275c40dd5 100644 --- a/web/src/hooks/file-manager-hooks.ts +++ b/web/src/hooks/file-manager-hooks.ts @@ -1,13 +1,12 @@ import { ResponseType } from '@/interfaces/database/base'; -import { - IConnectRequestBody, - IFileListRequestBody, -} from '@/interfaces/request/file-manager'; +import { IFolder } from '@/interfaces/database/file-manager'; +import { IConnectRequestBody } from '@/interfaces/request/file-manager'; import fileManagerService from '@/services/file-manager-service'; -import { useMutation, useQuery } from '@tanstack/react-query'; -import { PaginationProps, UploadFile } from 'antd'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { PaginationProps, UploadFile, message } from 'antd'; import React, { useCallback } from 'react'; -import { useDispatch, useSearchParams, useSelector } from 'umi'; +import { useTranslation } from 'react-i18next'; +import { useSearchParams } from 'umi'; import { useGetNextPagination, useHandleSearchChange } from './logic-hooks'; import { useSetPaginationParams } from './route-hook'; @@ -18,41 +17,22 @@ export const useGetFolderId = () => { return id ?? ''; }; -export const useFetchFileList = () => { - const dispatch = useDispatch(); - - const fetchFileList = useCallback( - (payload: IFileListRequestBody) => { - return dispatch({ - type: 'fileManager/listFile', - payload, - }); - }, - [dispatch], - ); - - return fetchFileList; -}; - export interface IListResult { searchString: string; handleInputChange: React.ChangeEventHandler; pagination: PaginationProps; setPagination: (pagination: { page: number; pageSize: number }) => void; + loading: boolean; } -export const useFetchNextFileList = (): ResponseType & IListResult => { +export const useFetchFileList = (): ResponseType & IListResult => { const { searchString, handleInputChange } = useHandleSearchChange(); const { pagination, setPagination } = useGetNextPagination(); const id = useGetFolderId(); - const { data } = useQuery({ + const { data, isFetching: loading } = useQuery({ queryKey: [ 'fetchFileList', - // pagination.current, - // id, - // pagination.pageSize, - // searchString, { id, searchString, @@ -87,27 +67,14 @@ export const useFetchNextFileList = (): ResponseType & IListResult => { handleInputChange: onInputChange, pagination: { ...pagination, total: data?.data?.total }, setPagination, + loading, }; }; -export const useRemoveFile = () => { - const dispatch = useDispatch(); - - const removeFile = useCallback( - (fileIds: string[], parentId: string) => { - return dispatch({ - type: 'fileManager/removeFile', - payload: { fileIds, parentId }, - }); - }, - [dispatch], - ); - - return removeFile; -}; - export const useDeleteFile = () => { const { setPaginationParams } = useSetPaginationParams(); + const queryClient = useQueryClient(); + const { data, isPending: loading, @@ -117,9 +84,10 @@ export const useDeleteFile = () => { mutationFn: async (params: { fileIds: string[]; parentId: string }) => { const { data } = await fileManagerService.removeFile(params); if (data.retcode === 0) { - setPaginationParams(1); + setPaginationParams(1); // TODO: There should be a better way to paginate the request list + queryClient.invalidateQueries({ queryKey: ['fetchFileList'] }); } - return data?.data ?? {}; + return data.retcode; }, }); @@ -127,106 +95,129 @@ export const useDeleteFile = () => { }; export const useRenameFile = () => { - const dispatch = useDispatch(); - - const renameFile = useCallback( - (fileId: string, name: string, parentId: string) => { - return dispatch({ - type: 'fileManager/renameFile', - payload: { fileId, name, parentId }, - }); + const queryClient = useQueryClient(); + const { t } = useTranslation(); + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['renameFile'], + mutationFn: async (params: { fileId: string; name: string }) => { + const { data } = await fileManagerService.renameFile(params); + if (data.retcode === 0) { + message.success(t('message.renamed')); + queryClient.invalidateQueries({ queryKey: ['fetchFileList'] }); + } + return data.retcode; }, - [dispatch], - ); + }); - return renameFile; + return { data, loading, renameFile: mutateAsync }; }; -export const useFetchParentFolderList = () => { - const dispatch = useDispatch(); - - const fetchParentFolderList = useCallback( - (fileId: string) => { - return dispatch({ - type: 'fileManager/getAllParentFolder', - payload: { fileId }, +export const useFetchParentFolderList = (): IFolder[] => { + const id = useGetFolderId(); + const { data } = useQuery({ + queryKey: ['fetchParentFolderList', id], + initialData: [], + enabled: !!id, + queryFn: async () => { + const { data } = await fileManagerService.getAllParentFolder({ + fileId: id, }); + + return data?.data?.parent_folders?.toReversed() ?? []; }, - [dispatch], - ); + }); - return fetchParentFolderList; + return data; }; export const useCreateFolder = () => { - const dispatch = useDispatch(); + const { setPaginationParams } = useSetPaginationParams(); + const queryClient = useQueryClient(); + const { t } = useTranslation(); - const createFolder = useCallback( - (parentId: string, name: string) => { - return dispatch({ - type: 'fileManager/createFolder', - payload: { parentId, name, type: 'folder' }, + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['createFolder'], + mutationFn: async (params: { parentId: string; name: string }) => { + const { data } = await fileManagerService.createFolder({ + ...params, + type: 'folder', }); + if (data.retcode === 0) { + message.success(t('message.created')); + setPaginationParams(1); + queryClient.invalidateQueries({ queryKey: ['fetchFileList'] }); + } + return data.retcode; }, - [dispatch], - ); - - return createFolder; -}; - -export const useSelectFileList = () => { - const fileList = useSelector((state) => state.fileManager.fileList); + }); - return fileList; -}; - -export const useSelectParentFolderList = () => { - const parentFolderList = useSelector( - (state) => state.fileManager.parentFolderList, - ); - return parentFolderList.toReversed(); + return { data, loading, createFolder: mutateAsync }; }; export const useUploadFile = () => { - const dispatch = useDispatch(); - - const uploadFile = useCallback( - (fileList: UploadFile[], parentId: string) => { - try { - return dispatch({ - type: 'fileManager/uploadFile', - payload: { - file: fileList, - parentId, - path: fileList.map((file) => (file as any).webkitRelativePath), - }, - }); - } catch (errorInfo) { - console.log('Failed:', errorInfo); + const { setPaginationParams } = useSetPaginationParams(); + const { t } = useTranslation(); + const queryClient = useQueryClient(); + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['uploadFile'], + mutationFn: async (params: { + fileList: UploadFile[]; + parentId: string; + }) => { + const fileList = params.fileList; + const pathList = params.fileList.map( + (file) => (file as any).webkitRelativePath, + ); + const formData = new FormData(); + formData.append('parent_id', params.parentId); + fileList.forEach((file: any, index: number) => { + formData.append('file', file); + formData.append('path', pathList[index]); + }); + const { data } = await fileManagerService.uploadFile(formData); + if (data.retcode === 0) { + message.success(t('message.uploaded')); + setPaginationParams(1); + queryClient.invalidateQueries({ queryKey: ['fetchFileList'] }); } + return data.retcode; }, - [dispatch], - ); + }); - return uploadFile; + return { data, loading, uploadFile: mutateAsync }; }; export const useConnectToKnowledge = () => { - const dispatch = useDispatch(); - - const uploadFile = useCallback( - (payload: IConnectRequestBody) => { - try { - return dispatch({ - type: 'fileManager/connectFileToKnowledge', - payload, - }); - } catch (errorInfo) { - console.log('Failed:', errorInfo); + const queryClient = useQueryClient(); + const { t } = useTranslation(); + + const { + data, + isPending: loading, + mutateAsync, + } = useMutation({ + mutationKey: ['connectFileToKnowledge'], + mutationFn: async (params: IConnectRequestBody) => { + const { data } = await fileManagerService.connectFileToKnowledge(params); + if (data.retcode === 0) { + message.success(t('message.operated')); + queryClient.invalidateQueries({ queryKey: ['fetchFileList'] }); } + return data.retcode; }, - [dispatch], - ); + }); - return uploadFile; + return { data, loading, connectFileToKnowledge: mutateAsync }; }; diff --git a/web/src/interfaces/request/file-manager.ts b/web/src/interfaces/request/file-manager.ts index 0a0928bf8..b355bf3a9 100644 --- a/web/src/interfaces/request/file-manager.ts +++ b/web/src/interfaces/request/file-manager.ts @@ -8,7 +8,7 @@ interface BaseRequestBody { parentId: string; } -export interface IConnectRequestBody extends BaseRequestBody { +export interface IConnectRequestBody { fileIds: string[]; kbIds: string[]; } diff --git a/web/src/pages/file-manager/file-toolbar.tsx b/web/src/pages/file-manager/file-toolbar.tsx index 74db2ea07..69b69ae63 100644 --- a/web/src/pages/file-manager/file-toolbar.tsx +++ b/web/src/pages/file-manager/file-toolbar.tsx @@ -26,7 +26,7 @@ import { import { IListResult, - useSelectParentFolderList, + useFetchParentFolderList, } from '@/hooks/file-manager-hooks'; import styles from './index.less'; @@ -49,7 +49,7 @@ const FileToolbar = ({ const { t } = useTranslate('knowledgeDetails'); const breadcrumbItems = useSelectBreadcrumbItems(); const { handleBreadcrumbClick } = useHandleBreadcrumbClick(); - const parentFolderList = useSelectParentFolderList(); + const parentFolderList = useFetchParentFolderList(); const isKnowledgeBase = parentFolderList.at(-1)?.source_type === 'knowledgebase'; diff --git a/web/src/pages/file-manager/hooks.ts b/web/src/pages/file-manager/hooks.ts index a9ee4c011..3983ff873 100644 --- a/web/src/pages/file-manager/hooks.ts +++ b/web/src/pages/file-manager/hooks.ts @@ -3,21 +3,15 @@ import { useConnectToKnowledge, useCreateFolder, useDeleteFile, - useFetchFileList, useFetchParentFolderList, useRenameFile, - useSelectFileList, - useSelectParentFolderList, useUploadFile, } from '@/hooks/file-manager-hooks'; -import { useGetPagination, useSetPagination } from '@/hooks/logic-hooks'; -import { useOneNamespaceEffectsLoading } from '@/hooks/store-hooks'; import { IFile } from '@/interfaces/database/file-manager'; -import { PaginationProps } from 'antd'; import { TableRowSelection } from 'antd/es/table/interface'; import { UploadFile } from 'antd/lib'; -import { useCallback, useEffect, useMemo, useState } from 'react'; -import { useDispatch, useNavigate, useSearchParams, useSelector } from 'umi'; +import { useCallback, useMemo, useState } from 'react'; +import { useNavigate, useSearchParams } from 'umi'; export const useGetFolderId = () => { const [searchParams] = useSearchParams(); @@ -26,71 +20,6 @@ export const useGetFolderId = () => { return id ?? ''; }; -export const useFetchDocumentListOnMount = () => { - const fetchDocumentList = useFetchFileList(); - const fileList = useSelectFileList(); - const id = useGetFolderId(); - const { searchString, pagination } = useSelector( - (state) => state.fileManager, - ); - const { pageSize, current } = pagination; - - const dispatch = useDispatch(); - - useEffect(() => { - fetchDocumentList({ - parent_id: id, - keywords: searchString, - page_size: pageSize, - page: current, - }); - }, [dispatch, fetchDocumentList, id, current, pageSize, searchString]); - - return { fetchDocumentList, fileList }; -}; - -export const useGetFilesPagination = () => { - const { pagination } = useSelector((state) => state.fileManager); - - const setPagination = useSetPagination('fileManager'); - - const onPageChange: PaginationProps['onChange'] = useCallback( - (pageNumber: number, pageSize: number) => { - setPagination(pageNumber, pageSize); - }, - [setPagination], - ); - - const { pagination: paginationInfo } = useGetPagination( - pagination.total, - pagination.current, - pagination.pageSize, - onPageChange, - ); - - return { - pagination: paginationInfo, - setPagination, - }; -}; - -export const useHandleSearchChange = () => { - const dispatch = useDispatch(); - const { searchString } = useSelector((state) => state.fileManager); - const setPagination = useSetPagination('fileManager'); - - const handleInputChange = useCallback( - (e: React.ChangeEvent) => { - const value = e.target.value; - dispatch({ type: 'fileManager/setSearchString', payload: value }); - setPagination(); - }, - [setPagination, dispatch], - ); - - return { handleInputChange, searchString }; -}; - export const useGetRowSelection = () => { const [selectedRowKeys, setSelectedRowKeys] = useState([]); @@ -126,11 +55,14 @@ export const useRenameCurrentFile = () => { hideModal: hideFileRenameModal, showModal: showFileRenameModal, } = useSetModalState(); - const renameFile = useRenameFile(); + const { renameFile, loading } = useRenameFile(); const onFileRenameOk = useCallback( async (name: string) => { - const ret = await renameFile(file.id, name, file.parent_id); + const ret = await renameFile({ + fileId: file.id, + name, + }); if (ret === 0) { hideFileRenameModal(); @@ -139,8 +71,6 @@ export const useRenameCurrentFile = () => { [renameFile, file, hideFileRenameModal], ); - const loading = useOneNamespaceEffectsLoading('fileManager', ['renameFile']); - const handleShowFileRenameModal = useCallback( async (record: IFile) => { setFile(record); @@ -160,15 +90,7 @@ export const useRenameCurrentFile = () => { }; export const useSelectBreadcrumbItems = () => { - const parentFolderList = useSelectParentFolderList(); - const id = useGetFolderId(); - const fetchParentFolderList = useFetchParentFolderList(); - - useEffect(() => { - if (id) { - fetchParentFolderList(id); - } - }, [id, fetchParentFolderList]); + const parentFolderList = useFetchParentFolderList(); return parentFolderList.length === 1 ? [] @@ -184,12 +106,12 @@ export const useHandleCreateFolder = () => { hideModal: hideFolderCreateModal, showModal: showFolderCreateModal, } = useSetModalState(); - const createFolder = useCreateFolder(); + const { createFolder, loading } = useCreateFolder(); const id = useGetFolderId(); const onFolderCreateOk = useCallback( async (name: string) => { - const ret = await createFolder(id, name); + const ret = await createFolder({ parentId: id, name }); if (ret === 0) { hideFolderCreateModal(); @@ -198,10 +120,6 @@ export const useHandleCreateFolder = () => { [createFolder, hideFolderCreateModal, id], ); - const loading = useOneNamespaceEffectsLoading('fileManager', [ - 'createFolder', - ]); - return { folderCreateLoading: loading, onFolderCreateOk, @@ -234,24 +152,19 @@ export const useHandleDeleteFile = ( return { handleRemoveFile }; }; -export const useSelectFileListLoading = () => { - return useOneNamespaceEffectsLoading('fileManager', ['listFile']); -}; - export const useHandleUploadFile = () => { const { visible: fileUploadVisible, hideModal: hideFileUploadModal, showModal: showFileUploadModal, } = useSetModalState(); - const uploadFile = useUploadFile(); + const { uploadFile, loading } = useUploadFile(); const id = useGetFolderId(); const onFileUploadOk = useCallback( async (fileList: UploadFile[]): Promise => { if (fileList.length > 0) { - const ret: number = await uploadFile(fileList, id); - console.info(ret); + const ret: number = await uploadFile({ fileList, parentId: id }); if (ret === 0) { hideFileUploadModal(); } @@ -261,8 +174,6 @@ export const useHandleUploadFile = () => { [uploadFile, hideFileUploadModal, id], ); - const loading = useOneNamespaceEffectsLoading('fileManager', ['uploadFile']); - return { fileUploadLoading: loading, onFileUploadOk, @@ -278,8 +189,8 @@ export const useHandleConnectToKnowledge = () => { hideModal: hideConnectToKnowledgeModal, showModal: showConnectToKnowledgeModal, } = useSetModalState(); - const connectToKnowledge = useConnectToKnowledge(); - const id = useGetFolderId(); + const { connectFileToKnowledge: connectToKnowledge, loading } = + useConnectToKnowledge(); const [record, setRecord] = useState({} as IFile); const initialValue = useMemo(() => { @@ -291,7 +202,6 @@ export const useHandleConnectToKnowledge = () => { const onConnectToKnowledgeOk = useCallback( async (knowledgeIds: string[]) => { const ret = await connectToKnowledge({ - parentId: id, fileIds: [record.id], kbIds: knowledgeIds, }); @@ -301,13 +211,9 @@ export const useHandleConnectToKnowledge = () => { } return ret; }, - [connectToKnowledge, hideConnectToKnowledgeModal, id, record.id], + [connectToKnowledge, hideConnectToKnowledgeModal, record.id], ); - const loading = useOneNamespaceEffectsLoading('fileManager', [ - 'connectFileToKnowledge', - ]); - const handleShowConnectToKnowledgeModal = useCallback( (record: IFile) => { setRecord(record); @@ -328,16 +234,14 @@ export const useHandleConnectToKnowledge = () => { export const useHandleBreadcrumbClick = () => { const navigate = useNavigate(); - const setPagination = useSetPagination('fileManager'); const handleBreadcrumbClick = useCallback( (path?: string) => { if (path) { - setPagination(); navigate(path); } }, - [setPagination, navigate], + [navigate], ); return { handleBreadcrumbClick }; diff --git a/web/src/pages/file-manager/index.tsx b/web/src/pages/file-manager/index.tsx index 398a39dd2..db208933b 100644 --- a/web/src/pages/file-manager/index.tsx +++ b/web/src/pages/file-manager/index.tsx @@ -1,4 +1,4 @@ -import { useFetchNextFileList } from '@/hooks/file-manager-hooks'; +import { useFetchFileList } from '@/hooks/file-manager-hooks'; import { IFile } from '@/interfaces/database/file-manager'; import { formatDate } from '@/utils/date'; import { Button, Flex, Space, Table, Tag, Typography } from 'antd'; @@ -12,7 +12,6 @@ import { useHandleUploadFile, useNavigateToOtherFolder, useRenameCurrentFile, - useSelectFileListLoading, } from './hooks'; import FileUploadModal from '@/components/file-upload-modal'; @@ -31,7 +30,6 @@ const FileManager = () => { const { t } = useTranslate('fileManager'); // const fileList = useSelectFileList(); const { rowSelection, setSelectedRowKeys } = useGetRowSelection(); - const loading = useSelectFileListLoading(); const navigateToOtherFolder = useNavigateToOtherFolder(); const { fileRenameVisible, @@ -64,8 +62,8 @@ const FileManager = () => { connectToKnowledgeLoading, } = useHandleConnectToKnowledge(); // const { pagination } = useGetFilesPagination(); - const { pagination, data, searchString, handleInputChange } = - useFetchNextFileList(); + const { pagination, data, searchString, handleInputChange, loading } = + useFetchFileList(); const columns: ColumnsType = [ { title: t('name'), diff --git a/web/src/pages/file-manager/model.ts b/web/src/pages/file-manager/model.ts deleted file mode 100644 index fc8bc153b..000000000 --- a/web/src/pages/file-manager/model.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { paginationModel } from '@/base'; -import { BaseState } from '@/interfaces/common'; -import { IFile, IFolder } from '@/interfaces/database/file-manager'; -import i18n from '@/locales/config'; -import fileManagerService, { - getDocumentFile, -} from '@/services/file-manager-service'; -import { message } from 'antd'; -import omit from 'lodash/omit'; -import { DvaModel } from 'umi'; - -export interface FileManagerModelState extends BaseState { - fileList: IFile[]; - parentFolderList: IFolder[]; -} - -const model: DvaModel = { - namespace: 'fileManager', - state: { - fileList: [], - parentFolderList: [], - ...(paginationModel.state as BaseState), - }, - reducers: { - setFileList(state, { payload }) { - return { ...state, fileList: payload }; - }, - setParentFolderList(state, { payload }) { - return { ...state, parentFolderList: payload }; - }, - ...paginationModel.reducers, - }, - effects: { - *removeFile({ payload = {} }, { call, put }) { - const { data } = yield call(fileManagerService.removeFile, { - fileIds: payload.fileIds, - }); - const { retcode } = data; - if (retcode === 0) { - message.success(i18n.t('message.deleted')); - yield put({ - type: 'listFile', - payload: { parentId: payload.parentId }, - }); - } - return retcode; - }, - *listFile({ payload = {} }, { call, put, select }) { - const { searchString, pagination } = yield select( - (state: any) => state.fileManager, - ); - const { current, pageSize } = pagination; - const { data } = yield call(fileManagerService.listFile, { - ...payload, - keywords: searchString.trim(), - page: current, - pageSize, - }); - const { retcode, data: res } = data; - if (retcode === 0 && Array.isArray(res.files)) { - yield put({ - type: 'setFileList', - payload: res.files, - }); - yield put({ - type: 'setPagination', - payload: { total: res.total }, - }); - } - }, - *renameFile({ payload = {} }, { call, put }) { - const { data } = yield call( - fileManagerService.renameFile, - omit(payload, ['parentId']), - ); - if (data.retcode === 0) { - message.success(i18n.t('message.renamed')); - yield put({ - type: 'listFile', - payload: { parentId: payload.parentId }, - }); - } - return data.retcode; - }, - *uploadFile({ payload = {} }, { call, put }) { - const fileList = payload.file; - const pathList = payload.path; - const formData = new FormData(); - formData.append('parent_id', payload.parentId); - fileList.forEach((file: any, index: number) => { - formData.append('file', file); - formData.append('path', pathList[index]); - }); - const { data } = yield call(fileManagerService.uploadFile, formData); - if (data.retcode === 0) { - message.success(i18n.t('message.uploaded')); - - yield put({ - type: 'listFile', - payload: { parentId: payload.parentId }, - }); - } - return data.retcode; - }, - *createFolder({ payload = {} }, { call, put }) { - const { data } = yield call(fileManagerService.createFolder, payload); - if (data.retcode === 0) { - message.success(i18n.t('message.created')); - - yield put({ - type: 'listFile', - payload: { parentId: payload.parentId }, - }); - } - return data.retcode; - }, - *getAllParentFolder({ payload = {} }, { call, put }) { - const { data } = yield call( - fileManagerService.getAllParentFolder, - payload, - ); - if (data.retcode === 0) { - yield put({ - type: 'setParentFolderList', - payload: data.data?.parent_folders ?? [], - }); - } - return data.retcode; - }, - *connectFileToKnowledge({ payload = {} }, { call, put }) { - const { data } = yield call( - fileManagerService.connectFileToKnowledge, - omit(payload, 'parentId'), - ); - if (data.retcode === 0) { - message.success(i18n.t('message.operated')); - yield put({ - type: 'listFile', - payload: { parentId: payload.parentId }, - }); - } - return data.retcode; - }, - *getDocumentFile({ payload = {} }, { call }) { - const ret = yield call(getDocumentFile, payload); - - return ret; - }, - }, -}; - -// const finalModel = modelExtend>( -// paginationModel, -// model, -// ); - -// console.info(finalModel); - -export default model; diff --git a/web/typings.d.ts b/web/typings.d.ts index 4b9d7f5a4..bf1401ff8 100644 --- a/web/typings.d.ts +++ b/web/typings.d.ts @@ -3,7 +3,6 @@ import { KFModelState } from '@/pages/add-knowledge/components/knowledge-file/mo import { TestingModelState } from '@/pages/add-knowledge/components/knowledge-testing/model'; import { kAModelState } from '@/pages/add-knowledge/model'; import { ChatModelState } from '@/pages/chat/model'; -import { FileManagerModelState } from '@/pages/file-manager/model'; import { LoginModelState } from '@/pages/login/model'; import { SettingModelState } from '@/pages/user-setting/model'; @@ -15,8 +14,6 @@ function useSelector( ): TSelected; export interface RootState { - // loading: Loading; - fileManager: FileManagerModelState; chatModel: ChatModelState; loginModel: LoginModelState; settingModel: SettingModelState;