balibabu commited on
Commit
40a88fa
·
1 Parent(s): 94f8c29

feat: upload file in FileManager #345 (#529)

Browse files

### What problem does this PR solve?

feat: upload file in FileManager #345

### Type of change

- [x] New Feature (non-breaking change which adds functionality)

web/src/hooks/fileManagerHooks.ts CHANGED
@@ -1,4 +1,8 @@
1
- import { IFileListRequestBody } from '@/interfaces/request/file-manager';
 
 
 
 
2
  import { useCallback } from 'react';
3
  import { useDispatch, useSelector } from 'umi';
4
 
@@ -94,3 +98,47 @@ export const useSelectParentFolderList = () => {
94
  );
95
  return parentFolderList.toReversed();
96
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ IConnectRequestBody,
3
+ IFileListRequestBody,
4
+ } from '@/interfaces/request/file-manager';
5
+ import { UploadFile } from 'antd';
6
  import { useCallback } from 'react';
7
  import { useDispatch, useSelector } from 'umi';
8
 
 
98
  );
99
  return parentFolderList.toReversed();
100
  };
101
+
102
+ export const useUploadFile = () => {
103
+ const dispatch = useDispatch();
104
+
105
+ const uploadFile = useCallback(
106
+ (file: UploadFile, parentId: string, path: string) => {
107
+ try {
108
+ return dispatch<any>({
109
+ type: 'fileManager/uploadFile',
110
+ payload: {
111
+ file,
112
+ parentId,
113
+ path,
114
+ },
115
+ });
116
+ } catch (errorInfo) {
117
+ console.log('Failed:', errorInfo);
118
+ }
119
+ },
120
+ [dispatch],
121
+ );
122
+
123
+ return uploadFile;
124
+ };
125
+
126
+ export const useConnectToKnowledge = () => {
127
+ const dispatch = useDispatch();
128
+
129
+ const uploadFile = useCallback(
130
+ (payload: IConnectRequestBody) => {
131
+ try {
132
+ return dispatch<any>({
133
+ type: 'fileManager/connectFileToKnowledge',
134
+ payload,
135
+ });
136
+ } catch (errorInfo) {
137
+ console.log('Failed:', errorInfo);
138
+ }
139
+ },
140
+ [dispatch],
141
+ );
142
+
143
+ return uploadFile;
144
+ };
web/src/interfaces/database/file-manager.ts CHANGED
@@ -3,7 +3,7 @@ export interface IFile {
3
  create_time: number;
4
  created_by: string;
5
  id: string;
6
- kb_ids: string[];
7
  location: string;
8
  name: string;
9
  parent_id: string;
 
3
  create_time: number;
4
  created_by: string;
5
  id: string;
6
+ kbs_info: { kb_id: string; kb_name: string }[];
7
  location: string;
8
  name: string;
9
  parent_id: string;
web/src/interfaces/request/file-manager.ts CHANGED
@@ -3,3 +3,12 @@ import { IPaginationRequestBody } from './base';
3
  export interface IFileListRequestBody extends IPaginationRequestBody {
4
  parent_id?: string; // folder id
5
  }
 
 
 
 
 
 
 
 
 
 
3
  export interface IFileListRequestBody extends IPaginationRequestBody {
4
  parent_id?: string; // folder id
5
  }
6
+
7
+ interface BaseRequestBody {
8
+ parentId: string;
9
+ }
10
+
11
+ export interface IConnectRequestBody extends BaseRequestBody {
12
+ fileIds: string[];
13
+ kbIds: string[];
14
+ }
web/src/locales/en.ts CHANGED
@@ -382,7 +382,7 @@ export default {
382
  passwordDescription:
383
  'Please enter your current password to change your password.',
384
  model: 'Model Providers',
385
- modelDescription: 'Manage your account settings and preferences here.',
386
  team: 'Team',
387
  logout: 'Log out',
388
  username: 'Username',
 
382
  passwordDescription:
383
  'Please enter your current password to change your password.',
384
  model: 'Model Providers',
385
+ modelDescription: 'Set the model parameter and API Key here.',
386
  team: 'Team',
387
  logout: 'Log out',
388
  username: 'Username',
web/src/locales/zh-traditional.ts CHANGED
@@ -352,7 +352,7 @@ export default {
352
  password: '密碼',
353
  passwordDescription: '請輸入您當前的密碼以更改您的密碼。',
354
  model: '模型提供商',
355
- modelDescription: '在此管理您的帳戶設置和首選項。',
356
  team: '團隊',
357
  logout: '登出',
358
  username: '使用者名稱',
 
352
  password: '密碼',
353
  passwordDescription: '請輸入您當前的密碼以更改您的密碼。',
354
  model: '模型提供商',
355
+ modelDescription: '在此設置模型參數和 API Key。',
356
  team: '團隊',
357
  logout: '登出',
358
  username: '使用者名稱',
web/src/locales/zh.ts CHANGED
@@ -369,7 +369,7 @@ export default {
369
  password: '密码',
370
  passwordDescription: '请输入您当前的密码以更改您的密码。',
371
  model: '模型提供商',
372
- modelDescription: '在此管理您的帐户设置和首选项。',
373
  team: '团队',
374
  logout: '登出',
375
  username: '用户名',
 
369
  password: '密码',
370
  passwordDescription: '请输入您当前的密码以更改您的密码。',
371
  model: '模型提供商',
372
+ modelDescription: '在此设置模型参数和 API Key。',
373
  team: '团队',
374
  logout: '登出',
375
  username: '用户名',
web/src/pages/file-manager/action-cell/index.tsx CHANGED
@@ -17,9 +17,15 @@ interface IProps {
17
  record: IFile;
18
  setCurrentRecord: (record: any) => void;
19
  showRenameModal: (record: IFile) => void;
 
20
  }
21
 
22
- const ActionCell = ({ record, setCurrentRecord, showRenameModal }: IProps) => {
 
 
 
 
 
23
  const documentId = record.id;
24
  const beingUsed = false;
25
  const { t } = useTranslate('knowledgeDetails');
@@ -41,9 +47,17 @@ const ActionCell = ({ record, setCurrentRecord, showRenameModal }: IProps) => {
41
  showRenameModal(record);
42
  };
43
 
 
 
 
 
44
  return (
45
  <Space size={0}>
46
- <Button type="text" className={styles.iconButton}>
 
 
 
 
47
  <ToolOutlined size={20} />
48
  </Button>
49
 
 
17
  record: IFile;
18
  setCurrentRecord: (record: any) => void;
19
  showRenameModal: (record: IFile) => void;
20
+ showConnectToKnowledgeModal: (ids: string[]) => void;
21
  }
22
 
23
+ const ActionCell = ({
24
+ record,
25
+ setCurrentRecord,
26
+ showRenameModal,
27
+ showConnectToKnowledgeModal,
28
+ }: IProps) => {
29
  const documentId = record.id;
30
  const beingUsed = false;
31
  const { t } = useTranslate('knowledgeDetails');
 
47
  showRenameModal(record);
48
  };
49
 
50
+ const onShowConnectToKnowledgeModal = () => {
51
+ showConnectToKnowledgeModal([documentId]);
52
+ };
53
+
54
  return (
55
  <Space size={0}>
56
+ <Button
57
+ type="text"
58
+ className={styles.iconButton}
59
+ onClick={onShowConnectToKnowledgeModal}
60
+ >
61
  <ToolOutlined size={20} />
62
  </Button>
63
 
web/src/pages/file-manager/connect-to-knowledge-modal/index.tsx ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { useFetchKnowledgeList } from '@/hooks/knowledgeHook';
2
+ import { IModalProps } from '@/interfaces/common';
3
+ import { Form, Modal, Select, SelectProps } from 'antd';
4
+
5
+ const ConnectToKnowledgeModal = ({
6
+ visible,
7
+ hideModal,
8
+ onOk,
9
+ }: IModalProps<string[]>) => {
10
+ const [form] = Form.useForm();
11
+ const { list } = useFetchKnowledgeList();
12
+
13
+ const options: SelectProps['options'] = list?.map((item) => ({
14
+ label: item.name,
15
+ value: item.id,
16
+ }));
17
+
18
+ const handleOk = async () => {
19
+ const values = await form.getFieldsValue();
20
+ const knowledgeIds = values.knowledgeIds ?? [];
21
+ if (knowledgeIds.length > 0) {
22
+ return onOk?.(knowledgeIds);
23
+ }
24
+ };
25
+
26
+ return (
27
+ <Modal
28
+ title="Add to Knowledge Base"
29
+ open={visible}
30
+ onOk={handleOk}
31
+ onCancel={hideModal}
32
+ >
33
+ <Form form={form}>
34
+ <Form.Item
35
+ name="knowledgeIds"
36
+ noStyle
37
+ rules={[
38
+ {
39
+ required: true,
40
+ message: 'Please select your favourite colors!',
41
+ type: 'array',
42
+ },
43
+ ]}
44
+ >
45
+ <Select
46
+ mode="multiple"
47
+ allowClear
48
+ style={{ width: '100%' }}
49
+ placeholder="Please select"
50
+ options={options}
51
+ />
52
+ </Form.Item>
53
+ </Form>
54
+ </Modal>
55
+ );
56
+ };
57
+
58
+ export default ConnectToKnowledgeModal;
web/src/pages/file-manager/file-toolbar.tsx CHANGED
@@ -32,6 +32,7 @@ import styles from './index.less';
32
  interface IProps {
33
  selectedRowKeys: string[];
34
  showFolderCreateModal: () => void;
 
35
  }
36
 
37
  const itemRender: BreadcrumbProps['itemRender'] = (
@@ -48,7 +49,11 @@ const itemRender: BreadcrumbProps['itemRender'] = (
48
  );
49
  };
50
 
51
- const FileToolbar = ({ selectedRowKeys, showFolderCreateModal }: IProps) => {
 
 
 
 
52
  const { t } = useTranslate('knowledgeDetails');
53
  const { fetchDocumentList } = useFetchDocumentListOnMount();
54
  const { setPagination, searchString } = useGetPagination(fetchDocumentList);
@@ -59,6 +64,7 @@ const FileToolbar = ({ selectedRowKeys, showFolderCreateModal }: IProps) => {
59
  return [
60
  {
61
  key: '1',
 
62
  label: (
63
  <div>
64
  <Button type="link">
@@ -85,7 +91,7 @@ const FileToolbar = ({ selectedRowKeys, showFolderCreateModal }: IProps) => {
85
  // disabled: true,
86
  },
87
  ];
88
- }, [t, showFolderCreateModal]);
89
 
90
  const { handleRemoveFile } = useHandleDeleteFile(selectedRowKeys);
91
 
 
32
  interface IProps {
33
  selectedRowKeys: string[];
34
  showFolderCreateModal: () => void;
35
+ showFileUploadModal: () => void;
36
  }
37
 
38
  const itemRender: BreadcrumbProps['itemRender'] = (
 
49
  );
50
  };
51
 
52
+ const FileToolbar = ({
53
+ selectedRowKeys,
54
+ showFolderCreateModal,
55
+ showFileUploadModal,
56
+ }: IProps) => {
57
  const { t } = useTranslate('knowledgeDetails');
58
  const { fetchDocumentList } = useFetchDocumentListOnMount();
59
  const { setPagination, searchString } = useGetPagination(fetchDocumentList);
 
64
  return [
65
  {
66
  key: '1',
67
+ onClick: showFileUploadModal,
68
  label: (
69
  <div>
70
  <Button type="link">
 
91
  // disabled: true,
92
  },
93
  ];
94
+ }, [t, showFolderCreateModal, showFileUploadModal]);
95
 
96
  const { handleRemoveFile } = useHandleDeleteFile(selectedRowKeys);
97
 
web/src/pages/file-manager/file-upload-modal/index.tsx CHANGED
@@ -1,61 +1,124 @@
 
1
  import { InboxOutlined } from '@ant-design/icons';
2
- import { Modal, Segmented, Upload, UploadProps, message } from 'antd';
3
- import { useState } from 'react';
 
 
 
 
 
 
 
 
 
 
4
 
5
  const { Dragger } = Upload;
6
 
7
- const FileUploadModal = () => {
8
- const [isModalOpen, setIsModalOpen] = useState(false);
9
-
 
 
 
 
 
 
10
  const props: UploadProps = {
11
- name: 'file',
12
  multiple: true,
13
- action: 'https://660d2bd96ddfa2943b33731c.mockapi.io/api/upload',
14
- onChange(info) {
15
- const { status } = info.file;
16
- if (status !== 'uploading') {
17
- console.log(info.file, info.fileList);
18
- }
19
- if (status === 'done') {
20
- message.success(`${info.file.name} file uploaded successfully.`);
21
- } else if (status === 'error') {
22
- message.error(`${info.file.name} file upload failed.`);
23
- }
24
  },
25
- onDrop(e) {
26
- console.log('Dropped files', e.dataTransfer.files);
 
 
 
 
27
  },
 
 
28
  };
29
 
30
- const handleOk = () => {
31
- setIsModalOpen(false);
32
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
34
- const handleCancel = () => {
35
- setIsModalOpen(false);
36
  };
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  return (
39
  <>
40
  <Modal
41
  title="File upload"
42
- open={isModalOpen}
43
- onOk={handleOk}
44
- onCancel={handleCancel}
 
45
  >
46
- <Segmented options={['Local uploads', 'S3 uploads']} block />
47
- <Dragger {...props}>
48
- <p className="ant-upload-drag-icon">
49
- <InboxOutlined />
50
- </p>
51
- <p className="ant-upload-text">
52
- Click or drag file to this area to upload
53
- </p>
54
- <p className="ant-upload-hint">
55
- Support for a single or bulk upload. Strictly prohibited from
56
- uploading company data or other banned files.
57
- </p>
58
- </Dragger>
 
 
 
59
  </Modal>
60
  </>
61
  );
 
1
+ import { IModalProps } from '@/interfaces/common';
2
  import { InboxOutlined } from '@ant-design/icons';
3
+ import {
4
+ Flex,
5
+ Modal,
6
+ Segmented,
7
+ Tabs,
8
+ TabsProps,
9
+ Upload,
10
+ UploadFile,
11
+ UploadProps,
12
+ } from 'antd';
13
+ import { Dispatch, SetStateAction, useState } from 'react';
14
+ import { useHandleUploadFile } from '../hooks';
15
 
16
  const { Dragger } = Upload;
17
 
18
+ const FileUpload = ({
19
+ directory,
20
+ fileList,
21
+ setFileList,
22
+ }: {
23
+ directory: boolean;
24
+ fileList: UploadFile[];
25
+ setFileList: Dispatch<SetStateAction<UploadFile[]>>;
26
+ }) => {
27
  const props: UploadProps = {
 
28
  multiple: true,
29
+ onRemove: (file) => {
30
+ const index = fileList.indexOf(file);
31
+ const newFileList = fileList.slice();
32
+ newFileList.splice(index, 1);
33
+ setFileList(newFileList);
 
 
 
 
 
 
34
  },
35
+ beforeUpload: (file) => {
36
+ setFileList((pre) => {
37
+ return [...pre, file];
38
+ });
39
+
40
+ return false;
41
  },
42
+ directory,
43
+ fileList,
44
  };
45
 
46
+ return (
47
+ <Dragger {...props}>
48
+ <p className="ant-upload-drag-icon">
49
+ <InboxOutlined />
50
+ </p>
51
+ <p className="ant-upload-text">
52
+ Click or drag file to this area to upload
53
+ </p>
54
+ <p className="ant-upload-hint">
55
+ Support for a single or bulk upload. Strictly prohibited from uploading
56
+ company data or other banned files.
57
+ </p>
58
+ </Dragger>
59
+ );
60
+ };
61
+
62
+ const FileUploadModal = ({ visible, hideModal }: IModalProps<any>) => {
63
+ const [value, setValue] = useState<string | number>('local');
64
+ const { onFileUploadOk, fileUploadLoading } = useHandleUploadFile();
65
+ const [fileList, setFileList] = useState<UploadFile[]>([]);
66
+ const [directoryFileList, setDirectoryFileList] = useState<UploadFile[]>([]);
67
 
68
+ const onOk = () => {
69
+ onFileUploadOk([...fileList, ...directoryFileList]);
70
  };
71
 
72
+ const items: TabsProps['items'] = [
73
+ {
74
+ key: '1',
75
+ label: 'File',
76
+ children: (
77
+ <FileUpload
78
+ directory={false}
79
+ fileList={fileList}
80
+ setFileList={setFileList}
81
+ ></FileUpload>
82
+ ),
83
+ },
84
+ {
85
+ key: '2',
86
+ label: 'Directory',
87
+ children: (
88
+ <FileUpload
89
+ directory
90
+ fileList={directoryFileList}
91
+ setFileList={setDirectoryFileList}
92
+ ></FileUpload>
93
+ ),
94
+ },
95
+ ];
96
+
97
  return (
98
  <>
99
  <Modal
100
  title="File upload"
101
+ open={visible}
102
+ onOk={onOk}
103
+ onCancel={hideModal}
104
+ confirmLoading={fileUploadLoading}
105
  >
106
+ <Flex gap={'large'} vertical>
107
+ <Segmented
108
+ options={[
109
+ { label: 'Local uploads', value: 'local' },
110
+ { label: 'S3 uploads', value: 's3' },
111
+ ]}
112
+ block
113
+ value={value}
114
+ onChange={setValue}
115
+ />
116
+ {value === 'local' ? (
117
+ <Tabs defaultActiveKey="1" items={items} />
118
+ ) : (
119
+ 'coming soon'
120
+ )}
121
+ </Flex>
122
  </Modal>
123
  </>
124
  );
web/src/pages/file-manager/hooks.ts CHANGED
@@ -4,6 +4,7 @@ import {
4
  useTranslate,
5
  } from '@/hooks/commonHooks';
6
  import {
 
7
  useCreateFolder,
8
  useFetchFileList,
9
  useFetchParentFolderList,
@@ -11,11 +12,14 @@ import {
11
  useRenameFile,
12
  useSelectFileList,
13
  useSelectParentFolderList,
 
14
  } from '@/hooks/fileManagerHooks';
15
  import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
16
  import { Pagination } from '@/interfaces/common';
17
  import { IFile } from '@/interfaces/database/file-manager';
 
18
  import { PaginationProps } from 'antd';
 
19
  import { useCallback, useEffect, useMemo, useState } from 'react';
20
  import { useDispatch, useNavigate, useSearchParams, useSelector } from 'umi';
21
 
@@ -250,3 +254,87 @@ export const useHandleDeleteFile = (fileIds: string[]) => {
250
  export const useSelectFileListLoading = () => {
251
  return useOneNamespaceEffectsLoading('fileManager', ['listFile']);
252
  };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  useTranslate,
5
  } from '@/hooks/commonHooks';
6
  import {
7
+ useConnectToKnowledge,
8
  useCreateFolder,
9
  useFetchFileList,
10
  useFetchParentFolderList,
 
12
  useRenameFile,
13
  useSelectFileList,
14
  useSelectParentFolderList,
15
+ useUploadFile,
16
  } from '@/hooks/fileManagerHooks';
17
  import { useOneNamespaceEffectsLoading } from '@/hooks/storeHooks';
18
  import { Pagination } from '@/interfaces/common';
19
  import { IFile } from '@/interfaces/database/file-manager';
20
+ import { getFilePathByWebkitRelativePath } from '@/utils/fileUtil';
21
  import { PaginationProps } from 'antd';
22
+ import { UploadFile } from 'antd/lib';
23
  import { useCallback, useEffect, useMemo, useState } from 'react';
24
  import { useDispatch, useNavigate, useSearchParams, useSelector } from 'umi';
25
 
 
254
  export const useSelectFileListLoading = () => {
255
  return useOneNamespaceEffectsLoading('fileManager', ['listFile']);
256
  };
257
+
258
+ export const useHandleUploadFile = () => {
259
+ const {
260
+ visible: fileUploadVisible,
261
+ hideModal: hideFileUploadModal,
262
+ showModal: showFileUploadModal,
263
+ } = useSetModalState();
264
+ const uploadFile = useUploadFile();
265
+ const id = useGetFolderId();
266
+
267
+ const onFileUploadOk = useCallback(
268
+ async (fileList: UploadFile[]) => {
269
+ console.info('fileList', fileList);
270
+ if (fileList.length > 0) {
271
+ const ret = await uploadFile(
272
+ fileList[0],
273
+ id,
274
+ getFilePathByWebkitRelativePath(fileList[0] as any),
275
+ );
276
+
277
+ if (ret === 0) {
278
+ hideFileUploadModal();
279
+ }
280
+ }
281
+ },
282
+ [uploadFile, hideFileUploadModal, id],
283
+ );
284
+
285
+ const loading = useOneNamespaceEffectsLoading('fileManager', ['uploadFile']);
286
+
287
+ return {
288
+ fileUploadLoading: loading,
289
+ onFileUploadOk,
290
+ fileUploadVisible,
291
+ hideFileUploadModal,
292
+ showFileUploadModal,
293
+ };
294
+ };
295
+
296
+ export const useHandleConnectToKnowledge = () => {
297
+ const {
298
+ visible: connectToKnowledgeVisible,
299
+ hideModal: hideConnectToKnowledgeModal,
300
+ showModal: showConnectToKnowledgeModal,
301
+ } = useSetModalState();
302
+ const connectToKnowledge = useConnectToKnowledge();
303
+ const id = useGetFolderId();
304
+ const [fileIds, setFileIds] = useState<string[]>([]);
305
+
306
+ const onConnectToKnowledgeOk = useCallback(
307
+ async (knowledgeIds: string[]) => {
308
+ const ret = await connectToKnowledge({
309
+ parentId: id,
310
+ fileIds,
311
+ kbIds: knowledgeIds,
312
+ });
313
+
314
+ if (ret === 0) {
315
+ hideConnectToKnowledgeModal();
316
+ }
317
+ },
318
+ [connectToKnowledge, hideConnectToKnowledgeModal, id, fileIds],
319
+ );
320
+
321
+ const loading = useOneNamespaceEffectsLoading('fileManager', [
322
+ 'connectFileToKnowledge',
323
+ ]);
324
+
325
+ const handleShowConnectToKnowledgeModal = useCallback(
326
+ (ids: string[]) => {
327
+ setFileIds(ids);
328
+ showConnectToKnowledgeModal();
329
+ },
330
+ [showConnectToKnowledgeModal],
331
+ );
332
+
333
+ return {
334
+ connectToKnowledgeLoading: loading,
335
+ onConnectToKnowledgeOk,
336
+ connectToKnowledgeVisible,
337
+ hideConnectToKnowledgeModal,
338
+ showConnectToKnowledgeModal: handleShowConnectToKnowledgeModal,
339
+ };
340
+ };
web/src/pages/file-manager/index.tsx CHANGED
@@ -7,13 +7,17 @@ import ActionCell from './action-cell';
7
  import FileToolbar from './file-toolbar';
8
  import {
9
  useGetRowSelection,
 
10
  useHandleCreateFolder,
 
11
  useNavigateToOtherFolder,
12
  useRenameCurrentFile,
13
  useSelectFileListLoading,
14
  } from './hooks';
15
 
16
  import RenameModal from '@/components/rename-modal';
 
 
17
  import FolderCreateModal from './folder-create-modal';
18
  import styles from './index.less';
19
 
@@ -37,6 +41,14 @@ const FileManager = () => {
37
  folderCreateLoading,
38
  onFolderCreateOk,
39
  } = useHandleCreateFolder();
 
 
 
 
 
 
 
 
40
 
41
  const columns: ColumnsType<IFile> = [
42
  {
@@ -64,6 +76,17 @@ const FileManager = () => {
64
  return formatDate(text);
65
  },
66
  },
 
 
 
 
 
 
 
 
 
 
 
67
  {
68
  title: 'Location',
69
  dataIndex: 'location',
@@ -80,6 +103,7 @@ const FileManager = () => {
80
  console.info(record);
81
  }}
82
  showRenameModal={showFileRenameModal}
 
83
  ></ActionCell>
84
  ),
85
  },
@@ -90,6 +114,7 @@ const FileManager = () => {
90
  <FileToolbar
91
  selectedRowKeys={rowSelection.selectedRowKeys as string[]}
92
  showFolderCreateModal={showFolderCreateModal}
 
93
  ></FileToolbar>
94
  <Table
95
  dataSource={fileList}
@@ -111,6 +136,15 @@ const FileManager = () => {
111
  hideModal={hideFolderCreateModal}
112
  onOk={onFolderCreateOk}
113
  ></FolderCreateModal>
 
 
 
 
 
 
 
 
 
114
  </section>
115
  );
116
  };
 
7
  import FileToolbar from './file-toolbar';
8
  import {
9
  useGetRowSelection,
10
+ useHandleConnectToKnowledge,
11
  useHandleCreateFolder,
12
+ useHandleUploadFile,
13
  useNavigateToOtherFolder,
14
  useRenameCurrentFile,
15
  useSelectFileListLoading,
16
  } from './hooks';
17
 
18
  import RenameModal from '@/components/rename-modal';
19
+ import ConnectToKnowledgeModal from './connect-to-knowledge-modal';
20
+ import FileUploadModal from './file-upload-modal';
21
  import FolderCreateModal from './folder-create-modal';
22
  import styles from './index.less';
23
 
 
41
  folderCreateLoading,
42
  onFolderCreateOk,
43
  } = useHandleCreateFolder();
44
+ const { fileUploadVisible, hideFileUploadModal, showFileUploadModal } =
45
+ useHandleUploadFile();
46
+ const {
47
+ connectToKnowledgeVisible,
48
+ hideConnectToKnowledgeModal,
49
+ showConnectToKnowledgeModal,
50
+ onConnectToKnowledgeOk,
51
+ } = useHandleConnectToKnowledge();
52
 
53
  const columns: ColumnsType<IFile> = [
54
  {
 
76
  return formatDate(text);
77
  },
78
  },
79
+ {
80
+ title: 'kbs_info',
81
+ dataIndex: 'kbs_info',
82
+ key: 'kbs_info',
83
+ render(value) {
84
+ console.info(value);
85
+ return Array.isArray(value)
86
+ ? value?.map((x) => x.kb_name).join(',')
87
+ : '';
88
+ },
89
+ },
90
  {
91
  title: 'Location',
92
  dataIndex: 'location',
 
103
  console.info(record);
104
  }}
105
  showRenameModal={showFileRenameModal}
106
+ showConnectToKnowledgeModal={showConnectToKnowledgeModal}
107
  ></ActionCell>
108
  ),
109
  },
 
114
  <FileToolbar
115
  selectedRowKeys={rowSelection.selectedRowKeys as string[]}
116
  showFolderCreateModal={showFolderCreateModal}
117
+ showFileUploadModal={showFileUploadModal}
118
  ></FileToolbar>
119
  <Table
120
  dataSource={fileList}
 
136
  hideModal={hideFolderCreateModal}
137
  onOk={onFolderCreateOk}
138
  ></FolderCreateModal>
139
+ <FileUploadModal
140
+ visible={fileUploadVisible}
141
+ hideModal={hideFileUploadModal}
142
+ ></FileUploadModal>
143
+ <ConnectToKnowledgeModal
144
+ visible={connectToKnowledgeVisible}
145
+ hideModal={hideConnectToKnowledgeModal}
146
+ onOk={onConnectToKnowledgeOk}
147
+ ></ConnectToKnowledgeModal>
148
  </section>
149
  );
150
  };
web/src/pages/file-manager/model.ts CHANGED
@@ -56,6 +56,20 @@ const model: DvaModel<FileManagerModelState> = {
56
  }
57
  return data.retcode;
58
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  *createFolder({ payload = {} }, { call, put }) {
60
  const { data } = yield call(fileManagerService.createFolder, payload);
61
  if (data.retcode === 0) {
@@ -79,6 +93,19 @@ const model: DvaModel<FileManagerModelState> = {
79
  }
80
  return data.retcode;
81
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
82
  },
83
  };
84
  export default model;
 
56
  }
57
  return data.retcode;
58
  },
59
+ *uploadFile({ payload = {} }, { call, put }) {
60
+ const formData = new FormData();
61
+ formData.append('parent_id', payload.parentId);
62
+ formData.append('file', payload.file);
63
+ formData.append('path', payload.path);
64
+ const { data } = yield call(fileManagerService.uploadFile, formData);
65
+ if (data.retcode === 0) {
66
+ yield put({
67
+ type: 'listFile',
68
+ payload: { parentId: payload.parentId },
69
+ });
70
+ }
71
+ return data.retcode;
72
+ },
73
  *createFolder({ payload = {} }, { call, put }) {
74
  const { data } = yield call(fileManagerService.createFolder, payload);
75
  if (data.retcode === 0) {
 
93
  }
94
  return data.retcode;
95
  },
96
+ *connectFileToKnowledge({ payload = {} }, { call, put }) {
97
+ const { data } = yield call(
98
+ fileManagerService.connectFileToKnowledge,
99
+ omit(payload, 'parentId'),
100
+ );
101
+ if (data.retcode === 0) {
102
+ yield put({
103
+ type: 'listFile',
104
+ payload: { parentId: payload.parentId },
105
+ });
106
+ }
107
+ return data.retcode;
108
+ },
109
  },
110
  };
