From dcd68bc5f4fb0d68408776ba90339df89ea09ec9 Mon Sep 17 00:00:00 2001 From: Steven Date: Tue, 27 May 2025 07:55:00 +0800 Subject: [PATCH] refactor: migrate resource store to v2 --- .../EmbeddedContent/EmbeddedResource.tsx | 8 +-- .../ActionButton/UploadResourceButton.tsx | 8 +-- web/src/components/MemoEditor/index.tsx | 5 +- web/src/store/v1/index.ts | 1 - web/src/store/v1/resource.ts | 44 -------------- web/src/store/v2/index.ts | 3 +- web/src/store/v2/resource.ts | 59 +++++++++++++++++++ 7 files changed, 71 insertions(+), 57 deletions(-) delete mode 100644 web/src/store/v1/resource.ts create mode 100644 web/src/store/v2/resource.ts diff --git a/web/src/components/MemoContent/EmbeddedContent/EmbeddedResource.tsx b/web/src/components/MemoContent/EmbeddedContent/EmbeddedResource.tsx index 7711158c..3690a113 100644 --- a/web/src/components/MemoContent/EmbeddedContent/EmbeddedResource.tsx +++ b/web/src/components/MemoContent/EmbeddedContent/EmbeddedResource.tsx @@ -1,7 +1,8 @@ +import { observer } from "mobx-react-lite"; import { useEffect } from "react"; import MemoResourceListView from "@/components/MemoResourceListView"; import useLoading from "@/hooks/useLoading"; -import { useResourceStore } from "@/store/v1"; +import { resourceStore } from "@/store/v2"; import { cn } from "@/utils"; import Error from "./Error"; @@ -35,9 +36,8 @@ const getAdditionalClassNameWithParams = (params: URLSearchParams) => { return additionalClassNames.join(" "); }; -const EmbeddedResource = ({ resourceId: uid, params: paramsStr }: Props) => { +const EmbeddedResource = observer(({ resourceId: uid, params: paramsStr }: Props) => { const loadingState = useLoading(); - const resourceStore = useResourceStore(); const resource = resourceStore.getResourceByName(uid); const params = new URLSearchParams(paramsStr); @@ -57,6 +57,6 @@ const EmbeddedResource = ({ resourceId: uid, params: paramsStr }: Props) => { ); -}; +}); export default EmbeddedResource; diff --git a/web/src/components/MemoEditor/ActionButton/UploadResourceButton.tsx b/web/src/components/MemoEditor/ActionButton/UploadResourceButton.tsx index 074fa24a..e63a5c92 100644 --- a/web/src/components/MemoEditor/ActionButton/UploadResourceButton.tsx +++ b/web/src/components/MemoEditor/ActionButton/UploadResourceButton.tsx @@ -1,8 +1,9 @@ import { Button } from "@usememos/mui"; import { LoaderIcon, PaperclipIcon } from "lucide-react"; +import { observer } from "mobx-react-lite"; import { useContext, useRef, useState } from "react"; import toast from "react-hot-toast"; -import { useResourceStore } from "@/store/v1"; +import { resourceStore } from "@/store/v2"; import { Resource } from "@/types/proto/api/v1/resource_service"; import { MemoEditorContext } from "../types"; @@ -14,9 +15,8 @@ interface State { uploadingFlag: boolean; } -const UploadResourceButton = (props: Props) => { +const UploadResourceButton = observer((props: Props) => { const context = useContext(MemoEditorContext); - const resourceStore = useResourceStore(); const [state, setState] = useState({ uploadingFlag: false, }); @@ -86,6 +86,6 @@ const UploadResourceButton = (props: Props) => { /> ); -}; +}); export default UploadResourceButton; diff --git a/web/src/components/MemoEditor/index.tsx b/web/src/components/MemoEditor/index.tsx index 0b71b064..724ffeaa 100644 --- a/web/src/components/MemoEditor/index.tsx +++ b/web/src/components/MemoEditor/index.tsx @@ -13,8 +13,8 @@ import { TAB_SPACE_WIDTH } from "@/helpers/consts"; import { isValidUrl } from "@/helpers/utils"; import useAsyncEffect from "@/hooks/useAsyncEffect"; import useCurrentUser from "@/hooks/useCurrentUser"; -import { useMemoStore, useResourceStore } from "@/store/v1"; -import { userStore, workspaceStore } from "@/store/v2"; +import { useMemoStore } from "@/store/v1"; +import { resourceStore, userStore, workspaceStore } from "@/store/v2"; import { Location, Memo, MemoRelation, MemoRelation_Type, Visibility } from "@/types/proto/api/v1/memo_service"; import { Resource } from "@/types/proto/api/v1/resource_service"; import { UserSetting } from "@/types/proto/api/v1/user_service"; @@ -62,7 +62,6 @@ const MemoEditor = observer((props: Props) => { const t = useTranslate(); const { i18n } = useTranslation(); const memoStore = useMemoStore(); - const resourceStore = useResourceStore(); const currentUser = useCurrentUser(); const [state, setState] = useState({ memoVisibility: Visibility.PRIVATE, diff --git a/web/src/store/v1/index.ts b/web/src/store/v1/index.ts index 65cd971d..b090b900 100644 --- a/web/src/store/v1/index.ts +++ b/web/src/store/v1/index.ts @@ -1,3 +1,2 @@ export * from "./memo"; -export * from "./resource"; export * from "./memoFilter"; diff --git a/web/src/store/v1/resource.ts b/web/src/store/v1/resource.ts deleted file mode 100644 index c9575222..00000000 --- a/web/src/store/v1/resource.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { create } from "zustand"; -import { combine } from "zustand/middleware"; -import { resourceServiceClient } from "@/grpcweb"; -import { CreateResourceRequest, Resource, UpdateResourceRequest } from "@/types/proto/api/v1/resource_service"; - -interface State { - resourceMapByName: Record; -} - -const getDefaultState = (): State => ({ - resourceMapByName: {}, -}); - -export const useResourceStore = create( - combine(getDefaultState(), (set, get) => ({ - setState: (state: State) => set(state), - getState: () => get(), - fetchResourceByName: async (name: string) => { - const resource = await resourceServiceClient.getResource({ - name, - }); - const resourceMap = get().resourceMapByName; - resourceMap[resource.name] = resource; - set({ resourceMapByName: resourceMap }); - return resource; - }, - getResourceByName: (name: string) => { - const resourceMap = get().resourceMapByName; - return Object.values(resourceMap).find((r) => r.name === name); - }, - async createResource(create: CreateResourceRequest): Promise { - const resource = await resourceServiceClient.createResource(create); - const resourceMap = get().resourceMapByName; - resourceMap[resource.name] = resource; - return resource; - }, - async updateResource(update: UpdateResourceRequest): Promise { - const resource = await resourceServiceClient.updateResource(update); - const resourceMap = get().resourceMapByName; - resourceMap[resource.name] = resource; - return resource; - }, - })), -); diff --git a/web/src/store/v2/index.ts b/web/src/store/v2/index.ts index 94307e44..4747e2bb 100644 --- a/web/src/store/v2/index.ts +++ b/web/src/store/v2/index.ts @@ -1,5 +1,6 @@ +import resourceStore from "./resource"; import userStore from "./user"; import viewStore from "./view"; import workspaceStore from "./workspace"; -export { workspaceStore, userStore, viewStore }; +export { resourceStore, workspaceStore, userStore, viewStore }; diff --git a/web/src/store/v2/resource.ts b/web/src/store/v2/resource.ts new file mode 100644 index 00000000..09164c68 --- /dev/null +++ b/web/src/store/v2/resource.ts @@ -0,0 +1,59 @@ +import { makeAutoObservable } from "mobx"; +import { resourceServiceClient } from "@/grpcweb"; +import { CreateResourceRequest, Resource, UpdateResourceRequest } from "@/types/proto/api/v1/resource_service"; + +class LocalState { + resourceMapByName: Record = {}; + + constructor() { + makeAutoObservable(this); + } + + setPartial(partial: Partial) { + Object.assign(this, partial); + } +} + +const resourceStore = (() => { + const state = new LocalState(); + + const fetchResourceByName = async (name: string) => { + const resource = await resourceServiceClient.getResource({ + name, + }); + const resourceMap = { ...state.resourceMapByName }; + resourceMap[resource.name] = resource; + state.setPartial({ resourceMapByName: resourceMap }); + return resource; + }; + + const getResourceByName = (name: string) => { + return Object.values(state.resourceMapByName).find((r) => r.name === name); + }; + + const createResource = async (create: CreateResourceRequest): Promise => { + const resource = await resourceServiceClient.createResource(create); + const resourceMap = { ...state.resourceMapByName }; + resourceMap[resource.name] = resource; + state.setPartial({ resourceMapByName: resourceMap }); + return resource; + }; + + const updateResource = async (update: UpdateResourceRequest): Promise => { + const resource = await resourceServiceClient.updateResource(update); + const resourceMap = { ...state.resourceMapByName }; + resourceMap[resource.name] = resource; + state.setPartial({ resourceMapByName: resourceMap }); + return resource; + }; + + return { + state, + fetchResourceByName, + getResourceByName, + createResource, + updateResource, + }; +})(); + +export default resourceStore;