balibabu
commited on
Commit
·
ba91369
1
Parent(s):
0a4eab6
feat: Move files in file manager #1826 (#1837)
Browse files### What problem does this PR solve?
feat: Move files in file manager #1826
### Type of change
- [x] New Feature (non-breaking change which adds functionality)
- web/src/assets/svg/move.svg +6 -0
- web/src/hooks/file-manager-hooks.ts +45 -0
- web/src/locales/en.ts +2 -0
- web/src/locales/zh-traditional.ts +2 -0
- web/src/locales/zh.ts +2 -0
- web/src/pages/file-manager/action-cell/index.tsx +24 -6
- web/src/pages/file-manager/file-toolbar.tsx +21 -2
- web/src/pages/file-manager/folder-create-modal/index.tsx +1 -15
- web/src/pages/file-manager/hooks.ts +46 -0
- web/src/pages/file-manager/index.tsx +19 -1
- web/src/pages/file-manager/move-file-modal/async-tree-select.tsx +64 -0
- web/src/pages/file-manager/move-file-modal/index.tsx +54 -0
- web/src/services/file-manager-service.ts +5 -0
- web/src/utils/api.ts +1 -0
web/src/assets/svg/move.svg
ADDED
|
web/src/hooks/file-manager-hooks.ts
CHANGED
@@ -28,6 +28,23 @@ export interface IListResult {
|
|
28 |
loading: boolean;
|
29 |
}
|
30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
export const useFetchFileList = (): ResponseType<any> & IListResult => {
|
32 |
const { searchString, handleInputChange } = useHandleSearchChange();
|
33 |
const { pagination, setPagination } = useGetPaginationWithRouter();
|
@@ -225,3 +242,31 @@ export const useConnectToKnowledge = () => {
|
|
225 |
|
226 |
return { data, loading, connectFileToKnowledge: mutateAsync };
|
227 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
loading: boolean;
|
29 |
}
|
30 |
|
31 |
+
export const useFetchPureFileList = () => {
|
32 |
+
const { mutateAsync, isPending: loading } = useMutation({
|
33 |
+
mutationKey: ['fetchPureFileList'],
|
34 |
+
gcTime: 0,
|
35 |
+
|
36 |
+
mutationFn: async (parentId: string) => {
|
37 |
+
const { data } = await fileManagerService.listFile({
|
38 |
+
parent_id: parentId,
|
39 |
+
});
|
40 |
+
|
41 |
+
return data;
|
42 |
+
},
|
43 |
+
});
|
44 |
+
|
45 |
+
return { loading, fetchList: mutateAsync };
|
46 |
+
};
|
47 |
+
|
48 |
export const useFetchFileList = (): ResponseType<any> & IListResult => {
|
49 |
const { searchString, handleInputChange } = useHandleSearchChange();
|
50 |
const { pagination, setPagination } = useGetPaginationWithRouter();
|
|
|
242 |
|
243 |
return { data, loading, connectFileToKnowledge: mutateAsync };
|
244 |
};
|
245 |
+
|
246 |
+
export interface IMoveFileBody {
|
247 |
+
src_file_ids: string[];
|
248 |
+
dest_file_id: string; // target folder id
|
249 |
+
}
|
250 |
+
|
251 |
+
export const useMoveFile = () => {
|
252 |
+
const queryClient = useQueryClient();
|
253 |
+
const { t } = useTranslation();
|
254 |
+
|
255 |
+
const {
|
256 |
+
data,
|
257 |
+
isPending: loading,
|
258 |
+
mutateAsync,
|
259 |
+
} = useMutation({
|
260 |
+
mutationKey: ['moveFile'],
|
261 |
+
mutationFn: async (params: IMoveFileBody) => {
|
262 |
+
const { data } = await fileManagerService.moveFile(params);
|
263 |
+
if (data.retcode === 0) {
|
264 |
+
message.success(t('message.operated'));
|
265 |
+
queryClient.invalidateQueries({ queryKey: ['fetchFileList'] });
|
266 |
+
}
|
267 |
+
return data.retcode;
|
268 |
+
},
|
269 |
+
});
|
270 |
+
|
271 |
+
return { data, loading, moveFile: mutateAsync };
|
272 |
+
};
|
web/src/locales/en.ts
CHANGED
@@ -26,6 +26,7 @@ export default {
|
|
26 |
download: 'Download',
|
27 |
close: 'Close',
|
28 |
preview: 'Preview',
|
|
|
29 |
},
|
30 |
login: {
|
31 |
login: 'Sign in',
|
@@ -564,6 +565,7 @@ The above is the content you need to summarize.`,
|
|
564 |
fileError: 'File error',
|
565 |
uploadLimit:
|
566 |
'The file size cannot exceed 10M, and the total number of files cannot exceed 128',
|
|
|
567 |
},
|
568 |
flow: {
|
569 |
cite: 'Cite',
|
|
|
26 |
download: 'Download',
|
27 |
close: 'Close',
|
28 |
preview: 'Preview',
|
29 |
+
move: 'Move',
|
30 |
},
|
31 |
login: {
|
32 |
login: 'Sign in',
|
|
|
565 |
fileError: 'File error',
|
566 |
uploadLimit:
|
567 |
'The file size cannot exceed 10M, and the total number of files cannot exceed 128',
|
568 |
+
destinationFolder: 'Destination folder',
|
569 |
},
|
570 |
flow: {
|
571 |
cite: 'Cite',
|
web/src/locales/zh-traditional.ts
CHANGED
@@ -26,6 +26,7 @@ export default {
|
|
26 |
download: '下載',
|
27 |
close: '關閉',
|
28 |
preview: '預覽',
|
|
|
29 |
},
|
30 |
login: {
|
31 |
login: '登入',
|
@@ -524,6 +525,7 @@ export default {
|
|
524 |
preview: '預覽',
|
525 |
fileError: '文件錯誤',
|
526 |
uploadLimit: '文件大小不能超過10M,文件總數不超過128個',
|
|
|
527 |
},
|
528 |
flow: {
|
529 |
cite: '引用',
|
|
|
26 |
download: '下載',
|
27 |
close: '關閉',
|
28 |
preview: '預覽',
|
29 |
+
move: '移動',
|
30 |
},
|
31 |
login: {
|
32 |
login: '登入',
|
|
|
525 |
preview: '預覽',
|
526 |
fileError: '文件錯誤',
|
527 |
uploadLimit: '文件大小不能超過10M,文件總數不超過128個',
|
528 |
+
destinationFolder: '目標資料夾',
|
529 |
},
|
530 |
flow: {
|
531 |
cite: '引用',
|
web/src/locales/zh.ts
CHANGED
@@ -26,6 +26,7 @@ export default {
|
|
26 |
download: '下载',
|
27 |
close: '关闭',
|
28 |
preview: '预览',
|
|
|
29 |
},
|
30 |
login: {
|
31 |
login: '登录',
|
@@ -542,6 +543,7 @@ export default {
|
|
542 |
preview: '预览',
|
543 |
fileError: '文件错误',
|
544 |
uploadLimit: '文件大小不能超过10M,文件总数不超过128个',
|
|
|
545 |
},
|
546 |
flow: {
|
547 |
flow: '工作流',
|
|
|
26 |
download: '下载',
|
27 |
close: '关闭',
|
28 |
preview: '预览',
|
29 |
+
move: '移动',
|
30 |
},
|
31 |
login: {
|
32 |
login: '登录',
|
|
|
543 |
preview: '预览',
|
544 |
fileError: '文件错误',
|
545 |
uploadLimit: '文件大小不能超过10M,文件总数不超过128个',
|
546 |
+
destinationFolder: '目标文件夹',
|
547 |
},
|
548 |
flow: {
|
549 |
flow: '工作流',
|
web/src/pages/file-manager/action-cell/index.tsx
CHANGED
@@ -1,6 +1,12 @@
|
|
|
|
|
|
1 |
import { useTranslate } from '@/hooks/common-hooks';
|
2 |
import { IFile } from '@/interfaces/database/file-manager';
|
3 |
import { api_host } from '@/utils/api';
|
|
|
|
|
|
|
|
|
4 |
import { downloadFile } from '@/utils/file-util';
|
5 |
import {
|
6 |
DeleteOutlined,
|
@@ -11,18 +17,13 @@ import {
|
|
11 |
} from '@ant-design/icons';
|
12 |
import { Button, Space, Tooltip } from 'antd';
|
13 |
import { useHandleDeleteFile } from '../hooks';
|
14 |
-
|
15 |
-
import NewDocumentLink from '@/components/new-document-link';
|
16 |
-
import {
|
17 |
-
getExtension,
|
18 |
-
isSupportedPreviewDocumentType,
|
19 |
-
} from '@/utils/document-util';
|
20 |
import styles from './index.less';
|
21 |
|
22 |
interface IProps {
|
23 |
record: IFile;
|
24 |
setCurrentRecord: (record: any) => void;
|
25 |
showRenameModal: (record: IFile) => void;
|
|
|
26 |
showConnectToKnowledgeModal: (record: IFile) => void;
|
27 |
setSelectedRowKeys(keys: string[]): void;
|
28 |
}
|
@@ -33,6 +34,7 @@ const ActionCell = ({
|
|
33 |
showRenameModal,
|
34 |
showConnectToKnowledgeModal,
|
35 |
setSelectedRowKeys,
|
|
|
36 |
}: IProps) => {
|
37 |
const documentId = record.id;
|
38 |
const beingUsed = false;
|
@@ -64,6 +66,10 @@ const ActionCell = ({
|
|
64 |
showConnectToKnowledgeModal(record);
|
65 |
};
|
66 |
|
|
|
|
|
|
|
|
|
67 |
return (
|
68 |
<Space size={0}>
|
69 |
{isKnowledgeBase || (
|
@@ -90,6 +96,18 @@ const ActionCell = ({
|
|
90 |
</Button>
|
91 |
</Tooltip>
|
92 |
)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
{isKnowledgeBase || (
|
94 |
<Tooltip title={t('delete', { keyPrefix: 'common' })}>
|
95 |
<Button
|
|
|
1 |
+
import NewDocumentLink from '@/components/new-document-link';
|
2 |
+
import SvgIcon from '@/components/svg-icon';
|
3 |
import { useTranslate } from '@/hooks/common-hooks';
|
4 |
import { IFile } from '@/interfaces/database/file-manager';
|
5 |
import { api_host } from '@/utils/api';
|
6 |
+
import {
|
7 |
+
getExtension,
|
8 |
+
isSupportedPreviewDocumentType,
|
9 |
+
} from '@/utils/document-util';
|
10 |
import { downloadFile } from '@/utils/file-util';
|
11 |
import {
|
12 |
DeleteOutlined,
|
|
|
17 |
} from '@ant-design/icons';
|
18 |
import { Button, Space, Tooltip } from 'antd';
|
19 |
import { useHandleDeleteFile } from '../hooks';
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
import styles from './index.less';
|
21 |
|
22 |
interface IProps {
|
23 |
record: IFile;
|
24 |
setCurrentRecord: (record: any) => void;
|
25 |
showRenameModal: (record: IFile) => void;
|
26 |
+
showMoveFileModal: (ids: string[]) => void;
|
27 |
showConnectToKnowledgeModal: (record: IFile) => void;
|
28 |
setSelectedRowKeys(keys: string[]): void;
|
29 |
}
|
|
|
34 |
showRenameModal,
|
35 |
showConnectToKnowledgeModal,
|
36 |
setSelectedRowKeys,
|
37 |
+
showMoveFileModal,
|
38 |
}: IProps) => {
|
39 |
const documentId = record.id;
|
40 |
const beingUsed = false;
|
|
|
66 |
showConnectToKnowledgeModal(record);
|
67 |
};
|
68 |
|
69 |
+
const onShowMoveFileModal = () => {
|
70 |
+
showMoveFileModal([documentId]);
|
71 |
+
};
|
72 |
+
|
73 |
return (
|
74 |
<Space size={0}>
|
75 |
{isKnowledgeBase || (
|
|
|
96 |
</Button>
|
97 |
</Tooltip>
|
98 |
)}
|
99 |
+
{isKnowledgeBase || (
|
100 |
+
<Tooltip title={t('move', { keyPrefix: 'common' })}>
|
101 |
+
<Button
|
102 |
+
type="text"
|
103 |
+
disabled={beingUsed}
|
104 |
+
onClick={onShowMoveFileModal}
|
105 |
+
className={styles.iconButton}
|
106 |
+
>
|
107 |
+
<SvgIcon name={`move`} width={16}></SvgIcon>
|
108 |
+
</Button>
|
109 |
+
</Tooltip>
|
110 |
+
)}
|
111 |
{isKnowledgeBase || (
|
112 |
<Tooltip title={t('delete', { keyPrefix: 'common' })}>
|
113 |
<Button
|
web/src/pages/file-manager/file-toolbar.tsx
CHANGED
@@ -17,13 +17,14 @@ import {
|
|
17 |
MenuProps,
|
18 |
Space,
|
19 |
} from 'antd';
|
20 |
-
import { useMemo } from 'react';
|
21 |
import {
|
22 |
useHandleBreadcrumbClick,
|
23 |
useHandleDeleteFile,
|
24 |
useSelectBreadcrumbItems,
|
25 |
} from './hooks';
|
26 |
|
|
|
27 |
import {
|
28 |
IListResult,
|
29 |
useFetchParentFolderList,
|
@@ -36,6 +37,7 @@ interface IProps
|
|
36 |
showFolderCreateModal: () => void;
|
37 |
showFileUploadModal: () => void;
|
38 |
setSelectedRowKeys: (keys: string[]) => void;
|
|
|
39 |
}
|
40 |
|
41 |
const FileToolbar = ({
|
@@ -45,6 +47,7 @@ const FileToolbar = ({
|
|
45 |
setSelectedRowKeys,
|
46 |
searchString,
|
47 |
handleInputChange,
|
|
|
48 |
}: IProps) => {
|
49 |
const { t } = useTranslate('knowledgeDetails');
|
50 |
const breadcrumbItems = useSelectBreadcrumbItems();
|
@@ -111,6 +114,10 @@ const FileToolbar = ({
|
|
111 |
setSelectedRowKeys,
|
112 |
);
|
113 |
|
|
|
|
|
|
|
|
|
114 |
const disabled = selectedRowKeys.length === 0;
|
115 |
|
116 |
const items: MenuProps['items'] = useMemo(() => {
|
@@ -127,8 +134,20 @@ const FileToolbar = ({
|
|
127 |
</Flex>
|
128 |
),
|
129 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
130 |
];
|
131 |
-
}, [
|
132 |
|
133 |
return (
|
134 |
<div className={styles.filter}>
|
|
|
17 |
MenuProps,
|
18 |
Space,
|
19 |
} from 'antd';
|
20 |
+
import { useCallback, useMemo } from 'react';
|
21 |
import {
|
22 |
useHandleBreadcrumbClick,
|
23 |
useHandleDeleteFile,
|
24 |
useSelectBreadcrumbItems,
|
25 |
} from './hooks';
|
26 |
|
27 |
+
import SvgIcon from '@/components/svg-icon';
|
28 |
import {
|
29 |
IListResult,
|
30 |
useFetchParentFolderList,
|
|
|
37 |
showFolderCreateModal: () => void;
|
38 |
showFileUploadModal: () => void;
|
39 |
setSelectedRowKeys: (keys: string[]) => void;
|
40 |
+
showMoveFileModal: (ids: string[]) => void;
|
41 |
}
|
42 |
|
43 |
const FileToolbar = ({
|
|
|
47 |
setSelectedRowKeys,
|
48 |
searchString,
|
49 |
handleInputChange,
|
50 |
+
showMoveFileModal,
|
51 |
}: IProps) => {
|
52 |
const { t } = useTranslate('knowledgeDetails');
|
53 |
const breadcrumbItems = useSelectBreadcrumbItems();
|
|
|
114 |
setSelectedRowKeys,
|
115 |
);
|
116 |
|
117 |
+
const handleShowMoveFileModal = useCallback(() => {
|
118 |
+
showMoveFileModal(selectedRowKeys);
|
119 |
+
}, [selectedRowKeys, showMoveFileModal]);
|
120 |
+
|
121 |
const disabled = selectedRowKeys.length === 0;
|
122 |
|
123 |
const items: MenuProps['items'] = useMemo(() => {
|
|
|
134 |
</Flex>
|
135 |
),
|
136 |
},
|
137 |
+
{
|
138 |
+
key: '5',
|
139 |
+
onClick: handleShowMoveFileModal,
|
140 |
+
label: (
|
141 |
+
<Flex gap={10}>
|
142 |
+
<span className={styles.deleteIconWrapper}>
|
143 |
+
<SvgIcon name={`move`} width={18}></SvgIcon>
|
144 |
+
</span>
|
145 |
+
<b>{t('move', { keyPrefix: 'common' })}</b>
|
146 |
+
</Flex>
|
147 |
+
),
|
148 |
+
},
|
149 |
];
|
150 |
+
}, [handleShowMoveFileModal, t, handleRemoveFile]);
|
151 |
|
152 |
return (
|
153 |
<div className={styles.filter}>
|
web/src/pages/file-manager/folder-create-modal/index.tsx
CHANGED
@@ -21,24 +21,12 @@ const FolderCreateModal = ({ visible, hideModal, loading, onOk }: IProps) => {
|
|
21 |
return onOk(ret.name);
|
22 |
};
|
23 |
|
24 |
-
const handleCancel = () => {
|
25 |
-
hideModal();
|
26 |
-
};
|
27 |
-
|
28 |
-
const onFinish = (values: any) => {
|
29 |
-
console.log('Success:', values);
|
30 |
-
};
|
31 |
-
|
32 |
-
const onFinishFailed = (errorInfo: any) => {
|
33 |
-
console.log('Failed:', errorInfo);
|
34 |
-
};
|
35 |
-
|
36 |
return (
|
37 |
<Modal
|
38 |
title={t('newFolder', { keyPrefix: 'fileManager' })}
|
39 |
open={visible}
|
40 |
onOk={handleOk}
|
41 |
-
onCancel={
|
42 |
okButtonProps={{ loading }}
|
43 |
confirmLoading={loading}
|
44 |
>
|
@@ -47,8 +35,6 @@ const FolderCreateModal = ({ visible, hideModal, loading, onOk }: IProps) => {
|
|
47 |
labelCol={{ span: 4 }}
|
48 |
wrapperCol={{ span: 20 }}
|
49 |
style={{ maxWidth: 600 }}
|
50 |
-
onFinish={onFinish}
|
51 |
-
onFinishFailed={onFinishFailed}
|
52 |
autoComplete="off"
|
53 |
form={form}
|
54 |
>
|
|
|
21 |
return onOk(ret.name);
|
22 |
};
|
23 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
return (
|
25 |
<Modal
|
26 |
title={t('newFolder', { keyPrefix: 'fileManager' })}
|
27 |
open={visible}
|
28 |
onOk={handleOk}
|
29 |
+
onCancel={hideModal}
|
30 |
okButtonProps={{ loading }}
|
31 |
confirmLoading={loading}
|
32 |
>
|
|
|
35 |
labelCol={{ span: 4 }}
|
36 |
wrapperCol={{ span: 20 }}
|
37 |
style={{ maxWidth: 600 }}
|
|
|
|
|
38 |
autoComplete="off"
|
39 |
form={form}
|
40 |
>
|
web/src/pages/file-manager/hooks.ts
CHANGED
@@ -4,6 +4,7 @@ import {
|
|
4 |
useCreateFolder,
|
5 |
useDeleteFile,
|
6 |
useFetchParentFolderList,
|
|
|
7 |
useRenameFile,
|
8 |
useUploadFile,
|
9 |
} from '@/hooks/file-manager-hooks';
|
@@ -246,3 +247,48 @@ export const useHandleBreadcrumbClick = () => {
|
|
246 |
|
247 |
return { handleBreadcrumbClick };
|
248 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
useCreateFolder,
|
5 |
useDeleteFile,
|
6 |
useFetchParentFolderList,
|
7 |
+
useMoveFile,
|
8 |
useRenameFile,
|
9 |
useUploadFile,
|
10 |
} from '@/hooks/file-manager-hooks';
|
|
|
247 |
|
248 |
return { handleBreadcrumbClick };
|
249 |
};
|
250 |
+
|
251 |
+
export const useHandleMoveFile = (
|
252 |
+
setSelectedRowKeys: (keys: string[]) => void,
|
253 |
+
) => {
|
254 |
+
const {
|
255 |
+
visible: moveFileVisible,
|
256 |
+
hideModal: hideMoveFileModal,
|
257 |
+
showModal: showMoveFileModal,
|
258 |
+
} = useSetModalState();
|
259 |
+
const { moveFile, loading } = useMoveFile();
|
260 |
+
const [sourceFileIds, setSourceFileIds] = useState<string[]>([]);
|
261 |
+
|
262 |
+
const onMoveFileOk = useCallback(
|
263 |
+
async (targetFolderId: string) => {
|
264 |
+
const ret = await moveFile({
|
265 |
+
src_file_ids: sourceFileIds,
|
266 |
+
dest_file_id: targetFolderId,
|
267 |
+
});
|
268 |
+
|
269 |
+
if (ret === 0) {
|
270 |
+
setSelectedRowKeys([]);
|
271 |
+
hideMoveFileModal();
|
272 |
+
}
|
273 |
+
return ret;
|
274 |
+
},
|
275 |
+
[moveFile, hideMoveFileModal, sourceFileIds, setSelectedRowKeys],
|
276 |
+
);
|
277 |
+
|
278 |
+
const handleShowMoveFileModal = useCallback(
|
279 |
+
(ids: string[]) => {
|
280 |
+
setSourceFileIds(ids);
|
281 |
+
showMoveFileModal();
|
282 |
+
},
|
283 |
+
[showMoveFileModal],
|
284 |
+
);
|
285 |
+
|
286 |
+
return {
|
287 |
+
initialValue: '',
|
288 |
+
moveFileLoading: loading,
|
289 |
+
onMoveFileOk,
|
290 |
+
moveFileVisible,
|
291 |
+
hideMoveFileModal,
|
292 |
+
showMoveFileModal: handleShowMoveFileModal,
|
293 |
+
};
|
294 |
+
};
|
web/src/pages/file-manager/index.tsx
CHANGED
@@ -9,6 +9,7 @@ import {
|
|
9 |
useGetRowSelection,
|
10 |
useHandleConnectToKnowledge,
|
11 |
useHandleCreateFolder,
|
|
|
12 |
useHandleUploadFile,
|
13 |
useNavigateToOtherFolder,
|
14 |
useRenameCurrentFile,
|
@@ -23,6 +24,7 @@ import { getExtension } from '@/utils/document-util';
|
|
23 |
import ConnectToKnowledgeModal from './connect-to-knowledge-modal';
|
24 |
import FolderCreateModal from './folder-create-modal';
|
25 |
import styles from './index.less';
|
|
|
26 |
|
27 |
const { Text } = Typography;
|
28 |
|
@@ -61,7 +63,13 @@ const FileManager = () => {
|
|
61 |
initialValue,
|
62 |
connectToKnowledgeLoading,
|
63 |
} = useHandleConnectToKnowledge();
|
64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
const { pagination, data, searchString, handleInputChange, loading } =
|
66 |
useFetchFileList();
|
67 |
const columns: ColumnsType<IFile> = [
|
@@ -139,6 +147,7 @@ const FileManager = () => {
|
|
139 |
console.info(record);
|
140 |
}}
|
141 |
showRenameModal={showFileRenameModal}
|
|
|
142 |
showConnectToKnowledgeModal={showConnectToKnowledgeModal}
|
143 |
setSelectedRowKeys={setSelectedRowKeys}
|
144 |
></ActionCell>
|
@@ -155,6 +164,7 @@ const FileManager = () => {
|
|
155 |
showFolderCreateModal={showFolderCreateModal}
|
156 |
showFileUploadModal={showFileUploadModal}
|
157 |
setSelectedRowKeys={setSelectedRowKeys}
|
|
|
158 |
></FileToolbar>
|
159 |
<Table
|
160 |
dataSource={data?.files}
|
@@ -191,6 +201,14 @@ const FileManager = () => {
|
|
191 |
onOk={onConnectToKnowledgeOk}
|
192 |
loading={connectToKnowledgeLoading}
|
193 |
></ConnectToKnowledgeModal>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
194 |
</section>
|
195 |
);
|
196 |
};
|
|
|
9 |
useGetRowSelection,
|
10 |
useHandleConnectToKnowledge,
|
11 |
useHandleCreateFolder,
|
12 |
+
useHandleMoveFile,
|
13 |
useHandleUploadFile,
|
14 |
useNavigateToOtherFolder,
|
15 |
useRenameCurrentFile,
|
|
|
24 |
import ConnectToKnowledgeModal from './connect-to-knowledge-modal';
|
25 |
import FolderCreateModal from './folder-create-modal';
|
26 |
import styles from './index.less';
|
27 |
+
import FileMovingModal from './move-file-modal';
|
28 |
|
29 |
const { Text } = Typography;
|
30 |
|
|
|
63 |
initialValue,
|
64 |
connectToKnowledgeLoading,
|
65 |
} = useHandleConnectToKnowledge();
|
66 |
+
const {
|
67 |
+
showMoveFileModal,
|
68 |
+
moveFileVisible,
|
69 |
+
onMoveFileOk,
|
70 |
+
hideMoveFileModal,
|
71 |
+
moveFileLoading,
|
72 |
+
} = useHandleMoveFile(setSelectedRowKeys);
|
73 |
const { pagination, data, searchString, handleInputChange, loading } =
|
74 |
useFetchFileList();
|
75 |
const columns: ColumnsType<IFile> = [
|
|
|
147 |
console.info(record);
|
148 |
}}
|
149 |
showRenameModal={showFileRenameModal}
|
150 |
+
showMoveFileModal={showMoveFileModal}
|
151 |
showConnectToKnowledgeModal={showConnectToKnowledgeModal}
|
152 |
setSelectedRowKeys={setSelectedRowKeys}
|
153 |
></ActionCell>
|
|
|
164 |
showFolderCreateModal={showFolderCreateModal}
|
165 |
showFileUploadModal={showFileUploadModal}
|
166 |
setSelectedRowKeys={setSelectedRowKeys}
|
167 |
+
showMoveFileModal={showMoveFileModal}
|
168 |
></FileToolbar>
|
169 |
<Table
|
170 |
dataSource={data?.files}
|
|
|
201 |
onOk={onConnectToKnowledgeOk}
|
202 |
loading={connectToKnowledgeLoading}
|
203 |
></ConnectToKnowledgeModal>
|
204 |
+
{moveFileVisible && (
|
205 |
+
<FileMovingModal
|
206 |
+
visible={moveFileVisible}
|
207 |
+
hideModal={hideMoveFileModal}
|
208 |
+
onOk={onMoveFileOk}
|
209 |
+
loading={moveFileLoading}
|
210 |
+
></FileMovingModal>
|
211 |
+
)}
|
212 |
</section>
|
213 |
);
|
214 |
};
|
web/src/pages/file-manager/move-file-modal/async-tree-select.tsx
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { useFetchPureFileList } from '@/hooks/file-manager-hooks';
|
2 |
+
import { IFile } from '@/interfaces/database/file-manager';
|
3 |
+
import type { GetProp, TreeSelectProps } from 'antd';
|
4 |
+
import { TreeSelect } from 'antd';
|
5 |
+
import { useCallback, useEffect, useState } from 'react';
|
6 |
+
|
7 |
+
type DefaultOptionType = GetProp<TreeSelectProps, 'treeData'>[number];
|
8 |
+
|
9 |
+
interface IProps {
|
10 |
+
value?: string;
|
11 |
+
onChange?: (value: string) => void;
|
12 |
+
}
|
13 |
+
|
14 |
+
const AsyncTreeSelect = ({ value, onChange }: IProps) => {
|
15 |
+
const { fetchList } = useFetchPureFileList();
|
16 |
+
const [treeData, setTreeData] = useState<Omit<DefaultOptionType, 'label'>[]>(
|
17 |
+
[],
|
18 |
+
);
|
19 |
+
|
20 |
+
const onLoadData: TreeSelectProps['loadData'] = useCallback(
|
21 |
+
async ({ id }) => {
|
22 |
+
const ret = await fetchList(id);
|
23 |
+
if (ret.retcode === 0) {
|
24 |
+
setTreeData((tree) => {
|
25 |
+
return tree.concat(
|
26 |
+
ret.data.files
|
27 |
+
.filter((x: IFile) => x.type === 'folder')
|
28 |
+
.map((x: IFile) => ({
|
29 |
+
id: x.id,
|
30 |
+
pId: x.parent_id,
|
31 |
+
value: x.id,
|
32 |
+
title: x.name,
|
33 |
+
isLeaf: false,
|
34 |
+
})),
|
35 |
+
);
|
36 |
+
});
|
37 |
+
}
|
38 |
+
},
|
39 |
+
[fetchList],
|
40 |
+
);
|
41 |
+
|
42 |
+
const handleChange = (newValue: string) => {
|
43 |
+
onChange?.(newValue);
|
44 |
+
};
|
45 |
+
|
46 |
+
useEffect(() => {
|
47 |
+
onLoadData?.({ id: '', props: '' });
|
48 |
+
}, [onLoadData]);
|
49 |
+
|
50 |
+
return (
|
51 |
+
<TreeSelect
|
52 |
+
treeDataSimpleMode
|
53 |
+
style={{ width: '100%' }}
|
54 |
+
value={value}
|
55 |
+
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
|
56 |
+
placeholder="Please select"
|
57 |
+
onChange={handleChange}
|
58 |
+
loadData={onLoadData}
|
59 |
+
treeData={treeData}
|
60 |
+
/>
|
61 |
+
);
|
62 |
+
};
|
63 |
+
|
64 |
+
export default AsyncTreeSelect;
|
web/src/pages/file-manager/move-file-modal/index.tsx
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { IModalManagerChildrenProps } from '@/components/modal-manager';
|
2 |
+
import { useTranslate } from '@/hooks/common-hooks';
|
3 |
+
import { Form, Modal } from 'antd';
|
4 |
+
import AsyncTreeSelect from './async-tree-select';
|
5 |
+
|
6 |
+
interface IProps extends Omit<IModalManagerChildrenProps, 'showModal'> {
|
7 |
+
loading: boolean;
|
8 |
+
onOk: (id: string) => void;
|
9 |
+
}
|
10 |
+
|
11 |
+
const FileMovingModal = ({ visible, hideModal, loading, onOk }: IProps) => {
|
12 |
+
const [form] = Form.useForm();
|
13 |
+
const { t } = useTranslate('fileManager');
|
14 |
+
|
15 |
+
type FieldType = {
|
16 |
+
name?: string;
|
17 |
+
};
|
18 |
+
|
19 |
+
const handleOk = async () => {
|
20 |
+
const ret = await form.validateFields();
|
21 |
+
|
22 |
+
return onOk(ret.name);
|
23 |
+
};
|
24 |
+
|
25 |
+
return (
|
26 |
+
<Modal
|
27 |
+
title={t('move', { keyPrefix: 'common' })}
|
28 |
+
open={visible}
|
29 |
+
onOk={handleOk}
|
30 |
+
onCancel={hideModal}
|
31 |
+
okButtonProps={{ loading }}
|
32 |
+
confirmLoading={loading}
|
33 |
+
width={600}
|
34 |
+
>
|
35 |
+
<Form
|
36 |
+
name="basic"
|
37 |
+
labelCol={{ span: 6 }}
|
38 |
+
wrapperCol={{ span: 18 }}
|
39 |
+
autoComplete="off"
|
40 |
+
form={form}
|
41 |
+
>
|
42 |
+
<Form.Item<FieldType>
|
43 |
+
label={t('destinationFolder')}
|
44 |
+
name="name"
|
45 |
+
rules={[{ required: true, message: t('pleaseSelect') }]}
|
46 |
+
>
|
47 |
+
<AsyncTreeSelect></AsyncTreeSelect>
|
48 |
+
</Form.Item>
|
49 |
+
</Form>
|
50 |
+
</Modal>
|
51 |
+
);
|
52 |
+
};
|
53 |
+
|
54 |
+
export default FileMovingModal;
|
web/src/services/file-manager-service.ts
CHANGED
@@ -13,6 +13,7 @@ const {
|
|
13 |
connectFileToKnowledge,
|
14 |
get_document_file,
|
15 |
getFile,
|
|
|
16 |
} = api;
|
17 |
|
18 |
const methods = {
|
@@ -49,6 +50,10 @@ const methods = {
|
|
49 |
method: 'get',
|
50 |
responseType: 'blob',
|
51 |
},
|
|
|
|
|
|
|
|
|
52 |
} as const;
|
53 |
|
54 |
const fileManagerService = registerServer<keyof typeof methods>(
|
|
|
13 |
connectFileToKnowledge,
|
14 |
get_document_file,
|
15 |
getFile,
|
16 |
+
moveFile,
|
17 |
} = api;
|
18 |
|
19 |
const methods = {
|
|
|
50 |
method: 'get',
|
51 |
responseType: 'blob',
|
52 |
},
|
53 |
+
moveFile: {
|
54 |
+
url: moveFile,
|
55 |
+
method: 'post',
|
56 |
+
},
|
57 |
} as const;
|
58 |
|
59 |
const fileManagerService = registerServer<keyof typeof methods>(
|
web/src/utils/api.ts
CHANGED
@@ -79,6 +79,7 @@ export default {
|
|
79 |
createFolder: `${api_host}/file/create`,
|
80 |
connectFileToKnowledge: `${api_host}/file2document/convert`,
|
81 |
getFile: `${api_host}/file/get`,
|
|
|
82 |
|
83 |
// system
|
84 |
getSystemVersion: `${api_host}/system/version`,
|
|
|
79 |
createFolder: `${api_host}/file/create`,
|
80 |
connectFileToKnowledge: `${api_host}/file2document/convert`,
|
81 |
getFile: `${api_host}/file/get`,
|
82 |
+
moveFile: `${api_host}/file/mv`,
|
83 |
|
84 |
// system
|
85 |
getSystemVersion: `${api_host}/system/version`,
|