Skip to content

Commit

Permalink
feat: create folder infiniflow#345 (infiniflow#518)
Browse files Browse the repository at this point in the history
### What problem does this PR solve?

feat: create folder
feat: ensure that all files in the current folder can be correctly
requested after renaming the folder
infiniflow#345 

### Type of change

- [x] New Feature (non-breaking change which adds functionality)
  • Loading branch information
cike8899 authored Apr 24, 2024
1 parent 68f0609 commit 25fc958
Show file tree
Hide file tree
Showing 10 changed files with 285 additions and 47 deletions.
24 changes: 20 additions & 4 deletions web/src/hooks/fileManagerHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ export const useRemoveFile = () => {
const dispatch = useDispatch();

const removeFile = useCallback(
(fileIds: string[]) => {
(fileIds: string[], parentId: string) => {
return dispatch<any>({
type: 'fileManager/removeFile',
payload: { fileIds },
payload: { fileIds, parentId },
});
},
[dispatch],
Expand All @@ -38,10 +38,10 @@ export const useRenameFile = () => {
const dispatch = useDispatch();

const renameFile = useCallback(
(fileId: string, name: string) => {
(fileId: string, name: string, parentId: string) => {
return dispatch<any>({
type: 'fileManager/renameFile',
payload: { fileId, name },
payload: { fileId, name, parentId },
});
},
[dispatch],
Expand All @@ -66,6 +66,22 @@ export const useFetchParentFolderList = () => {
return fetchParentFolderList;
};

export const useCreateFolder = () => {
const dispatch = useDispatch();

const createFolder = useCallback(
(parentId: string, name: string) => {
return dispatch<any>({
type: 'fileManager/createFolder',
payload: { parentId, name, type: 'folder' },
});
},
[dispatch],
);

return createFolder;
};

export const useSelectFileList = () => {
const fileList = useSelector((state) => state.fileManager.fileList);

Expand Down
21 changes: 5 additions & 16 deletions web/src/pages/file-manager/action-cell/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useShowDeleteConfirm, useTranslate } from '@/hooks/commonHooks';
import { useTranslate } from '@/hooks/commonHooks';
import { IFile } from '@/interfaces/database/file-manager';
import { api_host } from '@/utils/api';
import { downloadFile } from '@/utils/fileUtil';
import {
Expand All @@ -8,9 +9,8 @@ import {
ToolOutlined,
} from '@ant-design/icons';
import { Button, Space, Tooltip } from 'antd';
import { useHandleDeleteFile } from '../hooks';

import { useRemoveFile } from '@/hooks/fileManagerHooks';
import { IFile } from '@/interfaces/database/file-manager';
import styles from './index.less';

interface IProps {
Expand All @@ -23,18 +23,7 @@ const ActionCell = ({ record, setCurrentRecord, showRenameModal }: IProps) => {
const documentId = record.id;
const beingUsed = false;
const { t } = useTranslate('knowledgeDetails');
const removeDocument = useRemoveFile();
const showDeleteConfirm = useShowDeleteConfirm();

const onRmDocument = () => {
if (!beingUsed) {
showDeleteConfirm({
onOk: () => {
return removeDocument([documentId]);
},
});
}
};
const { handleRemoveFile } = useHandleDeleteFile([documentId]);

const onDownloadDocument = () => {
downloadFile({
Expand Down Expand Up @@ -71,7 +60,7 @@ const ActionCell = ({ record, setCurrentRecord, showRenameModal }: IProps) => {
<Button
type="text"
disabled={beingUsed}
onClick={onRmDocument}
onClick={handleRemoveFile}
className={styles.iconButton}
>
<DeleteOutlined size={20} />
Expand Down
32 changes: 13 additions & 19 deletions web/src/pages/file-manager/file-toolbar.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ReactComponent as DeleteIcon } from '@/assets/svg/delete.svg';
import { useShowDeleteConfirm, useTranslate } from '@/hooks/commonHooks';
import { useTranslate } from '@/hooks/commonHooks';
import {
DownOutlined,
FileOutlined,
FileTextOutlined,
FolderOpenOutlined,
PlusOutlined,
SearchOutlined,
} from '@ant-design/icons';
Expand All @@ -17,20 +17,21 @@ import {
MenuProps,
Space,
} from 'antd';
import { useCallback, useMemo } from 'react';
import { useMemo } from 'react';
import {
useFetchDocumentListOnMount,
useGetPagination,
useHandleDeleteFile,
useHandleSearchChange,
useSelectBreadcrumbItems,
} from './hooks';

import { useRemoveFile } from '@/hooks/fileManagerHooks';
import { Link } from 'umi';
import styles from './index.less';

interface IProps {
selectedRowKeys: string[];
showFolderCreateModal: () => void;
}

const itemRender: BreadcrumbProps['itemRender'] = (
Expand All @@ -47,13 +48,11 @@ const itemRender: BreadcrumbProps['itemRender'] = (
);
};

const FileToolbar = ({ selectedRowKeys }: IProps) => {
const FileToolbar = ({ selectedRowKeys, showFolderCreateModal }: IProps) => {
const { t } = useTranslate('knowledgeDetails');
const { fetchDocumentList } = useFetchDocumentListOnMount();
const { setPagination, searchString } = useGetPagination(fetchDocumentList);
const { handleInputChange } = useHandleSearchChange(setPagination);
const removeDocument = useRemoveFile();
const showDeleteConfirm = useShowDeleteConfirm();
const breadcrumbItems = useSelectBreadcrumbItems();

const actionItems: MenuProps['items'] = useMemo(() => {
Expand All @@ -74,34 +73,29 @@ const FileToolbar = ({ selectedRowKeys }: IProps) => {
{ type: 'divider' },
{
key: '2',
onClick: showFolderCreateModal,
label: (
<div>
<Button type="link">
<FileOutlined />
{t('emptyFiles')}
<FolderOpenOutlined />
New Folder
</Button>
</div>
),
// disabled: true,
},
];
}, [t]);
}, [t, showFolderCreateModal]);

const handleDelete = useCallback(() => {
showDeleteConfirm({
onOk: () => {
return removeDocument(selectedRowKeys);
},
});
}, [removeDocument, showDeleteConfirm, selectedRowKeys]);
const { handleRemoveFile } = useHandleDeleteFile(selectedRowKeys);

const disabled = selectedRowKeys.length === 0;

const items: MenuProps['items'] = useMemo(() => {
return [
{
key: '4',
onClick: handleDelete,
onClick: handleRemoveFile,
label: (
<Flex gap={10}>
<span className={styles.deleteIconWrapper}>
Expand All @@ -112,7 +106,7 @@ const FileToolbar = ({ selectedRowKeys }: IProps) => {
),
},
];
}, [handleDelete, t]);
}, [handleRemoveFile, t]);

return (
<div className={styles.filter}>
Expand Down
64 changes: 64 additions & 0 deletions web/src/pages/file-manager/file-upload-modal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { InboxOutlined } from '@ant-design/icons';
import { Modal, Segmented, Upload, UploadProps, message } from 'antd';
import { useState } from 'react';

const { Dragger } = Upload;

const FileUploadModal = () => {
const [isModalOpen, setIsModalOpen] = useState(false);

const props: UploadProps = {
name: 'file',
multiple: true,
action: 'https://660d2bd96ddfa2943b33731c.mockapi.io/api/upload',
onChange(info) {
const { status } = info.file;
if (status !== 'uploading') {
console.log(info.file, info.fileList);
}
if (status === 'done') {
message.success(`${info.file.name} file uploaded successfully.`);
} else if (status === 'error') {
message.error(`${info.file.name} file upload failed.`);
}
},
onDrop(e) {
console.log('Dropped files', e.dataTransfer.files);
},
};

const handleOk = () => {
setIsModalOpen(false);
};

const handleCancel = () => {
setIsModalOpen(false);
};

return (
<>
<Modal
title="File upload"
open={isModalOpen}
onOk={handleOk}
onCancel={handleCancel}
>
<Segmented options={['Local uploads', 'S3 uploads']} block />
<Dragger {...props}>
<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>
</Dragger>
</Modal>
</>
);
};

export default FileUploadModal;
67 changes: 67 additions & 0 deletions web/src/pages/file-manager/folder-create-modal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { IModalManagerChildrenProps } from '@/components/modal-manager';
import { useTranslate } from '@/hooks/commonHooks';
import { Form, Input, Modal } from 'antd';

interface IProps extends Omit<IModalManagerChildrenProps, 'showModal'> {
loading: boolean;
onOk: (name: string) => void;
}

const FolderCreateModal = ({ visible, hideModal, loading, onOk }: IProps) => {
const [form] = Form.useForm();
const { t } = useTranslate('common');

type FieldType = {
name?: string;
};

const handleOk = async () => {
const ret = await form.validateFields();

return onOk(ret.name);
};

const handleCancel = () => {
hideModal();
};

const onFinish = (values: any) => {
console.log('Success:', values);
};

const onFinishFailed = (errorInfo: any) => {
console.log('Failed:', errorInfo);
};

return (
<Modal
title={'New Folder'}
open={visible}
onOk={handleOk}
onCancel={handleCancel}
okButtonProps={{ loading }}
confirmLoading={loading}
>
<Form
name="basic"
labelCol={{ span: 4 }}
wrapperCol={{ span: 20 }}
style={{ maxWidth: 600 }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
form={form}
>
<Form.Item<FieldType>
label={t('name')}
name="name"
rules={[{ required: true, message: t('namePlaceholder') }]}
>
<Input />
</Form.Item>
</Form>
</Modal>
);
};

export default FolderCreateModal;
Loading

0 comments on commit 25fc958

Please sign in to comment.