111
  export default model;
web/src/pages/user-setting/setting-model/index.tsx CHANGED
@@ -228,7 +228,7 @@ const UserSettingModel = () => {
228
  <section className={styles.modelWrapper}>
229
  <SettingTitle
230
  title={t('model')}
231
- description={t('profileDescription')}
232
  showRightButton
233
  clickButton={showSystemSettingModal}
234
  ></SettingTitle>
 
228
  <section className={styles.modelWrapper}>
229
  <SettingTitle
230
  title={t('model')}
231
+ description={t('modelDescription')}
232
  showRightButton
233
  clickButton={showSystemSettingModal}
234
  ></SettingTitle>
web/src/services/fileManagerService.ts CHANGED
@@ -9,6 +9,7 @@ const {
9
  renameFile,
10
  getAllParentFolder,
11
  createFolder,
 
12
  } = api;
13
 
14
  const methods = {
@@ -36,6 +37,10 @@ const methods = {
36
  url: createFolder,
37
  method: 'post',
38
  },
 
 
 
 
39
  } as const;
40
 
41
  const fileManagerService = registerServer<keyof typeof methods>(
 
9
  renameFile,
10
  getAllParentFolder,
11
  createFolder,
12
+ connectFileToKnowledge,
13
  } = api;
14
 
15
  const methods = {
 
37
  url: createFolder,
38
  method: 'post',
39
  },
40
+ connectFileToKnowledge: {
41
+ url: connectFileToKnowledge,
42
+ method: 'post',
43
+ },
44
  } as const;
