mirror of
https://github.com/docmost/docmost.git
synced 2025-11-19 23:41:07 +10:00
fix: sidebar list when changing workspace (#1150)
* init * navigate in overview if current page is in deleted node * fix: implement pagination in sidebar-pages queries * fix: appendNodeChildren() Preserve deeper children if they exist and remove node if deleted
This commit is contained in:
@ -1,4 +1,19 @@
|
||||
import { atom } from "jotai";
|
||||
import { SpaceTreeNode } from "@/features/page/tree/types";
|
||||
import { appendNodeChildren } from "../utils";
|
||||
|
||||
export const treeDataAtom = atom<SpaceTreeNode[]>([]);
|
||||
|
||||
// Atom
|
||||
export const appendNodeChildrenAtom = atom(
|
||||
null,
|
||||
(
|
||||
get,
|
||||
set,
|
||||
{ parentId, children }: { parentId: string; children: SpaceTreeNode[] }
|
||||
) => {
|
||||
const currentTree = get(treeDataAtom);
|
||||
const updatedTree = appendNodeChildren(currentTree, parentId, children);
|
||||
set(treeDataAtom, updatedTree);
|
||||
}
|
||||
);
|
||||
|
||||
@ -2,7 +2,7 @@ import { NodeApi, NodeRendererProps, Tree, TreeApi } from "react-arborist";
|
||||
import { atom, useAtom } from "jotai";
|
||||
import { treeApiAtom } from "@/features/page/tree/atoms/tree-api-atom.ts";
|
||||
import {
|
||||
fetchAncestorChildren,
|
||||
fetchAllAncestorChildren,
|
||||
useGetRootSidebarPagesQuery,
|
||||
usePageQuery,
|
||||
useUpdatePageMutation,
|
||||
@ -24,7 +24,7 @@ import {
|
||||
IconPointFilled,
|
||||
IconTrash,
|
||||
} from "@tabler/icons-react";
|
||||
import { treeDataAtom } from "@/features/page/tree/atoms/tree-data-atom.ts";
|
||||
import { appendNodeChildrenAtom, treeDataAtom } from "@/features/page/tree/atoms/tree-data-atom.ts";
|
||||
import clsx from "clsx";
|
||||
import EmojiPicker from "@/components/ui/emoji-picker.tsx";
|
||||
import { useTreeMutation } from "@/features/page/tree/hooks/use-tree-mutation.ts";
|
||||
@ -140,7 +140,7 @@ export default function SpaceTree({ spaceId, readOnly }: SpaceTreeProps) {
|
||||
if (ancestor.id === currentPage.id) {
|
||||
return;
|
||||
}
|
||||
const children = await fetchAncestorChildren({
|
||||
const children = await fetchAllAncestorChildren({
|
||||
pageId: ancestor.id,
|
||||
spaceId: ancestor.spaceId,
|
||||
});
|
||||
@ -237,6 +237,7 @@ function Node({ node, style, dragHandle, tree }: NodeRendererProps<any>) {
|
||||
const { t } = useTranslation();
|
||||
const updatePageMutation = useUpdatePageMutation();
|
||||
const [treeData, setTreeData] = useAtom(treeDataAtom);
|
||||
const [, appendChildren] = useAtom(appendNodeChildrenAtom);
|
||||
const emit = useQueryEmit();
|
||||
const { spaceSlug } = useParams();
|
||||
const timerRef = useRef(null);
|
||||
@ -262,9 +263,10 @@ function Node({ node, style, dragHandle, tree }: NodeRendererProps<any>) {
|
||||
|
||||
async function handleLoadChildren(node: NodeApi<SpaceTreeNode>) {
|
||||
if (!node.data.hasChildren) return;
|
||||
if (node.data.children && node.data.children.length > 0) {
|
||||
return;
|
||||
}
|
||||
// in conflict with use-query-subscription.ts => case "addTreeNode","moveTreeNode" etc with websocket
|
||||
// if (node.data.children && node.data.children.length > 0) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
try {
|
||||
const params: SidebarPagesParams = {
|
||||
@ -272,21 +274,12 @@ function Node({ node, style, dragHandle, tree }: NodeRendererProps<any>) {
|
||||
spaceId: node.data.spaceId,
|
||||
};
|
||||
|
||||
const newChildren = await queryClient.fetchQuery({
|
||||
queryKey: ["sidebar-pages", params],
|
||||
queryFn: () => getSidebarPages(params),
|
||||
staleTime: 10 * 60 * 1000,
|
||||
const childrenTree = await fetchAllAncestorChildren(params);
|
||||
|
||||
appendChildren({
|
||||
parentId: node.data.id,
|
||||
children: childrenTree,
|
||||
});
|
||||
|
||||
const childrenTree = buildTree(newChildren.items);
|
||||
|
||||
const updatedTreeData = appendNodeChildren(
|
||||
treeData,
|
||||
node.data.id,
|
||||
childrenTree,
|
||||
);
|
||||
|
||||
setTreeData(updatedTreeData);
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch children:", error);
|
||||
}
|
||||
@ -304,17 +297,17 @@ function Node({ node, style, dragHandle, tree }: NodeRendererProps<any>) {
|
||||
|
||||
const handleEmojiSelect = (emoji: { native: string }) => {
|
||||
handleUpdateNodeIcon(node.id, emoji.native);
|
||||
updatePageMutation.mutateAsync({ pageId: node.id, icon: emoji.native });
|
||||
|
||||
setTimeout(() => {
|
||||
emit({
|
||||
operation: "updateOne",
|
||||
spaceId: node.data.spaceId,
|
||||
entity: ["pages"],
|
||||
id: node.id,
|
||||
payload: { icon: emoji.native },
|
||||
});
|
||||
}, 50);
|
||||
updatePageMutation.mutateAsync({ pageId: node.id, icon: emoji.native }).then((data) => {
|
||||
setTimeout(() => {
|
||||
emit({
|
||||
operation: "updateOne",
|
||||
spaceId: node.data.spaceId,
|
||||
entity: ["pages"],
|
||||
id: node.id,
|
||||
payload: { icon: emoji.native, parentPageId: data.parentPageId},
|
||||
});
|
||||
}, 50);
|
||||
});
|
||||
};
|
||||
|
||||
const handleRemoveEmoji = () => {
|
||||
@ -576,6 +569,12 @@ interface PageArrowProps {
|
||||
}
|
||||
|
||||
function PageArrow({ node, onExpandTree }: PageArrowProps) {
|
||||
useEffect(() => {
|
||||
if(node.isOpen){
|
||||
onExpandTree();
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ActionIcon
|
||||
size={20}
|
||||
|
||||
@ -93,7 +93,7 @@ export function useTreeMutation<T>(spaceId: string) {
|
||||
return data;
|
||||
};
|
||||
|
||||
const onMove: MoveHandler<T> = (args: {
|
||||
const onMove: MoveHandler<T> = async (args: {
|
||||
dragIds: string[];
|
||||
dragNodes: NodeApi<T>[];
|
||||
parentId: string | null;
|
||||
@ -176,7 +176,7 @@ export function useTreeMutation<T>(spaceId: string) {
|
||||
};
|
||||
|
||||
try {
|
||||
movePageMutation.mutateAsync(payload);
|
||||
await movePageMutation.mutateAsync(payload);
|
||||
|
||||
setTimeout(() => {
|
||||
emit({
|
||||
@ -206,6 +206,23 @@ export function useTreeMutation<T>(spaceId: string) {
|
||||
}
|
||||
};
|
||||
|
||||
const isPageInNode = (
|
||||
node: { data: SpaceTreeNode; children?: any[] },
|
||||
pageSlug: string
|
||||
): boolean => {
|
||||
if (node.data.slugId === pageSlug) {
|
||||
return true;
|
||||
}
|
||||
for (const item of node.children) {
|
||||
if (item.data.slugId === pageSlug) {
|
||||
return true;
|
||||
} else {
|
||||
return isPageInNode(item, pageSlug);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const onDelete: DeleteHandler<T> = async (args: { ids: string[] }) => {
|
||||
try {
|
||||
await deletePageMutation.mutateAsync(args.ids[0]);
|
||||
@ -218,8 +235,7 @@ export function useTreeMutation<T>(spaceId: string) {
|
||||
tree.drop({ id: args.ids[0] });
|
||||
setData(tree.data);
|
||||
|
||||
// navigate only if the current url is same as the deleted page
|
||||
if (pageSlug && node.data.slugId === pageSlug.split("-")[1]) {
|
||||
if (pageSlug && isPageInNode(node, pageSlug.split("-")[1])) {
|
||||
navigate(getSpaceUrl(spaceSlug));
|
||||
}
|
||||
|
||||
|
||||
@ -164,16 +164,35 @@ export function appendNodeChildren(
|
||||
nodeId: string,
|
||||
children: SpaceTreeNode[],
|
||||
) {
|
||||
return treeItems.map((nodeItem) => {
|
||||
if (nodeItem.id === nodeId) {
|
||||
return { ...nodeItem, children };
|
||||
}
|
||||
if (nodeItem.children) {
|
||||
// Preserve deeper children if they exist and remove node if deleted
|
||||
return treeItems.map((node) => {
|
||||
if (node.id === nodeId) {
|
||||
const newIds = new Set(children.map(c => c.id));
|
||||
|
||||
const existingMap = new Map(
|
||||
(node.children ?? []).filter(c => newIds.has(c.id)).map(c => [c.id, c])
|
||||
);
|
||||
|
||||
const merged = children.map((newChild) => {
|
||||
const existing = existingMap.get(newChild.id);
|
||||
return existing && existing.children
|
||||
? { ...newChild, children: existing.children }
|
||||
: newChild;
|
||||
});
|
||||
|
||||
return {
|
||||
...nodeItem,
|
||||
children: appendNodeChildren(nodeItem.children, nodeId, children),
|
||||
...node,
|
||||
children: merged,
|
||||
};
|
||||
}
|
||||
return nodeItem;
|
||||
|
||||
if (node.children) {
|
||||
return {
|
||||
...node,
|
||||
children: appendNodeChildren(node.children, nodeId, children),
|
||||
};
|
||||
}
|
||||
|
||||
return node;
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user