feat: translate FileManager #345 (#558)

### What problem does this PR solve?
#345
feat: translate FileManager
feat: batch delete files from the file table in the knowledge base

### Type of change

- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2024-04-26 17:22:23 +08:00
committed by GitHub
parent f69ff39fa0
commit eb62c669ae
20 changed files with 212 additions and 69 deletions

View File

@@ -38,7 +38,7 @@ const ActionCell = ({
const onDownloadDocument = () => {
downloadFile({
url: `${api_host}/document/get/${documentId}`,
url: `${api_host}/file/get/${documentId}`,
filename: record.name,
});
};

View File

@@ -1,3 +1,4 @@
import { useTranslate } from '@/hooks/commonHooks';
import { useFetchKnowledgeList } from '@/hooks/knowledgeHook';
import { IModalProps } from '@/interfaces/common';
import { Form, Modal, Select, SelectProps } from 'antd';
@@ -8,9 +9,11 @@ const ConnectToKnowledgeModal = ({
hideModal,
onOk,
initialValue,
loading,
}: IModalProps<string[]> & { initialValue: string[] }) => {
const [form] = Form.useForm();
const { list, fetchList } = useFetchKnowledgeList();
const { t } = useTranslate('fileManager');
const options: SelectProps['options'] = list?.map((item) => ({
label: item.name,
@@ -32,10 +35,11 @@ const ConnectToKnowledgeModal = ({
return (
<Modal
title="Add to Knowledge Base"
title={t('addToKnowledge')}
open={visible}
onOk={handleOk}
onCancel={hideModal}
confirmLoading={loading}
>
<Form form={form}>
<Form.Item name="knowledgeIds" noStyle>
@@ -43,7 +47,7 @@ const ConnectToKnowledgeModal = ({
mode="multiple"
allowClear
style={{ width: '100%' }}
placeholder="Please select"
placeholder={t('pleaseSelect')}
options={options}
/>
</Form.Item>

View File

@@ -20,12 +20,12 @@ import {
import { useMemo } from 'react';
import {
useFetchDocumentListOnMount,
useHandleBreadcrumbClick,
useHandleDeleteFile,
useHandleSearchChange,
useSelectBreadcrumbItems,
} from './hooks';
import { Link } from 'umi';
import styles from './index.less';
interface IProps {
@@ -35,20 +35,6 @@ interface IProps {
setSelectedRowKeys: (keys: string[]) => void;
}
const itemRender: BreadcrumbProps['itemRender'] = (
currentRoute,
params,
items,
) => {
const isLast = currentRoute?.path === items[items.length - 1]?.path;
return isLast ? (
<span>{currentRoute.title}</span>
) : (
<Link to={`${currentRoute.path}`}>{currentRoute.title}</Link>
);
};
const FileToolbar = ({
selectedRowKeys,
showFolderCreateModal,
@@ -59,6 +45,26 @@ const FileToolbar = ({
useFetchDocumentListOnMount();
const { handleInputChange, searchString } = useHandleSearchChange();
const breadcrumbItems = useSelectBreadcrumbItems();
const { handleBreadcrumbClick } = useHandleBreadcrumbClick();
const itemRender: BreadcrumbProps['itemRender'] = (
currentRoute,
params,
items,
) => {
const isLast = currentRoute?.path === items[items.length - 1]?.path;
return isLast ? (
<span>{currentRoute.title}</span>
) : (
<span
className={styles.breadcrumbItemButton}
onClick={() => handleBreadcrumbClick(currentRoute.path)}
>
{currentRoute.title}
</span>
);
};
const actionItems: MenuProps['items'] = useMemo(() => {
return [
@@ -70,7 +76,7 @@ const FileToolbar = ({
<Button type="link">
<Space>
<FileTextOutlined />
{t('localFiles')}
{t('uploadFile', { keyPrefix: 'fileManager' })}
</Space>
</Button>
</div>
@@ -83,12 +89,13 @@ const FileToolbar = ({
label: (
<div>
<Button type="link">
<FolderOpenOutlined />
New Folder
<Space>
<FolderOpenOutlined />
{t('newFolder', { keyPrefix: 'fileManager' })}
</Space>
</Button>
</div>
),
// disabled: true,
},
];
}, [t, showFolderCreateModal, showFileUploadModal]);

View File

@@ -0,0 +1,8 @@
.uploader {
:global {
.ant-upload-list {
max-height: 40vh;
overflow-y: auto;
}
}
}

View File

@@ -1,3 +1,4 @@
import { useTranslate } from '@/hooks/commonHooks';
import { IModalProps } from '@/interfaces/common';
import { InboxOutlined } from '@ant-design/icons';
import {
@@ -12,6 +13,8 @@ import {
} from 'antd';
import { Dispatch, SetStateAction, useState } from 'react';
import styles from './index.less';
const { Dragger } = Upload;
const FileUpload = ({
@@ -23,6 +26,7 @@ const FileUpload = ({
fileList: UploadFile[];
setFileList: Dispatch<SetStateAction<UploadFile[]>>;
}) => {
const { t } = useTranslate('fileManager');
const props: UploadProps = {
multiple: true,
onRemove: (file) => {
@@ -43,17 +47,12 @@ const FileUpload = ({
};
return (
<Dragger {...props}>
<Dragger {...props} className={styles.uploader}>
<p className="ant-upload-drag-icon">
<InboxOutlined />
</p>
<p className="ant-upload-text">
Click or drag file to this area to upload
</p>
<p className="ant-upload-hint">
Support for a single or bulk upload. Strictly prohibited from uploading
company data or other banned files.
</p>
<p className="ant-upload-text">{t('uploadTitle')}</p>
<p className="ant-upload-hint">{t('uploadDescription')}</p>
</Dragger>
);
};
@@ -64,18 +63,25 @@ const FileUploadModal = ({
loading,
onOk: onFileUploadOk,
}: IModalProps<UploadFile[]>) => {
const { t } = useTranslate('fileManager');
const [value, setValue] = useState<string | number>('local');
const [fileList, setFileList] = useState<UploadFile[]>([]);
const [directoryFileList, setDirectoryFileList] = useState<UploadFile[]>([]);
const onOk = () => {
return onFileUploadOk?.([...fileList, ...directoryFileList]);
const onOk = async () => {
const ret = await onFileUploadOk?.([...fileList, ...directoryFileList]);
console.info(ret);
if (ret !== undefined && ret === 0) {
setFileList([]);
setDirectoryFileList([]);
}
return ret;
};
const items: TabsProps['items'] = [
{
key: '1',
label: 'File',
label: t('file'),
children: (
<FileUpload
directory={false}
@@ -86,7 +92,7 @@ const FileUploadModal = ({
},
{
key: '2',
label: 'Directory',
label: t('directory'),
children: (
<FileUpload
directory
@@ -100,7 +106,7 @@ const FileUploadModal = ({
return (
<>
<Modal
title="File upload"
title={t('uploadFile')}
open={visible}
onOk={onOk}
onCancel={hideModal}
@@ -109,8 +115,8 @@ const FileUploadModal = ({
<Flex gap={'large'} vertical>
<Segmented
options={[
{ label: 'Local uploads', value: 'local' },
{ label: 'S3 uploads', value: 's3' },
{ label: t('local'), value: 'local' },
{ label: t('s3'), value: 's3' },
]}
block
value={value}
@@ -119,7 +125,7 @@ const FileUploadModal = ({
{value === 'local' ? (
<Tabs defaultActiveKey="1" items={items} />
) : (
'coming soon'
t('comingSoon', { keyPrefix: 'common' })
)}
</Flex>
</Modal>

View File

@@ -35,7 +35,7 @@ const FolderCreateModal = ({ visible, hideModal, loading, onOk }: IProps) => {
return (
<Modal
title={'New Folder'}
title={t('newFolder', { keyPrefix: 'fileManager' })}
open={visible}
onOk={handleOk}
onCancel={handleCancel}

View File

@@ -244,14 +244,14 @@ export const useHandleUploadFile = () => {
const id = useGetFolderId();
const onFileUploadOk = useCallback(
async (fileList: UploadFile[]) => {
console.info('fileList', fileList);
async (fileList: UploadFile[]): Promise<number | undefined> => {
if (fileList.length > 0) {
const ret = await uploadFile(fileList, id);
const ret: number = await uploadFile(fileList, id);
console.info(ret);
if (ret === 0) {
hideFileUploadModal();
}
return ret;
}
},
[uploadFile, hideFileUploadModal, id],
@@ -295,6 +295,7 @@ export const useHandleConnectToKnowledge = () => {
if (ret === 0) {
hideConnectToKnowledgeModal();
}
return ret;
},
[connectToKnowledge, hideConnectToKnowledgeModal, id, record.id],
);
@@ -320,3 +321,20 @@ export const useHandleConnectToKnowledge = () => {
showConnectToKnowledgeModal: handleShowConnectToKnowledgeModal,
};
};
export const useHandleBreadcrumbClick = () => {
const navigate = useNavigate();
const setPagination = useSetPagination('fileManager');
const handleBreadcrumbClick = useCallback(
(path?: string) => {
if (path) {
setPagination();
navigate(path);
}
},
[setPagination, navigate],
);
return { handleBreadcrumbClick };
};

View File

@@ -20,3 +20,10 @@
.linkButton {
padding: 0;
}
.breadcrumbItemButton {
cursor: pointer;
color: #1677ff;
padding: 0;
height: auto;
}

View File

@@ -1,7 +1,7 @@
import { useSelectFileList } from '@/hooks/fileManagerHooks';
import { IFile } from '@/interfaces/database/file-manager';
import { formatDate } from '@/utils/date';
import { Button, Flex, Table } from 'antd';
import { Button, Flex, Space, Table, Tag } from 'antd';
import { ColumnsType } from 'antd/es/table';
import ActionCell from './action-cell';
import FileToolbar from './file-toolbar';
@@ -18,6 +18,8 @@ import {
import RenameModal from '@/components/rename-modal';
import SvgIcon from '@/components/svg-icon';
import { useTranslate } from '@/hooks/commonHooks';
import { formatNumberWithThousandsSeparator } from '@/utils/commonUtil';
import { getExtension } from '@/utils/documentUtils';
import ConnectToKnowledgeModal from './connect-to-knowledge-modal';
import FileUploadModal from './file-upload-modal';
@@ -25,6 +27,7 @@ import FolderCreateModal from './folder-create-modal';
import styles from './index.less';
const FileManager = () => {
const { t } = useTranslate('fileManager');
const fileList = useSelectFileList();
const { rowSelection, setSelectedRowKeys } = useGetRowSelection();
const loading = useSelectFileListLoading();
@@ -57,12 +60,13 @@ const FileManager = () => {
showConnectToKnowledgeModal,
onConnectToKnowledgeOk,
initialValue,
connectToKnowledgeLoading,
} = useHandleConnectToKnowledge();
const { pagination } = useGetFilesPagination();
const columns: ColumnsType<IFile> = [
{
title: 'Name',
title: t('name'),
dataIndex: 'name',
key: 'name',
render(value, record) {
@@ -88,7 +92,7 @@ const FileManager = () => {
},
},
{
title: 'Upload Date',
title: t('uploadDate'),
dataIndex: 'create_date',
key: 'create_date',
render(text) {
@@ -96,22 +100,35 @@ const FileManager = () => {
},
},
{
title: 'Knowledge Base',
dataIndex: 'kbs_info',
key: 'kbs_info',
title: t('size'),
dataIndex: 'size',
key: 'size',
render(value) {
return Array.isArray(value)
? value?.map((x) => x.kb_name).join(',')
: '';
return (
formatNumberWithThousandsSeparator((value / 1024).toFixed(2)) + ' KB'
);
},
},
{
title: 'Location',
dataIndex: 'location',
key: 'location',
title: t('knowledgeBase'),
dataIndex: 'kbs_info',
key: 'kbs_info',
render(value) {
return Array.isArray(value) ? (
<Space wrap>
{value?.map((x) => (
<Tag color="blue" key={x.kb_id}>
{x.kb_name}
</Tag>
))}
</Space>
) : (
''
);
},
},
{
title: 'Action',
title: t('action'),
dataIndex: 'action',
key: 'action',
render: (text, record) => (
@@ -168,6 +185,7 @@ const FileManager = () => {
visible={connectToKnowledgeVisible}
hideModal={hideConnectToKnowledgeModal}
onOk={onConnectToKnowledgeOk}
loading={connectToKnowledgeLoading}
></ConnectToKnowledgeModal>
</section>
);

View File

@@ -1,7 +1,9 @@
import { paginationModel } from '@/base';
import { BaseState } from '@/interfaces/common';
import { IFile, IFolder } from '@/interfaces/database/file-manager';
import i18n from '@/locales/config';
import fileManagerService from '@/services/fileManagerService';
import { message } from 'antd';
import omit from 'lodash/omit';
import { DvaModel } from 'umi';
@@ -33,6 +35,7 @@ const model: DvaModel<FileManagerModelState> = {
});
const { retcode } = data;
if (retcode === 0) {
message.success(i18n.t('message.deleted'));
yield put({
type: 'listFile',
payload: { parentId: payload.parentId },
@@ -69,6 +72,7 @@ const model: DvaModel<FileManagerModelState> = {
omit(payload, ['parentId']),
);
if (data.retcode === 0) {
message.success(i18n.t('message.renamed'));
yield put({
type: 'listFile',
payload: { parentId: payload.parentId },
@@ -89,6 +93,8 @@ const model: DvaModel<FileManagerModelState> = {
});
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 },
@@ -99,6 +105,8 @@ const model: DvaModel<FileManagerModelState> = {
*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 },
@@ -125,6 +133,7 @@ const model: DvaModel<FileManagerModelState> = {
omit(payload, 'parentId'),
);
if (data.retcode === 0) {
message.success(i18n.t('message.operated'));
yield put({
type: 'listFile',
payload: { parentId: payload.parentId },