45
 
46
  const fileManagerService = registerServer<keyof typeof methods>(
web/src/utils/api.ts CHANGED
@@ -74,4 +74,5 @@ export default {
74
  renameFile: `${api_host}/file/rename`,
75
  getAllParentFolder: `${api_host}/file/all_parent_folder`,
76
  createFolder: `${api_host}/file/create`,
 
77
  };
 
74
  renameFile: `${api_host}/file/rename`,
75
  getAllParentFolder: `${api_host}/file/all_parent_folder`,
76
  createFolder: `${api_host}/file/create`,
77
+ connectFileToKnowledge: `${api_host}/file2document/convert`,
78
  };
web/src/utils/fileUtil.ts CHANGED
@@ -85,3 +85,12 @@ export const downloadFile = ({
85
  downloadElement.click();
86
  document.body.removeChild(downloadElement);
87
  };
 
 
 
 
 
 
 
 
 
 
85
  downloadElement.click();
86
  document.body.removeChild(downloadElement);
87
  };
88
+
89
+ export const getFilePathByWebkitRelativePath = (file: File) => {
90
+ const path = file.webkitRelativePath;
91
+ return path;
92
+ // if (path !== '') {
93
+ // return path.slice(0, path.lastIndexOf('/'));
94
+ // }
95
+ // return path;
96
+ };