mirror of
https://github.com/docmost/docmost.git
synced 2026-05-07 06:23:06 +08:00
fix(tree): update sidebar-pages cache directly instead of refetching on page move (#1870)
This commit is contained in:
@@ -163,9 +163,6 @@ export function useDeletePageMutation() {
|
|||||||
export function useMovePageMutation() {
|
export function useMovePageMutation() {
|
||||||
return useMutation<void, Error, IMovePage>({
|
return useMutation<void, Error, IMovePage>({
|
||||||
mutationFn: (data) => movePage(data),
|
mutationFn: (data) => movePage(data),
|
||||||
onSuccess: () => {
|
|
||||||
invalidateOnMovePage();
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,17 +455,127 @@ export function invalidateOnUpdatePage(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function invalidateOnMovePage() {
|
export function updateCacheOnMovePage(
|
||||||
//for move invalidate all sidebars for now (how to do???)
|
spaceId: string,
|
||||||
//invalidate all root sidebar pages
|
pageId: string,
|
||||||
queryClient.invalidateQueries({
|
oldParentId: string | null,
|
||||||
queryKey: ["root-sidebar-pages"],
|
newParentId: string | null,
|
||||||
});
|
pageData: Partial<IPage>,
|
||||||
//invalidate all sub sidebar pages
|
) {
|
||||||
queryClient.invalidateQueries({
|
// Remove page from old parent's cache
|
||||||
queryKey: ["sidebar-pages"],
|
const oldQueryKey =
|
||||||
});
|
oldParentId === null
|
||||||
// ---
|
? ["root-sidebar-pages", spaceId]
|
||||||
|
: ["sidebar-pages", { pageId: oldParentId, spaceId }];
|
||||||
|
|
||||||
|
queryClient.setQueryData<InfiniteData<IPagination<IPage>>>(
|
||||||
|
oldQueryKey,
|
||||||
|
(old) => {
|
||||||
|
if (!old) return old;
|
||||||
|
return {
|
||||||
|
...old,
|
||||||
|
pages: old.pages.map((page) => ({
|
||||||
|
...page,
|
||||||
|
items: page.items.filter((item) => item.id !== pageId),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update old parent's hasChildren flag if it has no more children
|
||||||
|
if (oldParentId !== null) {
|
||||||
|
const oldParentCache = queryClient.getQueryData<
|
||||||
|
InfiniteData<IPagination<IPage>>
|
||||||
|
>(["sidebar-pages", { pageId: oldParentId, spaceId }]);
|
||||||
|
|
||||||
|
const remainingChildren =
|
||||||
|
oldParentCache?.pages.flatMap((p) => p.items).length ?? 0;
|
||||||
|
|
||||||
|
if (remainingChildren === 0) {
|
||||||
|
// Update hasChildren in all caches where old parent appears
|
||||||
|
const allSideBarMatches = queryClient.getQueriesData({
|
||||||
|
predicate: (query) =>
|
||||||
|
query.queryKey[0] === "root-sidebar-pages" ||
|
||||||
|
query.queryKey[0] === "sidebar-pages",
|
||||||
|
});
|
||||||
|
|
||||||
|
allSideBarMatches.forEach(([key]) => {
|
||||||
|
queryClient.setQueryData<InfiniteData<IPagination<IPage>>>(
|
||||||
|
key,
|
||||||
|
(old) => {
|
||||||
|
if (!old) return old;
|
||||||
|
return {
|
||||||
|
...old,
|
||||||
|
pages: old.pages.map((page) => ({
|
||||||
|
...page,
|
||||||
|
items: page.items.map((item) =>
|
||||||
|
item.id === oldParentId
|
||||||
|
? { ...item, hasChildren: false }
|
||||||
|
: item,
|
||||||
|
),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add page to new parent's cache
|
||||||
|
const newQueryKey =
|
||||||
|
newParentId === null
|
||||||
|
? ["root-sidebar-pages", spaceId]
|
||||||
|
: ["sidebar-pages", { pageId: newParentId, spaceId }];
|
||||||
|
|
||||||
|
queryClient.setQueryData<InfiniteData<IPagination<Partial<IPage>>>>(
|
||||||
|
newQueryKey,
|
||||||
|
(old) => {
|
||||||
|
if (!old) return old;
|
||||||
|
|
||||||
|
// Check if page already exists in new location
|
||||||
|
const exists = old.pages.some((page) =>
|
||||||
|
page.items.some((item) => item.id === pageId),
|
||||||
|
);
|
||||||
|
if (exists) return old;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...old,
|
||||||
|
pages: old.pages.map((page, index) => {
|
||||||
|
if (index === old.pages.length - 1) {
|
||||||
|
return {
|
||||||
|
...page,
|
||||||
|
items: [...page.items, pageData],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update new parent's hasChildren flag
|
||||||
|
if (newParentId !== null) {
|
||||||
|
const allSideBarMatches = queryClient.getQueriesData({
|
||||||
|
predicate: (query) =>
|
||||||
|
query.queryKey[0] === "root-sidebar-pages" ||
|
||||||
|
query.queryKey[0] === "sidebar-pages",
|
||||||
|
});
|
||||||
|
|
||||||
|
allSideBarMatches.forEach(([key]) => {
|
||||||
|
queryClient.setQueryData<InfiniteData<IPagination<IPage>>>(key, (old) => {
|
||||||
|
if (!old) return old;
|
||||||
|
return {
|
||||||
|
...old,
|
||||||
|
pages: old.pages.map((page) => ({
|
||||||
|
...page,
|
||||||
|
items: page.items.map((item) =>
|
||||||
|
item.id === newParentId ? { ...item, hasChildren: true } : item,
|
||||||
|
),
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function invalidateOnDeletePage(pageId: string) {
|
export function invalidateOnDeletePage(pageId: string) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
useRemovePageMutation,
|
useRemovePageMutation,
|
||||||
useMovePageMutation,
|
useMovePageMutation,
|
||||||
useUpdatePageMutation,
|
useUpdatePageMutation,
|
||||||
|
updateCacheOnMovePage,
|
||||||
} from "@/features/page/queries/page-query.ts";
|
} from "@/features/page/queries/page-query.ts";
|
||||||
import { generateJitteredKeyBetween } from "fractional-indexing-jittered";
|
import { generateJitteredKeyBetween } from "fractional-indexing-jittered";
|
||||||
import { SpaceTreeNode } from "@/features/page/tree/types.ts";
|
import { SpaceTreeNode } from "@/features/page/tree/types.ts";
|
||||||
@@ -175,9 +176,25 @@ export function useTreeMutation<T>(spaceId: string) {
|
|||||||
parentPageId: args.parentId,
|
parentPageId: args.parentId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const draggedNode = args.dragNodes[0];
|
||||||
|
const nodeData = draggedNode.data as SpaceTreeNode;
|
||||||
|
const oldParentId = nodeData.parentPageId ?? null;
|
||||||
|
const pageData = {
|
||||||
|
id: nodeData.id,
|
||||||
|
slugId: nodeData.slugId,
|
||||||
|
title: nodeData.name,
|
||||||
|
icon: nodeData.icon,
|
||||||
|
position: newPosition,
|
||||||
|
spaceId: nodeData.spaceId,
|
||||||
|
parentPageId: args.parentId,
|
||||||
|
hasChildren: nodeData.hasChildren,
|
||||||
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await movePageMutation.mutateAsync(payload);
|
await movePageMutation.mutateAsync(payload);
|
||||||
|
|
||||||
|
updateCacheOnMovePage(spaceId, draggedNodeId, oldParentId, args.parentId, pageData);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
emit({
|
emit({
|
||||||
operation: "moveTreeNode",
|
operation: "moveTreeNode",
|
||||||
@@ -185,8 +202,10 @@ export function useTreeMutation<T>(spaceId: string) {
|
|||||||
payload: {
|
payload: {
|
||||||
id: draggedNodeId,
|
id: draggedNodeId,
|
||||||
parentId: args.parentId,
|
parentId: args.parentId,
|
||||||
|
oldParentId,
|
||||||
index: args.index,
|
index: args.index,
|
||||||
position: newPosition,
|
position: newPosition,
|
||||||
|
pageData,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}, 50);
|
}, 50);
|
||||||
|
|||||||
@@ -45,8 +45,10 @@ export type MoveTreeNodeEvent = {
|
|||||||
payload: {
|
payload: {
|
||||||
id: string;
|
id: string;
|
||||||
parentId: string;
|
parentId: string;
|
||||||
|
oldParentId: string | null;
|
||||||
index: number;
|
index: number;
|
||||||
position: string;
|
position: string;
|
||||||
|
pageData: Partial<IPage>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { IPagination } from "@/lib/types";
|
|||||||
import {
|
import {
|
||||||
invalidateOnCreatePage,
|
invalidateOnCreatePage,
|
||||||
invalidateOnDeletePage,
|
invalidateOnDeletePage,
|
||||||
invalidateOnMovePage,
|
updateCacheOnMovePage,
|
||||||
invalidateOnUpdatePage,
|
invalidateOnUpdatePage,
|
||||||
} from "../page/queries/page-query";
|
} from "../page/queries/page-query";
|
||||||
import { RQ_KEY } from "../comment/queries/comment-query";
|
import { RQ_KEY } from "../comment/queries/comment-query";
|
||||||
@@ -41,7 +41,13 @@ export const useQuerySubscription = () => {
|
|||||||
invalidateOnCreatePage(data.payload.data);
|
invalidateOnCreatePage(data.payload.data);
|
||||||
break;
|
break;
|
||||||
case "moveTreeNode":
|
case "moveTreeNode":
|
||||||
invalidateOnMovePage();
|
updateCacheOnMovePage(
|
||||||
|
data.spaceId,
|
||||||
|
data.payload.id,
|
||||||
|
data.payload.oldParentId,
|
||||||
|
data.payload.parentId,
|
||||||
|
data.payload.pageData,
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case "deleteTreeNode":
|
case "deleteTreeNode":
|
||||||
invalidateOnDeletePage(data.payload.node.id);
|
invalidateOnDeletePage(data.payload.node.id);
|
||||||
|
|||||||
Reference in New Issue
Block a user