From fa91f87675b121d3bfec0cbff0e0452ef6afeb0e Mon Sep 17 00:00:00 2001 From: fantasticit Date: Tue, 21 Jun 2022 22:20:26 +0800 Subject: [PATCH] client: update document import --- .../components/wiki/setting/import/index.tsx | 183 +++++++----------- .../setting/import/{editor.tsx => parser.tsx} | 50 +++-- packages/client/src/tiptap/core/index.tsx | 4 + 3 files changed, 98 insertions(+), 139 deletions(-) rename packages/client/src/components/wiki/setting/import/{editor.tsx => parser.tsx} (61%) diff --git a/packages/client/src/components/wiki/setting/import/index.tsx b/packages/client/src/components/wiki/setting/import/index.tsx index ce2fc3c4..fe40338b 100644 --- a/packages/client/src/components/wiki/setting/import/index.tsx +++ b/packages/client/src/components/wiki/setting/import/index.tsx @@ -1,11 +1,10 @@ -import { IconUpload } from '@douyinfe/semi-icons'; -import { Button, List, Toast, Typography } from '@douyinfe/semi-ui'; +import { Button, Toast, Typography, Upload } from '@douyinfe/semi-ui'; import type { IWiki } from '@think/domains'; import { useCreateDocument } from 'data/document'; import { useToggle } from 'hooks/use-toggle'; -import { useCallback, useRef, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; -import { ImportEditor } from './editor'; +import { createMarkdownParser, MarkdownParse } from './parser'; interface IProps { wikiId: IWiki['id']; @@ -15,137 +14,97 @@ const { Text } = Typography; export const Import: React.FC = ({ wikiId }) => { const { create } = useCreateDocument(); - const $upload = useRef(); - const [uploadFiles, setUploadFiles] = useState([]); - const [texts, setTexts] = useState>({}); - const [payloads, setPayloads] = useState< - Record< - string, - { - title: string; - content: string; - state: Uint8Array; - } - > - >({}); - const [parsedFiles, setParsedFiles] = useState([]); + const $upload = useRef(); const [loading, toggleLoading] = useToggle(false); + const [markdownParser, setMarkdownParser] = useState(); + const [fileList, setFileList] = useState([]); - const selectFile = useCallback(() => { - $upload.current.click(); - }, []); - - const handleFile = useCallback((e) => { - const files = Array.from(e.target.files) as Array; - + const handleFile = useCallback(({ fileList: files }) => { if (!files.length) return; files.forEach((file) => { + const fileName = file.fileInstance.name; + const fileReader = new FileReader(); fileReader.onload = function () { - setTexts((texts) => { - texts[file.name] = fileReader.result; - return texts; - }); - - setUploadFiles((files) => { - return files.concat(file.name); + setFileList((fileList) => { + if (fileList.find((file) => file.name === fileName)) return fileList; + return fileList.concat({ ...file, text: fileReader.result }); }); }; - fileReader.readAsText(file); + fileReader.readAsText(file.fileInstance); + }); + + return false; + }, []); + + const removeFile = useCallback((currentFile) => { + setFileList((fileList) => { + return fileList.filter((file) => file.name !== currentFile.name); }); }, []); - const onParsedFile = useCallback((filename) => { - return (payload) => { - setPayloads((payloads) => { - payloads[filename] = payload; - setParsedFiles((files) => files.concat(filename)); - return payloads; - }); - }; - }, []); - - const onParsedFileError = useCallback((filename) => { - return () => { - setUploadFiles((files) => { - return files.filter((name) => name !== filename); - }); - setTexts((texts) => { - delete texts[filename]; - return texts; - }); - }; - }, []); - - const onDeleteFile = useCallback((toDeleteFilename) => { - return () => { - setPayloads((payloads) => { - const newPayloads = Object.keys(payloads).reduce((accu, filename) => { - if (filename !== toDeleteFilename) { - accu[filename] = payloads[filename]; - } - return accu; - }, {}); - setParsedFiles(Object.keys(newPayloads)); - return newPayloads; - }); - }; - }, []); - const importFile = useCallback(() => { + if (!markdownParser) return; + + const total = fileList.length; + let success = 0; + let failed = 0; + toggleLoading(true); - Promise.all( - Object.keys(payloads).map((filename) => { - return create({ ...payloads[filename], wikiId }); - }) - ) - .then(() => { - Toast.success('文档已导入'); - }) - .finally(() => { - toggleLoading(false); - setTexts({}); - setUploadFiles([]); - setPayloads({}); - setParsedFiles([]); - $upload.current.value = ''; - }); - }, [payloads, toggleLoading, create, wikiId]); + for (const file of fileList) { + const payload = markdownParser.parse(file.name, file.text); + create({ ...payload, wikiId }) + .then(() => { + success += 1; + }) + .catch(() => { + failed += 1; + }) + .finally(() => { + if (success + failed === total) { + $upload.current.clear(); + toggleLoading(false); + setFileList([]); + + if (failed > 0) { + Toast.error('部分文件导入失败,请重新尝试导入!'); + } else { + Toast.success('导入成功'); + } + } + }); + } + }, [markdownParser, fileList, toggleLoading, create, wikiId]); + + useEffect(() => { + const markdownParser = createMarkdownParser(); + setMarkdownParser(markdownParser); + + return () => { + markdownParser.destroy(); + }; + }, []); return (
- - - - - {uploadFiles.map((filename) => { - return ( - - ); - })} - - ( - {filename}
} extra={} /> - )} - emptyContent={仅支持 Markdown 文件导入} + 点击上传文件或拖拽文件到这里} + dragSubText={仅支持 Markdown 文件导入} + onRemove={removeFile} />