### What problem does this PR solve? feat: add file icon to table of FileManager #345 fix: modify datasetDescription ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.3.1
| @@ -0,0 +1,18 @@ | |||
| <svg width="24" height="18" viewBox="0 0 24 18" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||
| <path | |||
| d="M1.32202e-08 2.54731L21.5 2.54731C22.8807 2.54731 24 3.4977 24 4.67006L24 15.2838C24 16.4562 22.8807 17.4066 21.5 17.4066L12 17.4066L2.5 17.4066C1.11929 17.4066 8.54054e-08 16.4562 7.9321e-08 15.2838L1.32202e-08 2.54731Z" | |||
| fill="#FBBC1A" /> | |||
| <path | |||
| d="M2.97454e-08 5.73144L7.49143e-08 14.4347C8.09987e-08 15.6071 1.11929 16.5575 2.5 16.5575L21.5 16.5575C22.8807 16.5575 24 15.6071 24 14.4347L24 5.51916C24 4.3468 22.8807 3.39641 21.5 3.39641L11 3.39641L11 4.45779C11 5.16121 10.3284 5.73144 9.5 5.73144L2.97454e-08 5.73144Z" | |||
| fill="url(#paint0_linear_2323_8307)" /> | |||
| <path | |||
| d="M8.81345e-09 1.6982C3.94591e-09 0.760312 0.89543 -4.64716e-09 2 -1.03797e-08L9 -4.67088e-08C10.1046 -5.24413e-08 11 0.760312 11 1.6982L11 2.54731L1.32202e-08 2.54731L8.81345e-09 1.6982Z" | |||
| fill="#FBBC1A" /> | |||
| <defs> | |||
| <linearGradient id="paint0_linear_2323_8307" x1="0" y1="0" x2="28.8004" y2="20.3231" | |||
| gradientUnits="userSpaceOnUse"> | |||
| <stop stop-color="#FFE69C" /> | |||
| <stop offset="1" stop-color="#FFC937" /> | |||
| </linearGradient> | |||
| </defs> | |||
| </svg> | |||
| @@ -0,0 +1,48 @@ | |||
| import isObject from 'lodash/isObject'; | |||
| import { DvaModel } from 'umi'; | |||
| import { BaseState } from './interfaces/common'; | |||
| type State = Record<string, any>; | |||
| type DvaModelKey<T> = keyof DvaModel<T>; | |||
| export const modelExtend = <T>( | |||
| baseModel: Partial<DvaModel<any>>, | |||
| extendModel: DvaModel<any>, | |||
| ): DvaModel<T> => { | |||
| return Object.keys(extendModel).reduce<DvaModel<T>>((pre, cur) => { | |||
| const baseValue = baseModel[cur as DvaModelKey<State>]; | |||
| const value = extendModel[cur as DvaModelKey<State>]; | |||
| if (isObject(value) && isObject(baseValue) && typeof value !== 'string') { | |||
| const key = cur as Exclude<DvaModelKey<State>, 'namespace'>; | |||
| pre[key] = { | |||
| ...baseValue, | |||
| ...value, | |||
| } as any; | |||
| } else { | |||
| pre[cur as DvaModelKey<State>] = value as any; | |||
| } | |||
| return pre; | |||
| }, {} as DvaModel<T>); | |||
| }; | |||
| export const paginationModel: Partial<DvaModel<BaseState>> = { | |||
| state: { | |||
| searchString: '', | |||
| pagination: { | |||
| total: 0, | |||
| current: 1, | |||
| pageSize: 10, | |||
| }, | |||
| }, | |||
| reducers: { | |||
| setSearchString(state, { payload }) { | |||
| return { ...state, searchString: payload }; | |||
| }, | |||
| setPagination(state, { payload }) { | |||
| return { ...state, pagination: { ...state.pagination, ...payload } }; | |||
| }, | |||
| }, | |||
| }; | |||
| @@ -103,14 +103,14 @@ export const useUploadFile = () => { | |||
| const dispatch = useDispatch(); | |||
| const uploadFile = useCallback( | |||
| (file: UploadFile, parentId: string, path: string) => { | |||
| (fileList: UploadFile[], parentId: string) => { | |||
| try { | |||
| return dispatch<any>({ | |||
| type: 'fileManager/uploadFile', | |||
| payload: { | |||
| file, | |||
| file: fileList, | |||
| parentId, | |||
| path, | |||
| path: fileList.map((file) => (file as any).webkitRelativePath), | |||
| }, | |||
| }); | |||
| } catch (errorInfo) { | |||
| @@ -127,13 +127,13 @@ export const useFetchKnowledgeBaseConfiguration = () => { | |||
| export const useFetchKnowledgeList = ( | |||
| shouldFilterListWithoutDocument: boolean = false, | |||
| ): { list: IKnowledge[]; loading: boolean } => { | |||
| ) => { | |||
| const dispatch = useDispatch(); | |||
| const loading = useOneNamespaceEffectsLoading('knowledgeModel', ['getList']); | |||
| const knowledgeModel = useSelector((state: any) => state.knowledgeModel); | |||
| const { data = [] } = knowledgeModel; | |||
| const list = useMemo(() => { | |||
| const list: IKnowledge[] = useMemo(() => { | |||
| return shouldFilterListWithoutDocument | |||
| ? data.filter((x: IKnowledge) => x.chunk_num > 0) | |||
| : data; | |||
| @@ -149,7 +149,7 @@ export const useFetchKnowledgeList = ( | |||
| fetchList(); | |||
| }, [fetchList]); | |||
| return { list, loading }; | |||
| return { list, loading, fetchList }; | |||
| }; | |||
| export const useSelectFileThumbnails = () => { | |||
| @@ -1,9 +1,12 @@ | |||
| import { LanguageTranslationMap } from '@/constants/common'; | |||
| import { Pagination } from '@/interfaces/common'; | |||
| import { IKnowledgeFile } from '@/interfaces/database/knowledge'; | |||
| import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | |||
| import { useCallback, useState } from 'react'; | |||
| import { PaginationProps } from 'antd'; | |||
| import { useCallback, useMemo, useState } from 'react'; | |||
| import { useTranslation } from 'react-i18next'; | |||
| import { useSetModalState } from './commonHooks'; | |||
| import { useDispatch } from 'umi'; | |||
| import { useSetModalState, useTranslate } from './commonHooks'; | |||
| import { useSetDocumentParser } from './documentHooks'; | |||
| import { useOneNamespaceEffectsLoading } from './storeHooks'; | |||
| import { useSaveSetting } from './userSettingHook'; | |||
| @@ -62,3 +65,51 @@ export const useChangeLanguage = () => { | |||
| return changeLanguage; | |||
| }; | |||
| export const useGetPagination = ( | |||
| total: number, | |||
| page: number, | |||
| pageSize: number, | |||
| onPageChange: PaginationProps['onChange'], | |||
| ) => { | |||
| const { t } = useTranslate('common'); | |||
| const pagination: PaginationProps = useMemo(() => { | |||
| return { | |||
| showQuickJumper: true, | |||
| total, | |||
| showSizeChanger: true, | |||
| current: page, | |||
| pageSize: pageSize, | |||
| pageSizeOptions: [1, 2, 10, 20, 50, 100], | |||
| onChange: onPageChange, | |||
| showTotal: (total) => `${t('total')} ${total}`, | |||
| }; | |||
| }, [t, onPageChange, page, pageSize, total]); | |||
| return { | |||
| pagination, | |||
| }; | |||
| }; | |||
| export const useSetPagination = (namespace: string) => { | |||
| const dispatch = useDispatch(); | |||
| const setPagination = useCallback( | |||
| (pageNumber = 1, pageSize?: number) => { | |||
| const pagination: Pagination = { | |||
| current: pageNumber, | |||
| } as Pagination; | |||
| if (pageSize) { | |||
| pagination.pageSize = pageSize; | |||
| } | |||
| dispatch({ | |||
| type: `${namespace}/setPagination`, | |||
| payload: pagination, | |||
| }); | |||
| }, | |||
| [dispatch, namespace], | |||
| ); | |||
| return setPagination; | |||
| }; | |||
| @@ -1,6 +1,7 @@ | |||
| export interface Pagination { | |||
| current: number; | |||
| pageSize: number; | |||
| total: number; | |||
| } | |||
| export interface BaseState { | |||
| @@ -70,7 +70,7 @@ export default { | |||
| namePlaceholder: 'Please input name!', | |||
| doc: 'Docs', | |||
| datasetDescription: | |||
| "Hey, don't forget to adjust the chunk after adding the dataset! 😉", | |||
| '😉 Questions and answers can only be answered after the parsing is successful.', | |||
| addFile: 'Add file', | |||
| searchFiles: 'Search your files', | |||
| localFiles: 'Local files', | |||
| @@ -69,7 +69,7 @@ export default { | |||
| name: '名稱', | |||
| namePlaceholder: '請輸入名稱', | |||
| doc: '文件', | |||
| datasetDescription: '嘿,添加數據集後別忘了調整解析塊!😉', | |||
| datasetDescription: '😉 解析成功後才能問答哦。', | |||
| addFile: '新增文件', | |||
| searchFiles: '搜索文件', | |||
| localFiles: '本地文件', | |||
| @@ -69,7 +69,7 @@ export default { | |||
| name: '名称', | |||
| namePlaceholder: '请输入名称', | |||
| doc: '文档', | |||
| datasetDescription: '嘿,添加数据集后别忘了调整解析块! 😉', | |||
| datasetDescription: '😉 解析成功后才能问答哦。', | |||
| addFile: '新增文件', | |||
| searchFiles: '搜索文件', | |||
| localFiles: '本地文件', | |||
| @@ -17,7 +17,8 @@ interface IProps { | |||
| record: IFile; | |||
| setCurrentRecord: (record: any) => void; | |||
| showRenameModal: (record: IFile) => void; | |||
| showConnectToKnowledgeModal: (ids: string[]) => void; | |||
| showConnectToKnowledgeModal: (record: IFile) => void; | |||
| setSelectedRowKeys(keys: string[]): void; | |||
| } | |||
| const ActionCell = ({ | |||
| @@ -25,11 +26,15 @@ const ActionCell = ({ | |||
| setCurrentRecord, | |||
| showRenameModal, | |||
| showConnectToKnowledgeModal, | |||
| setSelectedRowKeys, | |||
| }: IProps) => { | |||
| const documentId = record.id; | |||
| const beingUsed = false; | |||
| const { t } = useTranslate('knowledgeDetails'); | |||
| const { handleRemoveFile } = useHandleDeleteFile([documentId]); | |||
| const { handleRemoveFile } = useHandleDeleteFile( | |||
| [documentId], | |||
| setSelectedRowKeys, | |||
| ); | |||
| const onDownloadDocument = () => { | |||
| downloadFile({ | |||
| @@ -48,7 +53,7 @@ const ActionCell = ({ | |||
| }; | |||
| const onShowConnectToKnowledgeModal = () => { | |||
| showConnectToKnowledgeModal([documentId]); | |||
| showConnectToKnowledgeModal(record); | |||
| }; | |||
| return ( | |||
| @@ -79,14 +84,16 @@ const ActionCell = ({ | |||
| > | |||
| <DeleteOutlined size={20} /> | |||
| </Button> | |||
| <Button | |||
| type="text" | |||
| disabled={beingUsed} | |||
| onClick={onDownloadDocument} | |||
| className={styles.iconButton} | |||
| > | |||
| <DownloadOutlined size={20} /> | |||
| </Button> | |||
| {record.type !== 'folder' && ( | |||
| <Button | |||
| type="text" | |||
| disabled={beingUsed} | |||
| onClick={onDownloadDocument} | |||
| className={styles.iconButton} | |||
| > | |||
| <DownloadOutlined size={20} /> | |||
| </Button> | |||
| )} | |||
| </Space> | |||
| ); | |||
| }; | |||
| @@ -1,14 +1,16 @@ | |||
| import { useFetchKnowledgeList } from '@/hooks/knowledgeHook'; | |||
| import { IModalProps } from '@/interfaces/common'; | |||
| import { Form, Modal, Select, SelectProps } from 'antd'; | |||
| import { useEffect } from 'react'; | |||
| const ConnectToKnowledgeModal = ({ | |||
| visible, | |||
| hideModal, | |||
| onOk, | |||
| }: IModalProps<string[]>) => { | |||
| initialValue, | |||
| }: IModalProps<string[]> & { initialValue: string[] }) => { | |||
| const [form] = Form.useForm(); | |||
| const { list } = useFetchKnowledgeList(); | |||
| const { list, fetchList } = useFetchKnowledgeList(); | |||
| const options: SelectProps['options'] = list?.map((item) => ({ | |||
| label: item.name, | |||
| @@ -18,11 +20,16 @@ const ConnectToKnowledgeModal = ({ | |||
| const handleOk = async () => { | |||
| const values = await form.getFieldsValue(); | |||
| const knowledgeIds = values.knowledgeIds ?? []; | |||
| if (knowledgeIds.length > 0) { | |||
| return onOk?.(knowledgeIds); | |||
| } | |||
| return onOk?.(knowledgeIds); | |||
| }; | |||
| useEffect(() => { | |||
| if (visible) { | |||
| form.setFieldValue('knowledgeIds', initialValue); | |||
| fetchList(); | |||
| } | |||
| }, [visible, fetchList, initialValue, form]); | |||
| return ( | |||
| <Modal | |||
| title="Add to Knowledge Base" | |||
| @@ -31,17 +38,7 @@ const ConnectToKnowledgeModal = ({ | |||
| onCancel={hideModal} | |||
| > | |||
| <Form form={form}> | |||
| <Form.Item | |||
| name="knowledgeIds" | |||
| noStyle | |||
| rules={[ | |||
| { | |||
| required: true, | |||
| message: 'Please select your favourite colors!', | |||
| type: 'array', | |||
| }, | |||
| ]} | |||
| > | |||
| <Form.Item name="knowledgeIds" noStyle> | |||
| <Select | |||
| mode="multiple" | |||
| allowClear | |||
| @@ -20,7 +20,6 @@ import { | |||
| import { useMemo } from 'react'; | |||
| import { | |||
| useFetchDocumentListOnMount, | |||
| useGetPagination, | |||
| useHandleDeleteFile, | |||
| useHandleSearchChange, | |||
| useSelectBreadcrumbItems, | |||
| @@ -33,6 +32,7 @@ interface IProps { | |||
| selectedRowKeys: string[]; | |||
| showFolderCreateModal: () => void; | |||
| showFileUploadModal: () => void; | |||
| setSelectedRowKeys: (keys: string[]) => void; | |||
| } | |||
| const itemRender: BreadcrumbProps['itemRender'] = ( | |||
| @@ -53,11 +53,11 @@ const FileToolbar = ({ | |||
| selectedRowKeys, | |||
| showFolderCreateModal, | |||
| showFileUploadModal, | |||
| setSelectedRowKeys, | |||
| }: IProps) => { | |||
| const { t } = useTranslate('knowledgeDetails'); | |||
| const { fetchDocumentList } = useFetchDocumentListOnMount(); | |||
| const { setPagination, searchString } = useGetPagination(fetchDocumentList); | |||
| const { handleInputChange } = useHandleSearchChange(setPagination); | |||
| useFetchDocumentListOnMount(); | |||
| const { handleInputChange, searchString } = useHandleSearchChange(); | |||
| const breadcrumbItems = useSelectBreadcrumbItems(); | |||
| const actionItems: MenuProps['items'] = useMemo(() => { | |||
| @@ -93,7 +93,10 @@ const FileToolbar = ({ | |||
| ]; | |||
| }, [t, showFolderCreateModal, showFileUploadModal]); | |||
| const { handleRemoveFile } = useHandleDeleteFile(selectedRowKeys); | |||
| const { handleRemoveFile } = useHandleDeleteFile( | |||
| selectedRowKeys, | |||
| setSelectedRowKeys, | |||
| ); | |||
| const disabled = selectedRowKeys.length === 0; | |||
| @@ -11,7 +11,6 @@ import { | |||
| UploadProps, | |||
| } from 'antd'; | |||
| import { Dispatch, SetStateAction, useState } from 'react'; | |||
| import { useHandleUploadFile } from '../hooks'; | |||
| const { Dragger } = Upload; | |||
| @@ -59,14 +58,18 @@ const FileUpload = ({ | |||
| ); | |||
| }; | |||
| const FileUploadModal = ({ visible, hideModal }: IModalProps<any>) => { | |||
| const FileUploadModal = ({ | |||
| visible, | |||
| hideModal, | |||
| loading, | |||
| onOk: onFileUploadOk, | |||
| }: IModalProps<UploadFile[]>) => { | |||
| const [value, setValue] = useState<string | number>('local'); | |||
| const { onFileUploadOk, fileUploadLoading } = useHandleUploadFile(); | |||
| const [fileList, setFileList] = useState<UploadFile[]>([]); | |||
| const [directoryFileList, setDirectoryFileList] = useState<UploadFile[]>([]); | |||
| const onOk = () => { | |||
| onFileUploadOk([...fileList, ...directoryFileList]); | |||
| return onFileUploadOk?.([...fileList, ...directoryFileList]); | |||
| }; | |||
| const items: TabsProps['items'] = [ | |||
| @@ -101,7 +104,7 @@ const FileUploadModal = ({ visible, hideModal }: IModalProps<any>) => { | |||
| open={visible} | |||
| onOk={onOk} | |||
| onCancel={hideModal} | |||
| confirmLoading={fileUploadLoading} | |||
| confirmLoading={loading} | |||
| > | |||
| <Flex gap={'large'} vertical> | |||
| <Segmented | |||
| @@ -1,8 +1,4 @@ | |||
| import { | |||
| useSetModalState, | |||
| useShowDeleteConfirm, | |||
| useTranslate, | |||
| } from '@/hooks/commonHooks'; | |||
| import { useSetModalState, useShowDeleteConfirm } from '@/hooks/commonHooks'; | |||
| import { | |||
| useConnectToKnowledge, | |||
| useCreateFolder, | |||
| @@ -14,10 +10,9 @@ import { | |||
| useSelectParentFolderList, | |||
| useUploadFile, | |||
| } from '@/hooks/fileManagerHooks'; | |||
| import { useGetPagination, useSetPagination } from '@/hooks/logicHooks'; | |||
| import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks'; | |||
| import { Pagination } from '@/interfaces/common'; | |||
| import { IFile } from '@/interfaces/database/file-manager'; | |||
| import { getFilePathByWebkitRelativePath } from '@/utils/fileUtil'; | |||
| import { PaginationProps } from 'antd'; | |||
| import { UploadFile } from 'antd/lib'; | |||
| import { useCallback, useEffect, useMemo, useState } from 'react'; | |||
| @@ -27,95 +22,72 @@ export const useGetFolderId = () => { | |||
| const [searchParams] = useSearchParams(); | |||
| const id = searchParams.get('folderId') as string; | |||
| 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 }); | |||
| }, [dispatch, fetchDocumentList, id]); | |||
| fetchDocumentList({ | |||
| parent_id: id, | |||
| keywords: searchString, | |||
| page_size: pageSize, | |||
| page: current, | |||
| }); | |||
| }, [dispatch, fetchDocumentList, id, current, pageSize, searchString]); | |||
| return { fetchDocumentList, fileList }; | |||
| }; | |||
| export const useGetPagination = ( | |||
| fetchDocumentList: (payload: IFile) => any, | |||
| ) => { | |||
| const dispatch = useDispatch(); | |||
| const kFModel = useSelector((state: any) => state.kFModel); | |||
| const { t } = useTranslate('common'); | |||
| const setPagination = useCallback( | |||
| (pageNumber = 1, pageSize?: number) => { | |||
| const pagination: Pagination = { | |||
| current: pageNumber, | |||
| } as Pagination; | |||
| if (pageSize) { | |||
| pagination.pageSize = pageSize; | |||
| } | |||
| dispatch({ | |||
| type: 'kFModel/setPagination', | |||
| payload: pagination, | |||
| }); | |||
| }, | |||
| [dispatch], | |||
| ); | |||
| 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); | |||
| fetchDocumentList(); | |||
| }, | |||
| [fetchDocumentList, setPagination], | |||
| [setPagination], | |||
| ); | |||
| const pagination: PaginationProps = useMemo(() => { | |||
| return { | |||
| showQuickJumper: true, | |||
| total: kFModel.total, | |||
| showSizeChanger: true, | |||
| current: kFModel.pagination.current, | |||
| pageSize: kFModel.pagination.pageSize, | |||
| pageSizeOptions: [1, 2, 10, 20, 50, 100], | |||
| onChange: onPageChange, | |||
| showTotal: (total) => `${t('total')} ${total}`, | |||
| }; | |||
| }, [kFModel, onPageChange, t]); | |||
| const { pagination: paginationInfo } = useGetPagination( | |||
| pagination.total, | |||
| pagination.current, | |||
| pagination.pageSize, | |||
| onPageChange, | |||
| ); | |||
| return { | |||
| pagination, | |||
| pagination: paginationInfo, | |||
| setPagination, | |||
| total: kFModel.total, | |||
| searchString: kFModel.searchString, | |||
| }; | |||
| }; | |||
| export const useHandleSearchChange = (setPagination: () => void) => { | |||
| export const useHandleSearchChange = () => { | |||
| const dispatch = useDispatch(); | |||
| const throttledGetDocumentList = useCallback(() => { | |||
| dispatch({ | |||
| type: 'kFModel/throttledGetDocumentList', | |||
| }); | |||
| }, [dispatch]); | |||
| 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: 'kFModel/setSearchString', payload: value }); | |||
| dispatch({ type: 'fileManager/setSearchString', payload: value }); | |||
| setPagination(); | |||
| throttledGetDocumentList(); | |||
| }, | |||
| [setPagination, throttledGetDocumentList, dispatch], | |||
| [setPagination, dispatch], | |||
| ); | |||
| return { handleInputChange }; | |||
| return { handleInputChange, searchString }; | |||
| }; | |||
| export const useGetRowSelection = () => { | |||
| @@ -128,7 +100,7 @@ export const useGetRowSelection = () => { | |||
| }, | |||
| }; | |||
| return rowSelection; | |||
| return { rowSelection, setSelectedRowKeys }; | |||
| }; | |||
| export const useNavigateToOtherFolder = () => { | |||
| @@ -235,15 +207,22 @@ export const useHandleCreateFolder = () => { | |||
| }; | |||
| }; | |||
| export const useHandleDeleteFile = (fileIds: string[]) => { | |||
| export const useHandleDeleteFile = ( | |||
| fileIds: string[], | |||
| setSelectedRowKeys: (keys: string[]) => void, | |||
| ) => { | |||
| const removeDocument = useRemoveFile(); | |||
| const showDeleteConfirm = useShowDeleteConfirm(); | |||
| const parentId = useGetFolderId(); | |||
| const handleRemoveFile = () => { | |||
| showDeleteConfirm({ | |||
| onOk: () => { | |||
| return removeDocument(fileIds, parentId); | |||
| onOk: async () => { | |||
| const retcode = await removeDocument(fileIds, parentId); | |||
| if (retcode === 0) { | |||
| setSelectedRowKeys([]); | |||
| } | |||
| return; | |||
| }, | |||
| }); | |||
| }; | |||
| @@ -268,12 +247,8 @@ export const useHandleUploadFile = () => { | |||
| async (fileList: UploadFile[]) => { | |||
| console.info('fileList', fileList); | |||
| if (fileList.length > 0) { | |||
| const ret = await uploadFile( | |||
| fileList[0], | |||
| id, | |||
| getFilePathByWebkitRelativePath(fileList[0] as any), | |||
| ); | |||
| const ret = await uploadFile(fileList, id); | |||
| console.info(ret); | |||
| if (ret === 0) { | |||
| hideFileUploadModal(); | |||
| } | |||
| @@ -301,13 +276,19 @@ export const useHandleConnectToKnowledge = () => { | |||
| } = useSetModalState(); | |||
| const connectToKnowledge = useConnectToKnowledge(); | |||
| const id = useGetFolderId(); | |||
| const [fileIds, setFileIds] = useState<string[]>([]); | |||
| const [record, setRecord] = useState<IFile>({} as IFile); | |||
| const initialValue = useMemo(() => { | |||
| return Array.isArray(record?.kbs_info) | |||
| ? record?.kbs_info?.map((x) => x.kb_id) | |||
| : []; | |||
| }, [record?.kbs_info]); | |||
| const onConnectToKnowledgeOk = useCallback( | |||
| async (knowledgeIds: string[]) => { | |||
| const ret = await connectToKnowledge({ | |||
| parentId: id, | |||
| fileIds, | |||
| fileIds: [record.id], | |||
| kbIds: knowledgeIds, | |||
| }); | |||
| @@ -315,7 +296,7 @@ export const useHandleConnectToKnowledge = () => { | |||
| hideConnectToKnowledgeModal(); | |||
| } | |||
| }, | |||
| [connectToKnowledge, hideConnectToKnowledgeModal, id, fileIds], | |||
| [connectToKnowledge, hideConnectToKnowledgeModal, id, record.id], | |||
| ); | |||
| const loading = useOneNamespaceEffectsLoading('fileManager', [ | |||
| @@ -323,14 +304,15 @@ export const useHandleConnectToKnowledge = () => { | |||
| ]); | |||
| const handleShowConnectToKnowledgeModal = useCallback( | |||
| (ids: string[]) => { | |||
| setFileIds(ids); | |||
| (record: IFile) => { | |||
| setRecord(record); | |||
| showConnectToKnowledgeModal(); | |||
| }, | |||
| [showConnectToKnowledgeModal], | |||
| ); | |||
| return { | |||
| initialValue, | |||
| connectToKnowledgeLoading: loading, | |||
| onConnectToKnowledgeOk, | |||
| connectToKnowledgeVisible, | |||
| @@ -16,3 +16,7 @@ | |||
| width: 22px; | |||
| text-align: center; | |||
| } | |||
| .linkButton { | |||
| padding: 0; | |||
| } | |||
| @@ -1,11 +1,12 @@ | |||
| import { useSelectFileList } from '@/hooks/fileManagerHooks'; | |||
| import { IFile } from '@/interfaces/database/file-manager'; | |||
| import { formatDate } from '@/utils/date'; | |||
| import { Button, Table } from 'antd'; | |||
| import { Button, Flex, Table } from 'antd'; | |||
| import { ColumnsType } from 'antd/es/table'; | |||
| import ActionCell from './action-cell'; | |||
| import FileToolbar from './file-toolbar'; | |||
| import { | |||
| useGetFilesPagination, | |||
| useGetRowSelection, | |||
| useHandleConnectToKnowledge, | |||
| useHandleCreateFolder, | |||
| @@ -16,6 +17,8 @@ import { | |||
| } from './hooks'; | |||
| import RenameModal from '@/components/rename-modal'; | |||
| import SvgIcon from '@/components/svg-icon'; | |||
| import { getExtension } from '@/utils/documentUtils'; | |||
| import ConnectToKnowledgeModal from './connect-to-knowledge-modal'; | |||
| import FileUploadModal from './file-upload-modal'; | |||
| import FolderCreateModal from './folder-create-modal'; | |||
| @@ -23,7 +26,7 @@ import styles from './index.less'; | |||
| const FileManager = () => { | |||
| const fileList = useSelectFileList(); | |||
| const rowSelection = useGetRowSelection(); | |||
| const { rowSelection, setSelectedRowKeys } = useGetRowSelection(); | |||
| const loading = useSelectFileListLoading(); | |||
| const navigateToOtherFolder = useNavigateToOtherFolder(); | |||
| const { | |||
| @@ -41,14 +44,21 @@ const FileManager = () => { | |||
| folderCreateLoading, | |||
| onFolderCreateOk, | |||
| } = useHandleCreateFolder(); | |||
| const { fileUploadVisible, hideFileUploadModal, showFileUploadModal } = | |||
| useHandleUploadFile(); | |||
| const { | |||
| fileUploadVisible, | |||
| hideFileUploadModal, | |||
| showFileUploadModal, | |||
| fileUploadLoading, | |||
| onFileUploadOk, | |||
| } = useHandleUploadFile(); | |||
| const { | |||
| connectToKnowledgeVisible, | |||
| hideConnectToKnowledgeModal, | |||
| showConnectToKnowledgeModal, | |||
| onConnectToKnowledgeOk, | |||
| initialValue, | |||
| } = useHandleConnectToKnowledge(); | |||
| const { pagination } = useGetFilesPagination(); | |||
| const columns: ColumnsType<IFile> = [ | |||
| { | |||
| @@ -56,15 +66,24 @@ const FileManager = () => { | |||
| dataIndex: 'name', | |||
| key: 'name', | |||
| render(value, record) { | |||
| return record.type === 'folder' ? ( | |||
| <Button | |||
| type={'link'} | |||
| onClick={() => navigateToOtherFolder(record.id)} | |||
| > | |||
| {value} | |||
| </Button> | |||
| ) : ( | |||
| value | |||
| return ( | |||
| <Flex gap={10} align="center"> | |||
| <SvgIcon | |||
| name={`file-icon/${record.type === 'folder' ? 'folder' : getExtension(value)}`} | |||
| width={24} | |||
| ></SvgIcon> | |||
| {record.type === 'folder' ? ( | |||
| <Button | |||
| type={'link'} | |||
| className={styles.linkButton} | |||
| onClick={() => navigateToOtherFolder(record.id)} | |||
| > | |||
| {value} | |||
| </Button> | |||
| ) : ( | |||
| value | |||
| )} | |||
| </Flex> | |||
| ); | |||
| }, | |||
| }, | |||
| @@ -77,11 +96,10 @@ const FileManager = () => { | |||
| }, | |||
| }, | |||
| { | |||
| title: 'kbs_info', | |||
| title: 'Knowledge Base', | |||
| dataIndex: 'kbs_info', | |||
| key: 'kbs_info', | |||
| render(value) { | |||
| console.info(value); | |||
| return Array.isArray(value) | |||
| ? value?.map((x) => x.kb_name).join(',') | |||
| : ''; | |||
| @@ -104,6 +122,7 @@ const FileManager = () => { | |||
| }} | |||
| showRenameModal={showFileRenameModal} | |||
| showConnectToKnowledgeModal={showConnectToKnowledgeModal} | |||
| setSelectedRowKeys={setSelectedRowKeys} | |||
| ></ActionCell> | |||
| ), | |||
| }, | |||
| @@ -115,6 +134,7 @@ const FileManager = () => { | |||
| selectedRowKeys={rowSelection.selectedRowKeys as string[]} | |||
| showFolderCreateModal={showFolderCreateModal} | |||
| showFileUploadModal={showFileUploadModal} | |||
| setSelectedRowKeys={setSelectedRowKeys} | |||
| ></FileToolbar> | |||
| <Table | |||
| dataSource={fileList} | |||
| @@ -122,6 +142,7 @@ const FileManager = () => { | |||
| rowKey={'id'} | |||
| rowSelection={rowSelection} | |||
| loading={loading} | |||
| pagination={pagination} | |||
| /> | |||
| <RenameModal | |||
| visible={fileRenameVisible} | |||
| @@ -139,8 +160,11 @@ const FileManager = () => { | |||
| <FileUploadModal | |||
| visible={fileUploadVisible} | |||
| hideModal={hideFileUploadModal} | |||
| loading={fileUploadLoading} | |||
| onOk={onFileUploadOk} | |||
| ></FileUploadModal> | |||
| <ConnectToKnowledgeModal | |||
| initialValue={initialValue} | |||
| visible={connectToKnowledgeVisible} | |||
| hideModal={hideConnectToKnowledgeModal} | |||
| onOk={onConnectToKnowledgeOk} | |||
| @@ -1,16 +1,22 @@ | |||
| import { paginationModel } from '@/base'; | |||
| import { BaseState } from '@/interfaces/common'; | |||
| import { IFile, IFolder } from '@/interfaces/database/file-manager'; | |||
| import fileManagerService from '@/services/fileManagerService'; | |||
| import omit from 'lodash/omit'; | |||
| import { DvaModel } from 'umi'; | |||
| export interface FileManagerModelState { | |||
| export interface FileManagerModelState extends BaseState { | |||
| fileList: IFile[]; | |||
| parentFolderList: IFolder[]; | |||
| } | |||
| const model: DvaModel<FileManagerModelState> = { | |||
| namespace: 'fileManager', | |||
| state: { fileList: [], parentFolderList: [] }, | |||
| state: { | |||
| fileList: [], | |||
| parentFolderList: [], | |||
| ...(paginationModel.state as BaseState), | |||
| }, | |||
| reducers: { | |||
| setFileList(state, { payload }) { | |||
| return { ...state, fileList: payload }; | |||
| @@ -18,6 +24,7 @@ const model: DvaModel<FileManagerModelState> = { | |||
| setParentFolderList(state, { payload }) { | |||
| return { ...state, parentFolderList: payload }; | |||
| }, | |||
| ...paginationModel.reducers, | |||
| }, | |||
| effects: { | |||
| *removeFile({ payload = {} }, { call, put }) { | |||
| @@ -31,16 +38,29 @@ const model: DvaModel<FileManagerModelState> = { | |||
| payload: { parentId: payload.parentId }, | |||
| }); | |||
| } | |||
| return retcode; | |||
| }, | |||
| *listFile({ payload = {} }, { call, put }) { | |||
| const { data } = yield call(fileManagerService.listFile, payload); | |||
| *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 }) { | |||
| @@ -57,10 +77,16 @@ const model: DvaModel<FileManagerModelState> = { | |||
| 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); | |||
| formData.append('file', payload.file); | |||
| formData.append('path', payload.path); | |||
| // formData.append('file', payload.file); | |||
| // formData.append('path', payload.path); | |||
| 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) { | |||
| yield put({ | |||
| @@ -108,4 +134,12 @@ const model: DvaModel<FileManagerModelState> = { | |||
| }, | |||
| }, | |||
| }; | |||
| // const finalModel = modelExtend<DvaModel<FileManagerModelState & BaseState>>( | |||
| // paginationModel, | |||
| // model, | |||
| // ); | |||
| // console.info(finalModel); | |||
| export default model; | |||
| @@ -3,7 +3,7 @@ import kbService from '@/services/kbService'; | |||
| import { DvaModel } from 'umi'; | |||
| export interface KnowledgeModelState { | |||
| data: any[]; | |||
| data: IKnowledge[]; | |||
| knowledge: IKnowledge; | |||
| } | |||
| @@ -85,12 +85,3 @@ export const downloadFile = ({ | |||
| downloadElement.click(); | |||
| document.body.removeChild(downloadElement); | |||
| }; | |||
| export const getFilePathByWebkitRelativePath = (file: File) => { | |||
| const path = file.webkitRelativePath; | |||
| return path; | |||
| // if (path !== '') { | |||
| // return path.slice(0, path.lastIndexOf('/')); | |||
| // } | |||
| // return path; | |||
| }; | |||