mirror of
https://github.com/docmost/docmost.git
synced 2026-05-21 09:14:07 +08:00
fix tree
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
.row {
|
.row {
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: var(--mantine-spacing-sm);
|
gap: var(--mantine-spacing-sm);
|
||||||
@@ -38,12 +39,21 @@
|
|||||||
color: light-dark(var(--mantine-color-gray-6), var(--mantine-color-dark-2));
|
color: light-dark(var(--mantine-color-gray-6), var(--mantine-color-dark-2));
|
||||||
font-size: var(--mantine-font-size-xs);
|
font-size: var(--mantine-font-size-xs);
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
transition: opacity 100ms ease;
|
||||||
|
|
||||||
|
.row:hover &,
|
||||||
|
.row:focus-within & {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.useButton {
|
.useButton {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: var(--mantine-spacing-sm);
|
||||||
|
transform: translateY(-50%);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: opacity 100ms ease;
|
transition: opacity 100ms ease;
|
||||||
flex-shrink: 0;
|
|
||||||
|
|
||||||
.row:hover &,
|
.row:hover &,
|
||||||
.row:focus-within &,
|
.row:focus-within &,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
UseQueryResult,
|
UseQueryResult,
|
||||||
InfiniteData,
|
InfiniteData,
|
||||||
} from "@tanstack/react-query";
|
} from "@tanstack/react-query";
|
||||||
|
import { useAtom, useStore } from "jotai";
|
||||||
import {
|
import {
|
||||||
getTemplates,
|
getTemplates,
|
||||||
getTemplateById,
|
getTemplateById,
|
||||||
@@ -18,6 +19,12 @@ import { ITemplate } from "@/ee/template/types/template.types";
|
|||||||
import { IPagination } from "@/lib/types.ts";
|
import { IPagination } from "@/lib/types.ts";
|
||||||
import { notifications } from "@mantine/notifications";
|
import { notifications } from "@mantine/notifications";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { invalidateOnCreatePage } from "@/features/page/queries/page-query.ts";
|
||||||
|
import { treeDataAtom } from "@/features/page/tree/atoms/tree-data-atom.ts";
|
||||||
|
import { treeModel } from "@/features/page/tree/model/tree-model";
|
||||||
|
import { SpaceTreeNode } from "@/features/page/tree/types.ts";
|
||||||
|
import { IPage } from "@/features/page/types/page.types.ts";
|
||||||
|
import { useQueryEmit } from "@/features/websocket/use-query-emit.ts";
|
||||||
|
|
||||||
export function useGetTemplatesQuery(params?: { spaceId?: string }) {
|
export function useGetTemplatesQuery(params?: { spaceId?: string }) {
|
||||||
const { spaceId } = params ?? {};
|
const { spaceId } = params ?? {};
|
||||||
@@ -149,13 +156,64 @@ export function useDeleteTemplateMutation() {
|
|||||||
|
|
||||||
export function useUseTemplateMutation() {
|
export function useUseTemplateMutation() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const [, setTreeData] = useAtom(treeDataAtom);
|
||||||
|
const store = useStore();
|
||||||
|
const emit = useQueryEmit();
|
||||||
|
|
||||||
return useMutation({
|
return useMutation<
|
||||||
mutationFn: (data: {
|
IPage,
|
||||||
templateId: string;
|
Error,
|
||||||
spaceId: string;
|
{ templateId: string; spaceId: string; parentPageId?: string }
|
||||||
parentPageId?: string;
|
>({
|
||||||
}) => useTemplate(data),
|
mutationFn: (data) => useTemplate(data),
|
||||||
|
onSuccess: (page) => {
|
||||||
|
// React Query sidebar-pages cache update (same path useCreatePageMutation takes).
|
||||||
|
invalidateOnCreatePage(page);
|
||||||
|
|
||||||
|
const parentId = page.parentPageId ?? null;
|
||||||
|
const newNode: SpaceTreeNode = {
|
||||||
|
id: page.id,
|
||||||
|
slugId: page.slugId,
|
||||||
|
name: page.title,
|
||||||
|
icon: page.icon,
|
||||||
|
position: page.position,
|
||||||
|
spaceId: page.spaceId,
|
||||||
|
parentPageId: page.parentPageId,
|
||||||
|
hasChildren: false,
|
||||||
|
children: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Only mutate the tree atom and broadcast if it currently represents
|
||||||
|
// this space. Cross-space template-use (e.g., from the gallery picking
|
||||||
|
// a different space) lets the target space's clients pick up the new
|
||||||
|
// page on their next React Query refetch (focus, navigation, etc.).
|
||||||
|
// Without this guard we'd both pollute the local tree and send a wrong
|
||||||
|
// `index` to remote clients in the target space.
|
||||||
|
const current = store.get(treeDataAtom);
|
||||||
|
const treeIsForThisSpace = current[0]?.spaceId === page.spaceId;
|
||||||
|
if (!treeIsForThisSpace) return;
|
||||||
|
|
||||||
|
const lastIndex =
|
||||||
|
parentId === null
|
||||||
|
? current.length
|
||||||
|
: (treeModel.find(current, parentId)?.children?.length ?? 0);
|
||||||
|
|
||||||
|
setTreeData((prev) =>
|
||||||
|
treeModel.insert(prev, parentId, newNode, lastIndex),
|
||||||
|
);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
emit({
|
||||||
|
operation: "addTreeNode",
|
||||||
|
spaceId: page.spaceId,
|
||||||
|
payload: {
|
||||||
|
parentId,
|
||||||
|
index: lastIndex,
|
||||||
|
data: newNode,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}, 50);
|
||||||
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
const errorMessage = error["response"]?.data?.message;
|
const errorMessage = error["response"]?.data?.message;
|
||||||
notifications.show({
|
notifications.show({
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import api from "@/lib/api-client";
|
import api from "@/lib/api-client";
|
||||||
import { ITemplate } from "@/ee/template/types/template.types";
|
import { ITemplate } from "@/ee/template/types/template.types";
|
||||||
|
import { IPage } from "@/features/page/types/page.types";
|
||||||
import { IPagination } from "@/lib/types.ts";
|
import { IPagination } from "@/lib/types.ts";
|
||||||
|
|
||||||
export async function getTemplates(params?: {
|
export async function getTemplates(params?: {
|
||||||
@@ -40,7 +41,7 @@ export async function useTemplate(data: {
|
|||||||
templateId: string;
|
templateId: string;
|
||||||
spaceId: string;
|
spaceId: string;
|
||||||
parentPageId?: string;
|
parentPageId?: string;
|
||||||
}): Promise<any> {
|
}): Promise<IPage> {
|
||||||
const req = await api.post("/templates/use", data);
|
const req = await api.post<IPage>("/templates/use", data);
|
||||||
return req.data;
|
return req.data;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user