From c4a24bead65f63235f3db9f8b14cc40c0c272563 Mon Sep 17 00:00:00 2001 From: Steven Date: Fri, 19 Jul 2024 20:52:52 +0800 Subject: [PATCH] chore(frontend): tweak memo relations --- .../components/CreateMemoRelationDialog.tsx | 4 +- .../ActionButton/AddMemoRelationButton.tsx | 3 + web/src/components/MemoRelationListView.tsx | 109 +++++++++++++++--- web/src/store/v1/memo.ts | 11 -- web/src/store/v1/resource.ts | 11 -- 5 files changed, 97 insertions(+), 41 deletions(-) diff --git a/web/src/components/CreateMemoRelationDialog.tsx b/web/src/components/CreateMemoRelationDialog.tsx index 1e1cb488..a8ebffa9 100644 --- a/web/src/components/CreateMemoRelationDialog.tsx +++ b/web/src/components/CreateMemoRelationDialog.tsx @@ -13,6 +13,8 @@ import Icon from "./Icon"; interface Props extends DialogProps { onConfirm: (memos: Memo[], embedded?: boolean) => void; + // Custom filter function for filtering memos. + filter?: (memo: Memo) => boolean; } const CreateMemoRelationDialog: React.FC = (props: Props) => { @@ -24,7 +26,7 @@ const CreateMemoRelationDialog: React.FC = (props: Props) => { const [fetchedMemos, setFetchedMemos] = useState([]); const [selectedMemos, setSelectedMemos] = useState([]); const [embedded, setEmbedded] = useState(true); - const filteredMemos = fetchedMemos.filter((memo) => !selectedMemos.includes(memo)); + const filteredMemos = fetchedMemos.filter((memo) => !selectedMemos.includes(memo) && (!props.filter || props.filter(memo))); useDebounce( async () => { diff --git a/web/src/components/MemoEditor/ActionButton/AddMemoRelationButton.tsx b/web/src/components/MemoEditor/ActionButton/AddMemoRelationButton.tsx index 1b7d1e9d..e8be41d5 100644 --- a/web/src/components/MemoEditor/ActionButton/AddMemoRelationButton.tsx +++ b/web/src/components/MemoEditor/ActionButton/AddMemoRelationButton.tsx @@ -5,6 +5,7 @@ import toast from "react-hot-toast"; import showCreateMemoRelationDialog from "@/components/CreateMemoRelationDialog"; import Icon from "@/components/Icon"; import { MemoRelation_Type } from "@/types/proto/api/v1/memo_relation_service"; +import { Memo } from "@/types/proto/api/v1/memo_service"; import { EditorRefActions } from "../Editor"; import { MemoEditorContext } from "../types"; @@ -55,6 +56,8 @@ const AddMemoRelationButton = (props: Props) => { ), ); }, + filter: (memo: Memo) => + memo.name !== context.memoName && !context.relationList.some((relation) => relation.relatedMemo === memo.name), }); }; diff --git a/web/src/components/MemoRelationListView.tsx b/web/src/components/MemoRelationListView.tsx index 7ad6b60e..4cbcb733 100644 --- a/web/src/components/MemoRelationListView.tsx +++ b/web/src/components/MemoRelationListView.tsx @@ -1,8 +1,11 @@ -import { memo, useEffect, useState } from "react"; +import clsx from "clsx"; +import { memo, useState } from "react"; +import { Link } from "react-router-dom"; +import useAsyncEffect from "@/hooks/useAsyncEffect"; import { useMemoStore } from "@/store/v1"; import { MemoRelation } from "@/types/proto/api/v1/memo_relation_service"; import { Memo } from "@/types/proto/api/v1/memo_service"; -import EmbeddedContent from "./MemoContent/EmbeddedContent"; +import Icon from "./Icon"; interface Props { memo: Memo; @@ -13,26 +16,96 @@ const MemoRelationListView = (props: Props) => { const { memo, relations: relationList } = props; const memoStore = useMemoStore(); const [referencingMemoList, setReferencingMemoList] = useState([]); + const [referencedMemoList, setReferencedMemoList] = useState([]); + const [selectedTab, setSelectedTab] = useState<"referencing" | "referenced">("referencing"); - useEffect(() => { - (async () => { - const referencingMemoList = await Promise.all( - relationList - .filter((relation) => relation.memo === memo.name && relation.relatedMemo !== memo.name) - .map((relation) => memoStore.getOrFetchMemoByName(relation.relatedMemo, { skipStore: true })), - ); - setReferencingMemoList(referencingMemoList); - })(); - }, [memo, relationList]); + useAsyncEffect(async () => { + const referencingMemoList = await Promise.all( + relationList + .filter((relation) => relation.memo === memo.name && relation.relatedMemo !== memo.name) + .map((relation) => memoStore.getOrFetchMemoByName(relation.relatedMemo, { skipStore: true })), + ); + setReferencingMemoList(referencingMemoList); + const referencedMemoList = await Promise.all( + relationList + .filter((relation) => relation.memo !== memo.name && relation.relatedMemo === memo.name) + .map((relation) => memoStore.getOrFetchMemoByName(relation.memo, { skipStore: true })), + ); + setReferencedMemoList(referencedMemoList); + if (referencingMemoList.length === 0) { + setSelectedTab("referenced"); + } else { + setSelectedTab("referencing"); + } + }, [memo.name, relationList]); + + if (referencingMemoList.length + referencedMemoList.length === 0) { + return null; + } return ( - referencingMemoList.length > 0 && ( -
- {referencingMemoList.map((memo) => { - return ; - })} +
+
+ {referencingMemoList.length > 0 && ( + + )} + {referencedMemoList.length > 0 && ( + + )}
- ) + {selectedTab === "referencing" && referencingMemoList.length > 0 && ( +
+ {referencingMemoList.map((memo) => { + return ( + + + {memo.snippet} + + ); + })} +
+ )} + {selectedTab === "referenced" && referencedMemoList.length > 0 && ( +
+ {referencedMemoList.map((memo) => { + return ( + + + {memo.snippet} + + ); + })} +
+ )} +
); }; diff --git a/web/src/store/v1/memo.ts b/web/src/store/v1/memo.ts index f4e695ec..b2394c18 100644 --- a/web/src/store/v1/memo.ts +++ b/web/src/store/v1/memo.ts @@ -48,17 +48,6 @@ export const useMemoStore = create( getMemoByName: (name: string) => { return get().memoMapByName[name]; }, - searchMemos: async (filter: string) => { - const { memos } = await memoServiceClient.searchMemos({ - filter, - }); - const memoMap = get().memoMapByName; - for (const memo of memos) { - memoMap[memo.name] = memo; - } - set({ stateId: uniqueId(), memoMapByName: memoMap }); - return memos; - }, fetchMemoByUid: async (uid: string) => { const memo = await memoServiceClient.getMemoByUid({ uid, diff --git a/web/src/store/v1/resource.ts b/web/src/store/v1/resource.ts index 89e194f4..9c90f4d0 100644 --- a/web/src/store/v1/resource.ts +++ b/web/src/store/v1/resource.ts @@ -15,17 +15,6 @@ export const useResourceStore = create( combine(getDefaultState(), (set, get) => ({ setState: (state: State) => set(state), getState: () => get(), - searchResources: async (filter: string) => { - const { resources } = await resourceServiceClient.searchResources({ - filter, - }); - const resourceMap = get().resourceMapByName; - for (const resource of resources) { - resourceMap[resource.name] = resource; - } - set({ resourceMapByName: resourceMap }); - return resources; - }, fetchResourceByUID: async (uid: string) => { const resource = await resourceServiceClient.getResourceByUid({ uid,