From 2911f8722e97ddd1355155c190fbbd3e72e6517d Mon Sep 17 00:00:00 2001 From: hzhang Date: Wed, 5 Mar 2025 01:23:09 +0000 Subject: [PATCH] add: tree / search --- src/components/Navigations/PathNode.js | 33 ++++- src/components/Navigations/SideNavigation.js | 133 +++++++------------ src/utils/path-queries.js | 4 + src/utils/tree-queries.js | 19 +++ 4 files changed, 96 insertions(+), 93 deletions(-) create mode 100644 src/utils/tree-queries.js diff --git a/src/components/Navigations/PathNode.js b/src/components/Navigations/PathNode.js index 7b06993..6586020 100644 --- a/src/components/Navigations/PathNode.js +++ b/src/components/Navigations/PathNode.js @@ -2,7 +2,7 @@ import React, {useState} from "react"; import { Link } from "react-router-dom"; import PermissionGuard from "../PermissionGuard"; import "./PathNode.css"; -import {useDeletePath, useMovePath, usePaths, useUpdatePath} from "../../utils/path-queries"; +import {useDeletePath, useMovePath, usePath, usePaths, useUpdatePath} from "../../utils/path-queries"; import {useIndexMarkdown, useMarkdownsByPath, useMoveMarkdown} from "../../utils/markdown-queries"; import MarkdownNode from "./MarkdownNode"; @@ -11,8 +11,8 @@ const PathNode = ({ path, isRoot = false }) => { const [isEditing, setIsEditing] = useState(false); const [newName, setNewName] = useState(path.name); - const { data: childPaths, isLoading: isChildLoading, error: childError } = usePaths(path.id); - const { data: markdowns, isLoading: isMarkdownLoading, error: markdownError } = useMarkdownsByPath(path.id); +// const { data: childPaths, isLoading: isChildLoading, error: childError } = usePaths(path.id); +// const { data: markdowns, isLoading: isMarkdownLoading, error: markdownError } = useMarkdownsByPath(path.id); const deletePath = useDeletePath(); const updatePath = useUpdatePath(); @@ -60,18 +60,40 @@ const PathNode = ({ path, isRoot = false }) => { }) }; + const childPaths = path.children.filter(x => x.type==="path"); const sortedPaths = childPaths ? childPaths.slice().sort((a, b) => a.order.localeCompare(b.order)) : []; + const markdowns = path.children.filter(x => x.type==="markdown"); const sortedMarkdowns = markdowns ? markdowns.filter(md => md.title !== "index").sort((a, b) => a.order.localeCompare(b.order)) : []; - if(childError || markdownError){ +/* if(childError || markdownError){ return
  • Error...
  • ; - } + }*/ + if(isRoot) + return ( + + ); return (
  • @@ -167,7 +189,6 @@ const PathNode = ({ path, isRoot = false }) => { {isExpanded && (
      - {isChildLoading &&

      Loading...

      } {sortedPaths.map((child) => ( { - const {data: paths, isLoading, error } = usePaths(1); + const {data: tree, isLoading, error} = useTree(); const deletePath = useDeletePath(); const updatePath = useUpdatePath(); const [searchTerm, setSearchTerm] = React.useState(""); const [keyword, setKeyword] = React.useState(""); const [searchMode, setSearchMode] = React.useState(false); - - const {data: searchResults, isLoading: isSearching} = useSearchMarkdown(keyword, { - enabled: searchMode && !!searchMode, - }); - const sortedPaths = paths - ? paths.slice().sort((a, b) => a.order.localeCompare(b.order)) - : []; const handleDelete = (id) => { if (window.confirm("Are you sure you want to delete this path?")){ deletePath.mutate(id, { @@ -30,13 +22,30 @@ const SideNavigation = () => { } }; - const handleSearch = () => { - setSearchMode(true); - setKeyword(searchTerm); - } - const exitSearch = () => { - setSearchMode(false); - } + + const filterTree = (t, k) => { + if(t === undefined) + return undefined; + if (t.type === "path") { + if (t.name.includes(k)) { + return { ...t }; + } + const filteredChildren = (t.children || []) + .map(c => filterTree(c, k)) + .filter(Boolean); + + if (filteredChildren.length > 0) { + return { ...t, children: filteredChildren }; + } + } else if (t.type === "markdown") { + if (t.title.includes(k)) { + return { ...t }; + } + } + return undefined; + }; + + const filteredTree = filterTree(tree, keyword); const handleSave = (id, newName) => { updatePath.mutate({ id, data: {name: newName }} , { @@ -45,55 +54,17 @@ const SideNavigation = () => { } }); }; - if(!searchMode && isLoading){ - return ; - } - if(searchMode && isSearching){ - return ; - } - if(error){ - return ; - } - - + if (isLoading) return ; + if (error) return ; return ( ); diff --git a/src/utils/path-queries.js b/src/utils/path-queries.js index 512d35f..b0b4ecd 100644 --- a/src/utils/path-queries.js +++ b/src/utils/path-queries.js @@ -55,6 +55,7 @@ export const useCreatePath = () => { onSuccess: (res, variables) => { console.log(JSON.stringify(variables)); queryClient.invalidateQueries(["paths", variables.parent_id]); + queryClient.invalidateQueries("tree"); }, } ); @@ -73,6 +74,7 @@ export const useUpdatePath = () => { onSuccess: (res, variables) => { queryClient.invalidateQueries(["paths", res.parent_id]); queryClient.invalidateQueries(["path", variables.data.id]); + queryClient.invalidateQueries("tree"); }, } ); @@ -89,6 +91,7 @@ export const useDeletePath = () => { { onSuccess: () => { queryClient.invalidateQueries("paths"); + queryClient.invalidateQueries("tree"); }, } ); @@ -107,6 +110,7 @@ export const useMovePath = () => { { onSuccess: () => { queryClient.invalidateQueries("paths"); + queryClient.invalidateQueries("tree"); } } ); diff --git a/src/utils/tree-queries.js b/src/utils/tree-queries.js new file mode 100644 index 0000000..67fbdf4 --- /dev/null +++ b/src/utils/tree-queries.js @@ -0,0 +1,19 @@ +import {useQuery, useMutation, useQueryClient} from "react-query"; +import {fetch_} from "./request-utils"; +import {useConfig} from "../ConfigProvider"; + + +export const useTree = () => { + const queryClient = useQueryClient(); + const config = useConfig(); + return useQuery( + "tree", + () => fetch_(`${config.BACKEND_HOST}/api/tree/`), + { + onSuccess: data => { + if(data) + queryClient.setQueryData("tree", data); + } + } + ); +} \ No newline at end of file