feat: add file icon to table of FileManager #345 (#543)

### 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)
This commit is contained in:
balibabu
2024-04-25 19:06:24 +08:00
committed by GitHub
parent 26003b5076
commit 1dcd439c58
19 changed files with 317 additions and 154 deletions

View File

@ -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>
);
};

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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');
export const useGetFilesPagination = () => {
const { pagination } = useSelector((state) => state.fileManager);
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],
);
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,

View File

@ -16,3 +16,7 @@
width: 22px;
text-align: center;
}
.linkButton {
padding: 0;
}

View File

@ -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}

View File

@ -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;