From 590b626052a6d3bddbf665d1e07610465b820c5b Mon Sep 17 00:00:00 2001 From: Steven Date: Wed, 1 May 2024 10:43:09 +0800 Subject: [PATCH] chore: update upload resources button --- web/src/components/CreateResourceDialog.tsx | 202 ------------------ .../ActionButton/UploadResourceButton.tsx | 84 ++++++++ web/src/components/MemoEditor/index.tsx | 26 +-- .../components/MemoEditor/types/context.ts | 5 + 4 files changed, 99 insertions(+), 218 deletions(-) delete mode 100644 web/src/components/CreateResourceDialog.tsx create mode 100644 web/src/components/MemoEditor/ActionButton/UploadResourceButton.tsx diff --git a/web/src/components/CreateResourceDialog.tsx b/web/src/components/CreateResourceDialog.tsx deleted file mode 100644 index cd60d27b..00000000 --- a/web/src/components/CreateResourceDialog.tsx +++ /dev/null @@ -1,202 +0,0 @@ -import { Button, IconButton, List, ListItem, Typography } from "@mui/joy"; -import React, { useRef, useState } from "react"; -import { toast } from "react-hot-toast"; -import { useResourceStore } from "@/store/v1"; -import { Resource } from "@/types/proto/api/v1/resource_service"; -import { useTranslate } from "@/utils/i18n"; -import { generateDialog } from "./Dialog"; -import Icon from "./Icon"; - -interface Props extends DialogProps { - onCancel?: () => void; - onConfirm?: (resourceList: Resource[]) => void; -} - -interface State { - uploadingFlag: boolean; -} - -const CreateResourceDialog: React.FC = (props: Props) => { - const t = useTranslate(); - const { destroy, onCancel, onConfirm } = props; - const resourceStore = useResourceStore(); - const [state, setState] = useState({ - uploadingFlag: false, - }); - const [fileList, setFileList] = useState([]); - const fileInputRef = useRef(null); - - const handleReorderFileList = (fileName: string, direction: "up" | "down") => { - const fileIndex = fileList.findIndex((file) => file.name === fileName); - if (fileIndex === -1) { - return; - } - - const newFileList = [...fileList]; - - if (direction === "up") { - if (fileIndex === 0) { - return; - } - const temp = newFileList[fileIndex - 1]; - newFileList[fileIndex - 1] = newFileList[fileIndex]; - newFileList[fileIndex] = temp; - } else if (direction === "down") { - if (fileIndex === fileList.length - 1) { - return; - } - const temp = newFileList[fileIndex + 1]; - newFileList[fileIndex + 1] = newFileList[fileIndex]; - newFileList[fileIndex] = temp; - } - - setFileList(newFileList); - }; - - const handleCloseDialog = () => { - if (onCancel) { - onCancel(); - } - destroy(); - }; - - const handleFileInputChange = async () => { - if (!fileInputRef.current || !fileInputRef.current.files) { - return; - } - - const files: File[] = []; - for (const file of fileInputRef.current.files) { - files.push(file); - } - setFileList(files); - }; - - const allowConfirmAction = () => { - if (!fileInputRef.current || !fileInputRef.current.files || fileInputRef.current.files.length === 0) { - return false; - } - return true; - }; - - const handleConfirmBtnClick = async () => { - if (state.uploadingFlag) { - return; - } - - setState((state) => { - return { - ...state, - uploadingFlag: true, - }; - }); - - const createdResourceList: Resource[] = []; - try { - if (!fileInputRef.current || !fileInputRef.current.files) { - return; - } - const filesOnInput = Array.from(fileInputRef.current.files); - for (const file of fileList) { - const fileOnInput = filesOnInput.find((fileOnInput) => fileOnInput.name === file.name); - if (!fileOnInput) { - continue; - } - const { name: filename, size, type } = file; - const buffer = new Uint8Array(await file.arrayBuffer()); - const resource = await resourceStore.createResource({ - resource: Resource.fromPartial({ - filename, - size, - type, - content: buffer, - }), - }); - createdResourceList.push(resource); - } - } catch (error: any) { - console.error(error); - toast.error(error.details); - } - - if (onConfirm) { - onConfirm(createdResourceList); - } - destroy(); - }; - - return ( - <> -
-

{t("resource.create-dialog.title")}

- - - -
-
-
- - -
- - {fileList.map((file, index) => ( - - {file.name} -
- - -
-
- ))} -
- -
- - -
-
- - ); -}; - -function showCreateResourceDialog(props: Omit) { - generateDialog( - { - dialogName: "create-resource-dialog", - }, - CreateResourceDialog, - props, - ); -} - -export default showCreateResourceDialog; diff --git a/web/src/components/MemoEditor/ActionButton/UploadResourceButton.tsx b/web/src/components/MemoEditor/ActionButton/UploadResourceButton.tsx new file mode 100644 index 00000000..378cbcbc --- /dev/null +++ b/web/src/components/MemoEditor/ActionButton/UploadResourceButton.tsx @@ -0,0 +1,84 @@ +import { IconButton } from "@mui/joy"; +import { useContext, useRef, useState } from "react"; +import toast from "react-hot-toast"; +import Icon from "@/components/Icon"; +import { useResourceStore } from "@/store/v1"; +import { Resource } from "@/types/proto/api/v1/resource_service"; +import { MemoEditorContext } from "../types"; + +interface State { + uploadingFlag: boolean; +} + +const UploadResourceButton = () => { + const context = useContext(MemoEditorContext); + const resourceStore = useResourceStore(); + const [state, setState] = useState({ + uploadingFlag: false, + }); + const fileInputRef = useRef(null); + + const handleFileInputChange = async () => { + if (!fileInputRef.current || !fileInputRef.current.files || fileInputRef.current.files.length === 0) { + return; + } + if (state.uploadingFlag) { + return; + } + + setState((state) => { + return { + ...state, + uploadingFlag: true, + }; + }); + + const createdResourceList: Resource[] = []; + try { + if (!fileInputRef.current || !fileInputRef.current.files) { + return; + } + const filesOnInput = Array.from(fileInputRef.current.files); + for (const file of fileInputRef.current.files) { + const fileOnInput = filesOnInput.find((fileOnInput) => fileOnInput.name === file.name); + if (!fileOnInput) { + continue; + } + const { name: filename, size, type } = file; + const buffer = new Uint8Array(await file.arrayBuffer()); + const resource = await resourceStore.createResource({ + resource: Resource.fromPartial({ + filename, + size, + type, + content: buffer, + }), + }); + createdResourceList.push(resource); + } + } catch (error: any) { + console.error(error); + toast.error(error.details); + } + + context.setResourceList([...context.resourceList, ...createdResourceList]); + }; + + return ( + + + + + ); +}; + +export default UploadResourceButton; diff --git a/web/src/components/MemoEditor/index.tsx b/web/src/components/MemoEditor/index.tsx index 6aa4b2b9..2585a3fb 100644 --- a/web/src/components/MemoEditor/index.tsx +++ b/web/src/components/MemoEditor/index.tsx @@ -1,4 +1,4 @@ -import { Select, Option, Button, IconButton, Divider } from "@mui/joy"; +import { Select, Option, Button, Divider } from "@mui/joy"; import React, { useEffect, useMemo, useRef, useState } from "react"; import { toast } from "react-hot-toast"; import { useTranslation } from "react-i18next"; @@ -17,12 +17,12 @@ import { WorkspaceSettingKey } from "@/types/proto/store/workspace_setting"; import { useTranslate } from "@/utils/i18n"; import { convertVisibilityFromString, convertVisibilityToString } from "@/utils/memo"; import { extractTagsFromContent } from "@/utils/tag"; -import showCreateResourceDialog from "../CreateResourceDialog"; import Icon from "../Icon"; import VisibilityIcon from "../VisibilityIcon"; import AddMemoRelationButton from "./ActionButton/AddMemoRelationButton"; import MarkdownMenu from "./ActionButton/MarkdownMenu"; import TagSelector from "./ActionButton/TagSelector"; +import UploadResourceButton from "./ActionButton/UploadResourceButton"; import Editor, { EditorRefActions } from "./Editor"; import RelationListView from "./RelationListView"; import ResourceListView from "./ResourceListView"; @@ -176,17 +176,6 @@ const MemoEditor = (props: Props) => { })); }; - const handleUploadFileBtnClick = () => { - showCreateResourceDialog({ - onConfirm: (resourceList) => { - setState((prevState) => ({ - ...prevState, - resourceList: [...prevState.resourceList, ...resourceList], - })); - }, - }); - }; - const handleSetResourceList = (resourceList: Resource[]) => { setState((prevState) => ({ ...prevState, @@ -397,7 +386,14 @@ const MemoEditor = (props: Props) => { return ( { + setState((prevState) => ({ + ...prevState, + resourceList, + })); + }, setRelationList: (relationList: MemoRelation[]) => { setState((prevState) => ({ ...prevState, @@ -425,9 +421,7 @@ const MemoEditor = (props: Props) => {
- - - +
diff --git a/web/src/components/MemoEditor/types/context.ts b/web/src/components/MemoEditor/types/context.ts index 73fbd6ac..c53e9430 100644 --- a/web/src/components/MemoEditor/types/context.ts +++ b/web/src/components/MemoEditor/types/context.ts @@ -1,13 +1,18 @@ import { createContext } from "react"; import { MemoRelation } from "@/types/proto/api/v1/memo_relation_service"; +import { Resource } from "@/types/proto/api/v1/resource_service"; interface Context { + resourceList: Resource[]; relationList: MemoRelation[]; + setResourceList: (resourceList: Resource[]) => void; setRelationList: (relationList: MemoRelation[]) => void; memoName?: string; } export const MemoEditorContext = createContext({ + resourceList: [], relationList: [], + setResourceList: () => {}, setRelationList: () => {}, });