feat: 收口 mindmap Phase 6 Leptos UI shell

This commit is contained in:
lix-2026
2026-05-11 12:27:40 +08:00
parent b7dddd2a66
commit b5eb27fabc
51 changed files with 8669 additions and 1313 deletions
@@ -25,6 +25,14 @@ export async function GET(
{ params }: { params: Promise<{ docId: string; mindmapId: string }> },
) {
const { docId, mindmapId } = await params;
const url = new URL(request.url);
const view = url.searchParams.get("view");
const queryName =
view === "simple_mind_map_scene" || url.searchParams.get("queryName") === "mindmap.simple_mind_map_scene.get"
? "mindmap.simple_mind_map_scene.get"
: view === "editor_scene"
? "mindmap.editor_scene.get"
: "mindmaps.get";
if (isConvexEnabled()) {
const { auth, client } = await getAuthedConvexClient();
@@ -43,11 +51,12 @@ export async function GET(
},
});
const envelope = buildDocumentQueryEnvelope({
name: "mindmaps.get",
name: queryName,
payload: {
documentId: docId,
mindmapId,
workspaceId: null,
rootNodeId: url.searchParams.get("rootNodeId"),
},
});
const plan = await resolveRustBridgeQueryPlan({ context, envelope });
@@ -65,6 +74,9 @@ export async function GET(
client,
plan,
});
if (queryName === "mindmap.simple_mind_map_scene.get" || queryName === "mindmap.editor_scene.get") {
return NextResponse.json(res);
}
return NextResponse.json({
data: res?.data ?? defaultMindmapData,
source: "convex",
@@ -97,9 +109,12 @@ export async function POST(
if (isConvexEnabled()) {
const { auth, client } = await getAuthedConvexClient();
const { data, createOnly } = (await request.json().catch(() => ({ data: null }))) as {
const { data, createOnly, commandName, commands, projectionRevision } = (await request.json().catch(() => ({ data: null }))) as {
data?: unknown;
createOnly?: boolean;
commandName?: string;
commands?: unknown[];
projectionRevision?: number | null;
};
try {
@@ -116,22 +131,31 @@ export async function POST(
client: "wolai-frontend",
},
});
const isCommandApply = commandName === "mindmap.command.apply";
const envelope = buildDocumentCommandEnvelope({
name: "mindmaps.put",
payload: {
documentId: docId,
mindmapId,
data: data ?? defaultMindmapData,
createOnly: typeof createOnly === "boolean" ? createOnly : false,
},
name: isCommandApply ? "mindmap.command.apply" : "mindmaps.put",
payload: isCommandApply
? {
documentId: docId,
mindmapId,
workspaceId: null,
commands: Array.isArray(commands) ? commands : [],
projectionRevision: typeof projectionRevision === "number" ? projectionRevision : null,
}
: {
documentId: docId,
mindmapId,
data: data ?? defaultMindmapData,
createOnly: typeof createOnly === "boolean" ? createOnly : false,
},
context,
target: {
workspaceId: null,
pageId: docId,
blockId: mindmapId,
},
reason: "mindmap-route:put",
refs: ["task-032", "mindmap-route"],
reason: isCommandApply ? "mindmap-route:command-apply" : "mindmap-route:put",
refs: isCommandApply ? ["task-166", "mindmap-command-bridge"] : ["task-032", "mindmap-route"],
});
const plan = await resolveRustBridgeCommandPlan({ context, envelope });
const result = await executeRustBridgeMutationTransport<{
@@ -1,30 +0,0 @@
"use client";
import { MindmapBlockView, defaultMindmapData } from "@/components/editor/blocks/MindmapBlock";
import type { BlockNoteEditor } from "@blocknote/core";
import type { CustomBlockSchema } from "@/components/editor/schema";
const stubBlock = {
id: "dev-mindmap",
type: "mindmap",
props: {
docId: "dev",
data: defaultMindmapData,
},
content: [],
children: [],
} as any;
const editorStub = {
updateBlock: () => {
/* 开发沙盒中跳过持久化 */
},
} as unknown as BlockNoteEditor<CustomBlockSchema>;
export default function MindmapDevPage() {
return (
<div className="fixed inset-0 bg-white">
<MindmapBlockView block={stubBlock} editor={editorStub} fullscreen />
</div>
);
}
@@ -7,31 +7,41 @@ import {
buildMindmapProjection,
defaultMindmapData,
type MindmapProjection,
type MindmapSimpleMindMapScene,
} from "@/lib/mindmap/mindmap-projection";
import MindmapPageClient from "./mindmap-page-client";
type MindmapRouteQueryResult = {
data?: unknown;
meta?: unknown;
};
export const MINDMAP_PAGE_LEGACY_COMPAT_CONTRACT = {
shellOwner: "mnote-web",
runtimeRole: "legacy_compat_island",
island: "mindmap_runtime",
runtimeRole: "simple_mind_map_adapter",
island: "leptos_mindmap_adapter",
projectionQueryName: "mindmap.simple_mind_map_scene.get",
commandName: "mindmap.command.apply",
} as const;
async function fetchMindmapProjectionOnServer(input: {
async function fetchMindmapAdapterProjectionOnServer(input: {
docId: string;
mindmapId: string;
}): Promise<MindmapProjection | null> {
}): Promise<MindmapSimpleMindMapScene | null> {
if (!isConvexEnabled()) {
return buildMindmapProjection({
return {
schema: "mnote.mindmap.simple_mind_map_scene.v1",
runtime: "simple-mind-map",
documentId: input.docId,
mindmapId: input.mindmapId,
data: defaultMindmapData,
rootNodeId: null,
root: defaultMindmapData,
layout: "logicalStructure",
theme: "classic",
themeConfig: {},
view: {},
config: {},
compatPayload: { source: "compat-blob", mindmapId: input.mindmapId },
kernelRevision: 1,
source: "compat-blob",
owner: "rust-kernel",
meta: null,
});
};
}
try {
@@ -63,7 +73,7 @@ async function fetchMindmapProjectionOnServer(input: {
workspaceId: null,
});
const envelope = buildDocumentQueryEnvelope({
name: "mindmaps.get",
name: MINDMAP_PAGE_LEGACY_COMPAT_CONTRACT.projectionQueryName,
payload: {
documentId: input.docId,
mindmapId: input.mindmapId,
@@ -74,43 +84,70 @@ async function fetchMindmapProjectionOnServer(input: {
context,
envelope,
});
const result = await executeRustBridgeQueryTransport<MindmapRouteQueryResult | null>({
const result = await executeRustBridgeQueryTransport<MindmapSimpleMindMapScene | null>({
client,
plan,
});
return buildMindmapProjection({
documentId: input.docId,
mindmapId: input.mindmapId,
data: result?.data ?? defaultMindmapData,
meta: result?.meta ?? {
requestId: context.requestId,
traceId: context.traceId,
workspaceId: context.workspaceId,
documentId: input.docId,
pageId: input.docId,
mindmapId: input.mindmapId,
attachmentId: input.mindmapId,
},
});
return result
? {
...result,
source: result.source ?? "compat-blob",
owner: result.owner ?? "rust-kernel",
meta: result.meta ?? {
requestId: context.requestId,
traceId: context.traceId,
workspaceId: context.workspaceId,
documentId: input.docId,
pageId: input.docId,
mindmapId: input.mindmapId,
attachmentId: input.mindmapId,
},
}
: null;
} catch {
return null;
}
}
function buildStandaloneProjectionFromAdapter(input: {
docId: string;
mindmapId: string;
adapterProjection: MindmapSimpleMindMapScene | null;
}): MindmapProjection | null {
if (!input.adapterProjection) return null;
return buildMindmapProjection({
documentId: input.docId,
mindmapId: input.mindmapId,
data: input.adapterProjection.root ?? defaultMindmapData,
source: input.adapterProjection.source ?? "compat-blob",
owner: input.adapterProjection.owner ?? "rust-kernel",
meta: input.adapterProjection.meta,
});
}
export default async function MindmapFullscreenPage({
params,
}: {
params: Promise<{ docId: string; mindmapId: string }>;
}) {
const { docId, mindmapId } = await params;
const initialProjection = await fetchMindmapProjectionOnServer({ docId, mindmapId });
const initialAdapterProjection = await fetchMindmapAdapterProjectionOnServer({ docId, mindmapId });
const initialProjection = buildStandaloneProjectionFromAdapter({
docId,
mindmapId,
adapterProjection: initialAdapterProjection,
});
return (
<main
data-react-island={MINDMAP_PAGE_LEGACY_COMPAT_CONTRACT.island}
data-leptos-mindmap-island={MINDMAP_PAGE_LEGACY_COMPAT_CONTRACT.island}
data-runtime-role={MINDMAP_PAGE_LEGACY_COMPAT_CONTRACT.runtimeRole}
data-shell-owner={MINDMAP_PAGE_LEGACY_COMPAT_CONTRACT.shellOwner}
data-projection-query={MINDMAP_PAGE_LEGACY_COMPAT_CONTRACT.projectionQueryName}
data-command-name={MINDMAP_PAGE_LEGACY_COMPAT_CONTRACT.commandName}
data-adapter-source={initialAdapterProjection?.source ?? "compat-blob"}
data-kernel-revision={initialAdapterProjection?.kernelRevision ?? 1}
>
<MindmapPageClient
docId={docId}