### What problem does this PR solve? fix: fetch the file list after uploading the file by @tanstack/react-query #1306 ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)tags/v0.9.0
| import { ResponseType } from '@/interfaces/database/base'; | 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 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 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 { useGetNextPagination, useHandleSearchChange } from './logic-hooks'; | ||||
| import { useSetPaginationParams } from './route-hook'; | import { useSetPaginationParams } from './route-hook'; | ||||
| return id ?? ''; | return id ?? ''; | ||||
| }; | }; | ||||
| export const useFetchFileList = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const fetchFileList = useCallback( | |||||
| (payload: IFileListRequestBody) => { | |||||
| return dispatch<any>({ | |||||
| type: 'fileManager/listFile', | |||||
| payload, | |||||
| }); | |||||
| }, | |||||
| [dispatch], | |||||
| ); | |||||
| return fetchFileList; | |||||
| }; | |||||
| export interface IListResult { | export interface IListResult { | ||||
| searchString: string; | searchString: string; | ||||
| handleInputChange: React.ChangeEventHandler<HTMLInputElement>; | handleInputChange: React.ChangeEventHandler<HTMLInputElement>; | ||||
| pagination: PaginationProps; | pagination: PaginationProps; | ||||
| setPagination: (pagination: { page: number; pageSize: number }) => void; | setPagination: (pagination: { page: number; pageSize: number }) => void; | ||||
| loading: boolean; | |||||
| } | } | ||||
| export const useFetchNextFileList = (): ResponseType<any> & IListResult => { | |||||
| export const useFetchFileList = (): ResponseType<any> & IListResult => { | |||||
| const { searchString, handleInputChange } = useHandleSearchChange(); | const { searchString, handleInputChange } = useHandleSearchChange(); | ||||
| const { pagination, setPagination } = useGetNextPagination(); | const { pagination, setPagination } = useGetNextPagination(); | ||||
| const id = useGetFolderId(); | const id = useGetFolderId(); | ||||
| const { data } = useQuery({ | |||||
| const { data, isFetching: loading } = useQuery({ | |||||
| queryKey: [ | queryKey: [ | ||||
| 'fetchFileList', | 'fetchFileList', | ||||
| // pagination.current, | |||||
| // id, | |||||
| // pagination.pageSize, | |||||
| // searchString, | |||||
| { | { | ||||
| id, | id, | ||||
| searchString, | searchString, | ||||
| handleInputChange: onInputChange, | handleInputChange: onInputChange, | ||||
| pagination: { ...pagination, total: data?.data?.total }, | pagination: { ...pagination, total: data?.data?.total }, | ||||
| setPagination, | setPagination, | ||||
| loading, | |||||
| }; | }; | ||||
| }; | }; | ||||
| export const useRemoveFile = () => { | |||||
| const dispatch = useDispatch(); | |||||
| const removeFile = useCallback( | |||||
| (fileIds: string[], parentId: string) => { | |||||
| return dispatch<any>({ | |||||
| type: 'fileManager/removeFile', | |||||
| payload: { fileIds, parentId }, | |||||
| }); | |||||
| }, | |||||
| [dispatch], | |||||
| ); | |||||
| return removeFile; | |||||
| }; | |||||
| export const useDeleteFile = () => { | export const useDeleteFile = () => { | ||||
| const { setPaginationParams } = useSetPaginationParams(); | const { setPaginationParams } = useSetPaginationParams(); | ||||
| const queryClient = useQueryClient(); | |||||
| const { | const { | ||||
| data, | data, | ||||
| isPending: loading, | isPending: loading, | ||||
| mutationFn: async (params: { fileIds: string[]; parentId: string }) => { | mutationFn: async (params: { fileIds: string[]; parentId: string }) => { | ||||
| const { data } = await fileManagerService.removeFile(params); | const { data } = await fileManagerService.removeFile(params); | ||||
| if (data.retcode === 0) { | 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; | |||||
| }, | }, | ||||
| }); | }); | ||||
| }; | }; | ||||
| export const useRenameFile = () => { | export const useRenameFile = () => { | ||||
| const dispatch = useDispatch(); | |||||
| const renameFile = useCallback( | |||||
| (fileId: string, name: string, parentId: string) => { | |||||
| return dispatch<any>({ | |||||
| 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<any>({ | |||||
| 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 = () => { | export const useCreateFolder = () => { | ||||
| const dispatch = useDispatch(); | |||||
| const { setPaginationParams } = useSetPaginationParams(); | |||||
| const queryClient = useQueryClient(); | |||||
| const { t } = useTranslation(); | |||||
| const createFolder = useCallback( | |||||
| (parentId: string, name: string) => { | |||||
| return dispatch<any>({ | |||||
| 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 = () => { | export const useUploadFile = () => { | ||||
| const dispatch = useDispatch(); | |||||
| const uploadFile = useCallback( | |||||
| (fileList: UploadFile[], parentId: string) => { | |||||
| try { | |||||
| return dispatch<any>({ | |||||
| 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 = () => { | export const useConnectToKnowledge = () => { | ||||
| const dispatch = useDispatch(); | |||||
| const uploadFile = useCallback( | |||||
| (payload: IConnectRequestBody) => { | |||||
| try { | |||||
| return dispatch<any>({ | |||||
| 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 }; | |||||
| }; | }; |
| parentId: string; | parentId: string; | ||||
| } | } | ||||
| export interface IConnectRequestBody extends BaseRequestBody { | |||||
| export interface IConnectRequestBody { | |||||
| fileIds: string[]; | fileIds: string[]; | ||||
| kbIds: string[]; | kbIds: string[]; | ||||
| } | } |
| import { | import { | ||||
| IListResult, | IListResult, | ||||
| useSelectParentFolderList, | |||||
| useFetchParentFolderList, | |||||
| } from '@/hooks/file-manager-hooks'; | } from '@/hooks/file-manager-hooks'; | ||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| const { t } = useTranslate('knowledgeDetails'); | const { t } = useTranslate('knowledgeDetails'); | ||||
| const breadcrumbItems = useSelectBreadcrumbItems(); | const breadcrumbItems = useSelectBreadcrumbItems(); | ||||
| const { handleBreadcrumbClick } = useHandleBreadcrumbClick(); | const { handleBreadcrumbClick } = useHandleBreadcrumbClick(); | ||||
| const parentFolderList = useSelectParentFolderList(); | |||||
| const parentFolderList = useFetchParentFolderList(); | |||||
| const isKnowledgeBase = | const isKnowledgeBase = | ||||
| parentFolderList.at(-1)?.source_type === 'knowledgebase'; | parentFolderList.at(-1)?.source_type === 'knowledgebase'; | ||||
| useConnectToKnowledge, | useConnectToKnowledge, | ||||
| useCreateFolder, | useCreateFolder, | ||||
| useDeleteFile, | useDeleteFile, | ||||
| useFetchFileList, | |||||
| useFetchParentFolderList, | useFetchParentFolderList, | ||||
| useRenameFile, | useRenameFile, | ||||
| useSelectFileList, | |||||
| useSelectParentFolderList, | |||||
| useUploadFile, | useUploadFile, | ||||
| } from '@/hooks/file-manager-hooks'; | } 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 { IFile } from '@/interfaces/database/file-manager'; | ||||
| import { PaginationProps } from 'antd'; | |||||
| import { TableRowSelection } from 'antd/es/table/interface'; | import { TableRowSelection } from 'antd/es/table/interface'; | ||||
| import { UploadFile } from 'antd/lib'; | 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 = () => { | export const useGetFolderId = () => { | ||||
| const [searchParams] = useSearchParams(); | const [searchParams] = useSearchParams(); | ||||
| return id ?? ''; | 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<HTMLInputElement | HTMLTextAreaElement>) => { | |||||
| const value = e.target.value; | |||||
| dispatch({ type: 'fileManager/setSearchString', payload: value }); | |||||
| setPagination(); | |||||
| }, | |||||
| [setPagination, dispatch], | |||||
| ); | |||||
| return { handleInputChange, searchString }; | |||||
| }; | |||||
| export const useGetRowSelection = () => { | export const useGetRowSelection = () => { | ||||
| const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]); | const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]); | ||||
| hideModal: hideFileRenameModal, | hideModal: hideFileRenameModal, | ||||
| showModal: showFileRenameModal, | showModal: showFileRenameModal, | ||||
| } = useSetModalState(); | } = useSetModalState(); | ||||
| const renameFile = useRenameFile(); | |||||
| const { renameFile, loading } = useRenameFile(); | |||||
| const onFileRenameOk = useCallback( | const onFileRenameOk = useCallback( | ||||
| async (name: string) => { | async (name: string) => { | ||||
| const ret = await renameFile(file.id, name, file.parent_id); | |||||
| const ret = await renameFile({ | |||||
| fileId: file.id, | |||||
| name, | |||||
| }); | |||||
| if (ret === 0) { | if (ret === 0) { | ||||
| hideFileRenameModal(); | hideFileRenameModal(); | ||||
| [renameFile, file, hideFileRenameModal], | [renameFile, file, hideFileRenameModal], | ||||
| ); | ); | ||||
| const loading = useOneNamespaceEffectsLoading('fileManager', ['renameFile']); | |||||
| const handleShowFileRenameModal = useCallback( | const handleShowFileRenameModal = useCallback( | ||||
| async (record: IFile) => { | async (record: IFile) => { | ||||
| setFile(record); | setFile(record); | ||||
| }; | }; | ||||
| export const useSelectBreadcrumbItems = () => { | 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 | return parentFolderList.length === 1 | ||||
| ? [] | ? [] | ||||
| hideModal: hideFolderCreateModal, | hideModal: hideFolderCreateModal, | ||||
| showModal: showFolderCreateModal, | showModal: showFolderCreateModal, | ||||
| } = useSetModalState(); | } = useSetModalState(); | ||||
| const createFolder = useCreateFolder(); | |||||
| const { createFolder, loading } = useCreateFolder(); | |||||
| const id = useGetFolderId(); | const id = useGetFolderId(); | ||||
| const onFolderCreateOk = useCallback( | const onFolderCreateOk = useCallback( | ||||
| async (name: string) => { | async (name: string) => { | ||||
| const ret = await createFolder(id, name); | |||||
| const ret = await createFolder({ parentId: id, name }); | |||||
| if (ret === 0) { | if (ret === 0) { | ||||
| hideFolderCreateModal(); | hideFolderCreateModal(); | ||||
| [createFolder, hideFolderCreateModal, id], | [createFolder, hideFolderCreateModal, id], | ||||
| ); | ); | ||||
| const loading = useOneNamespaceEffectsLoading('fileManager', [ | |||||
| 'createFolder', | |||||
| ]); | |||||
| return { | return { | ||||
| folderCreateLoading: loading, | folderCreateLoading: loading, | ||||
| onFolderCreateOk, | onFolderCreateOk, | ||||
| return { handleRemoveFile }; | return { handleRemoveFile }; | ||||
| }; | }; | ||||
| export const useSelectFileListLoading = () => { | |||||
| return useOneNamespaceEffectsLoading('fileManager', ['listFile']); | |||||
| }; | |||||
| export const useHandleUploadFile = () => { | export const useHandleUploadFile = () => { | ||||
| const { | const { | ||||
| visible: fileUploadVisible, | visible: fileUploadVisible, | ||||
| hideModal: hideFileUploadModal, | hideModal: hideFileUploadModal, | ||||
| showModal: showFileUploadModal, | showModal: showFileUploadModal, | ||||
| } = useSetModalState(); | } = useSetModalState(); | ||||
| const uploadFile = useUploadFile(); | |||||
| const { uploadFile, loading } = useUploadFile(); | |||||
| const id = useGetFolderId(); | const id = useGetFolderId(); | ||||
| const onFileUploadOk = useCallback( | const onFileUploadOk = useCallback( | ||||
| async (fileList: UploadFile[]): Promise<number | undefined> => { | async (fileList: UploadFile[]): Promise<number | undefined> => { | ||||
| if (fileList.length > 0) { | 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) { | if (ret === 0) { | ||||
| hideFileUploadModal(); | hideFileUploadModal(); | ||||
| } | } | ||||
| [uploadFile, hideFileUploadModal, id], | [uploadFile, hideFileUploadModal, id], | ||||
| ); | ); | ||||
| const loading = useOneNamespaceEffectsLoading('fileManager', ['uploadFile']); | |||||
| return { | return { | ||||
| fileUploadLoading: loading, | fileUploadLoading: loading, | ||||
| onFileUploadOk, | onFileUploadOk, | ||||
| hideModal: hideConnectToKnowledgeModal, | hideModal: hideConnectToKnowledgeModal, | ||||
| showModal: showConnectToKnowledgeModal, | showModal: showConnectToKnowledgeModal, | ||||
| } = useSetModalState(); | } = useSetModalState(); | ||||
| const connectToKnowledge = useConnectToKnowledge(); | |||||
| const id = useGetFolderId(); | |||||
| const { connectFileToKnowledge: connectToKnowledge, loading } = | |||||
| useConnectToKnowledge(); | |||||
| const [record, setRecord] = useState<IFile>({} as IFile); | const [record, setRecord] = useState<IFile>({} as IFile); | ||||
| const initialValue = useMemo(() => { | const initialValue = useMemo(() => { | ||||
| const onConnectToKnowledgeOk = useCallback( | const onConnectToKnowledgeOk = useCallback( | ||||
| async (knowledgeIds: string[]) => { | async (knowledgeIds: string[]) => { | ||||
| const ret = await connectToKnowledge({ | const ret = await connectToKnowledge({ | ||||
| parentId: id, | |||||
| fileIds: [record.id], | fileIds: [record.id], | ||||
| kbIds: knowledgeIds, | kbIds: knowledgeIds, | ||||
| }); | }); | ||||
| } | } | ||||
| return ret; | return ret; | ||||
| }, | }, | ||||
| [connectToKnowledge, hideConnectToKnowledgeModal, id, record.id], | |||||
| [connectToKnowledge, hideConnectToKnowledgeModal, record.id], | |||||
| ); | ); | ||||
| const loading = useOneNamespaceEffectsLoading('fileManager', [ | |||||
| 'connectFileToKnowledge', | |||||
| ]); | |||||
| const handleShowConnectToKnowledgeModal = useCallback( | const handleShowConnectToKnowledgeModal = useCallback( | ||||
| (record: IFile) => { | (record: IFile) => { | ||||
| setRecord(record); | setRecord(record); | ||||
| export const useHandleBreadcrumbClick = () => { | export const useHandleBreadcrumbClick = () => { | ||||
| const navigate = useNavigate(); | const navigate = useNavigate(); | ||||
| const setPagination = useSetPagination('fileManager'); | |||||
| const handleBreadcrumbClick = useCallback( | const handleBreadcrumbClick = useCallback( | ||||
| (path?: string) => { | (path?: string) => { | ||||
| if (path) { | if (path) { | ||||
| setPagination(); | |||||
| navigate(path); | navigate(path); | ||||
| } | } | ||||
| }, | }, | ||||
| [setPagination, navigate], | |||||
| [navigate], | |||||
| ); | ); | ||||
| return { handleBreadcrumbClick }; | return { handleBreadcrumbClick }; |
| import { useFetchNextFileList } from '@/hooks/file-manager-hooks'; | |||||
| import { useFetchFileList } from '@/hooks/file-manager-hooks'; | |||||
| import { IFile } from '@/interfaces/database/file-manager'; | import { IFile } from '@/interfaces/database/file-manager'; | ||||
| import { formatDate } from '@/utils/date'; | import { formatDate } from '@/utils/date'; | ||||
| import { Button, Flex, Space, Table, Tag, Typography } from 'antd'; | import { Button, Flex, Space, Table, Tag, Typography } from 'antd'; | ||||
| useHandleUploadFile, | useHandleUploadFile, | ||||
| useNavigateToOtherFolder, | useNavigateToOtherFolder, | ||||
| useRenameCurrentFile, | useRenameCurrentFile, | ||||
| useSelectFileListLoading, | |||||
| } from './hooks'; | } from './hooks'; | ||||
| import FileUploadModal from '@/components/file-upload-modal'; | import FileUploadModal from '@/components/file-upload-modal'; | ||||
| const { t } = useTranslate('fileManager'); | const { t } = useTranslate('fileManager'); | ||||
| // const fileList = useSelectFileList(); | // const fileList = useSelectFileList(); | ||||
| const { rowSelection, setSelectedRowKeys } = useGetRowSelection(); | const { rowSelection, setSelectedRowKeys } = useGetRowSelection(); | ||||
| const loading = useSelectFileListLoading(); | |||||
| const navigateToOtherFolder = useNavigateToOtherFolder(); | const navigateToOtherFolder = useNavigateToOtherFolder(); | ||||
| const { | const { | ||||
| fileRenameVisible, | fileRenameVisible, | ||||
| connectToKnowledgeLoading, | connectToKnowledgeLoading, | ||||
| } = useHandleConnectToKnowledge(); | } = useHandleConnectToKnowledge(); | ||||
| // const { pagination } = useGetFilesPagination(); | // const { pagination } = useGetFilesPagination(); | ||||
| const { pagination, data, searchString, handleInputChange } = | |||||
| useFetchNextFileList(); | |||||
| const { pagination, data, searchString, handleInputChange, loading } = | |||||
| useFetchFileList(); | |||||
| const columns: ColumnsType<IFile> = [ | const columns: ColumnsType<IFile> = [ | ||||
| { | { | ||||
| title: t('name'), | title: t('name'), |
| 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<FileManagerModelState> = { | |||||
| 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<DvaModel<FileManagerModelState & BaseState>>( | |||||
| // paginationModel, | |||||
| // model, | |||||
| // ); | |||||
| // console.info(finalModel); | |||||
| export default model; |
| import { TestingModelState } from '@/pages/add-knowledge/components/knowledge-testing/model'; | import { TestingModelState } from '@/pages/add-knowledge/components/knowledge-testing/model'; | ||||
| import { kAModelState } from '@/pages/add-knowledge/model'; | import { kAModelState } from '@/pages/add-knowledge/model'; | ||||
| import { ChatModelState } from '@/pages/chat/model'; | import { ChatModelState } from '@/pages/chat/model'; | ||||
| import { FileManagerModelState } from '@/pages/file-manager/model'; | |||||
| import { LoginModelState } from '@/pages/login/model'; | import { LoginModelState } from '@/pages/login/model'; | ||||
| import { SettingModelState } from '@/pages/user-setting/model'; | import { SettingModelState } from '@/pages/user-setting/model'; | ||||
| ): TSelected; | ): TSelected; | ||||
| export interface RootState { | export interface RootState { | ||||
| // loading: Loading; | |||||
| fileManager: FileManagerModelState; | |||||
| chatModel: ChatModelState; | chatModel: ChatModelState; | ||||
| loginModel: LoginModelState; | loginModel: LoginModelState; | ||||
| settingModel: SettingModelState; | settingModel: SettingModelState; |