mirror of
https://github.com/docmost/docmost.git
synced 2025-11-16 23:41:09 +10:00
fix: improve sidebar page tree syncing (#407)
* sync node deletion * tree sync improvements * fix cache bug * fix debounced page title * fix
This commit is contained in:
@ -1,3 +1,5 @@
|
||||
import { SpaceTreeNode } from "@/features/page/tree/types.ts";
|
||||
|
||||
export type InvalidateEvent = {
|
||||
operation: "invalidate";
|
||||
entity: Array<string>;
|
||||
@ -11,4 +13,37 @@ export type UpdateEvent = {
|
||||
payload: Partial<any>;
|
||||
};
|
||||
|
||||
export type WebSocketEvent = InvalidateEvent | UpdateEvent;
|
||||
export type DeleteEvent = {
|
||||
operation: "deleteOne";
|
||||
entity: Array<string>;
|
||||
id: string;
|
||||
payload?: Partial<any>;
|
||||
};
|
||||
|
||||
export type AddTreeNodeEvent = {
|
||||
operation: "addTreeNode";
|
||||
payload: {
|
||||
parentId: string;
|
||||
index: number;
|
||||
data: SpaceTreeNode;
|
||||
};
|
||||
};
|
||||
|
||||
export type MoveTreeNodeEvent = {
|
||||
operation: "moveTreeNode";
|
||||
payload: {
|
||||
id: string;
|
||||
parentId: string;
|
||||
index: number;
|
||||
position: string;
|
||||
}
|
||||
};
|
||||
|
||||
export type DeleteTreeNodeEvent = {
|
||||
operation: "deleteTreeNode";
|
||||
payload: {
|
||||
node: SpaceTreeNode
|
||||
}
|
||||
};
|
||||
|
||||
export type WebSocketEvent = InvalidateEvent | UpdateEvent | DeleteEvent | AddTreeNodeEvent | MoveTreeNodeEvent | DeleteTreeNodeEvent;
|
||||
|
||||
@ -30,10 +30,13 @@ export const useQuerySubscription = () => {
|
||||
queryKeyId = data.id;
|
||||
}
|
||||
|
||||
queryClient.setQueryData([...data.entity, queryKeyId], {
|
||||
...queryClient.getQueryData([...data.entity, queryKeyId]),
|
||||
...data.payload,
|
||||
});
|
||||
// only update if data was already in cache
|
||||
if(queryClient.getQueryData([...data.entity, queryKeyId])){
|
||||
queryClient.setQueryData([...data.entity, queryKeyId], {
|
||||
...queryClient.getQueryData([...data.entity, queryKeyId]),
|
||||
...data.payload,
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
queryClient.setQueriesData(
|
||||
|
||||
@ -2,17 +2,15 @@ import { useEffect, useRef } from "react";
|
||||
import { socketAtom } from "@/features/websocket/atoms/socket-atom.ts";
|
||||
import { useAtom } from "jotai";
|
||||
import { treeDataAtom } from "@/features/page/tree/atoms/tree-data-atom.ts";
|
||||
import {
|
||||
updateTreeNodeIcon,
|
||||
updateTreeNodeName,
|
||||
} from "@/features/page/tree/utils";
|
||||
import { WebSocketEvent } from "@/features/websocket/types";
|
||||
import { SpaceTreeNode } from "@/features/page/tree/types.ts";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { SimpleTree } from "react-arborist";
|
||||
|
||||
export const useTreeSocket = () => {
|
||||
const [socket] = useAtom(socketAtom);
|
||||
const [treeData, setTreeData] = useAtom(treeDataAtom);
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const initialTreeData = useRef(treeData);
|
||||
|
||||
useEffect(() => {
|
||||
@ -20,42 +18,59 @@ export const useTreeSocket = () => {
|
||||
}, [treeData]);
|
||||
|
||||
useEffect(() => {
|
||||
socket?.on("message", (event) => {
|
||||
const data: WebSocketEvent = event;
|
||||
socket?.on("message", (event: WebSocketEvent) => {
|
||||
|
||||
const initialData = initialTreeData.current;
|
||||
switch (data.operation) {
|
||||
case "invalidate":
|
||||
// nothing to do here
|
||||
break;
|
||||
const treeApi = new SimpleTree<SpaceTreeNode>(initialData);
|
||||
|
||||
switch (event.operation) {
|
||||
case "updateOne":
|
||||
// Get the initial value of treeData
|
||||
if (initialData && initialData.length > 0) {
|
||||
let newTreeData: SpaceTreeNode[];
|
||||
|
||||
if (data.entity[0] === "pages") {
|
||||
if (data.payload?.title !== undefined) {
|
||||
newTreeData = updateTreeNodeName(
|
||||
initialData,
|
||||
data.id,
|
||||
data.payload.title,
|
||||
);
|
||||
if (event.entity[0] === "pages") {
|
||||
if (treeApi.find(event.id)) {
|
||||
if (event.payload?.title) {
|
||||
treeApi.update({ id: event.id, changes: { name: event.payload.title } });
|
||||
}
|
||||
|
||||
if (data.payload?.icon !== undefined) {
|
||||
newTreeData = updateTreeNodeIcon(
|
||||
initialData,
|
||||
data.id,
|
||||
data.payload.icon,
|
||||
);
|
||||
}
|
||||
|
||||
if (newTreeData && newTreeData.length > 0) {
|
||||
setTreeData(newTreeData);
|
||||
if (event.payload?.icon) {
|
||||
treeApi.update({ id: event.id, changes: { icon: event.payload.icon } });
|
||||
}
|
||||
setTreeData(treeApi.data);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'addTreeNode':
|
||||
if (treeApi.find(event.payload.data.id)) return;
|
||||
|
||||
treeApi.create({ parentId: event.payload.parentId, index: event.payload.index, data: event.payload.data });
|
||||
setTreeData(treeApi.data);
|
||||
|
||||
break;
|
||||
case 'moveTreeNode':
|
||||
// move node
|
||||
treeApi.move({
|
||||
id: event.payload.id,
|
||||
parentId: event.payload.parentId,
|
||||
index: event.payload.index
|
||||
});
|
||||
|
||||
// update node position
|
||||
treeApi.update({
|
||||
id: event.payload.id,
|
||||
changes: {
|
||||
position: event.payload.position,
|
||||
}
|
||||
});
|
||||
|
||||
setTreeData(treeApi.data);
|
||||
|
||||
break;
|
||||
case "deleteTreeNode":
|
||||
treeApi.drop({ id: event.payload.node.id });
|
||||
setTreeData(treeApi.data);
|
||||
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['pages', event.payload.node.slugId].filter(Boolean),
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
}, [socket]);
|
||||
|
||||
Reference in New Issue
Block a user