feat(kernel): finish phase3 bridge cutover and phase4 tree projection
- add generic mnote-web query transport and bridge routes for workspace/request/trace - route sidebar compat traffic through mnote-web and tighten fixture fallback to dev/test - unify sidebar/page tree/file tree/picker consumers on page_tree projection - sync phase3/phase4 checklist, breakdown docs, and harness progress state
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { buildPageTreeProjectionItems } from "@/lib/tree-projection";
|
||||
import { buildVisibleRows } from "./rows";
|
||||
import { parseFileTreeRowId } from "./types";
|
||||
|
||||
@@ -33,7 +34,7 @@ describe("buildVisibleRows", () => {
|
||||
};
|
||||
|
||||
const rows = buildVisibleRows({
|
||||
nodes: [a],
|
||||
pageRows: buildPageTreeProjectionItems([a]),
|
||||
expanded: new Set(["a"]),
|
||||
assetsByDoc: {
|
||||
a: [
|
||||
@@ -108,7 +109,7 @@ describe("buildVisibleRows", () => {
|
||||
};
|
||||
|
||||
const rows = buildVisibleRows({
|
||||
nodes: [a, a],
|
||||
pageRows: buildPageTreeProjectionItems([a, a]),
|
||||
expanded: new Set(["a"]),
|
||||
assetsByDoc: {},
|
||||
});
|
||||
|
||||
@@ -1,55 +1,52 @@
|
||||
"use client";
|
||||
|
||||
import type { SidebarTreeNode } from "@/lib/kernel-sidebar";
|
||||
import type { PageTreeProjectionItem } from "@/lib/tree-projection";
|
||||
import type { MediaAsset } from "@/types/media";
|
||||
import type { FileTreeRow } from "./types";
|
||||
import { makeAssetFolderRowId, makeAssetRowId, makeDocRowId, makeIndexRowId } from "./types";
|
||||
|
||||
export function buildVisibleRows({
|
||||
nodes,
|
||||
pageRows,
|
||||
expanded,
|
||||
assetsByDoc,
|
||||
assetChildrenByAssetId,
|
||||
expandedAssetFolderIds,
|
||||
}: {
|
||||
nodes: SidebarTreeNode[];
|
||||
// 只消费统一 page_tree projection;结构真相不再由文件树自行定义。
|
||||
pageRows: PageTreeProjectionItem[];
|
||||
expanded: Set<string>;
|
||||
assetsByDoc: Record<string, MediaAsset[]>;
|
||||
assetChildrenByAssetId?: Record<string, MediaAsset[]>;
|
||||
expandedAssetFolderIds?: Set<string>;
|
||||
}): FileTreeRow[] {
|
||||
const rows: FileTreeRow[] = [];
|
||||
const visitedDocIds = new Set<string>();
|
||||
|
||||
const walk = (node: SidebarTreeNode, depth: number) => {
|
||||
// 防御性处理:上游数据异常时(例如同一 docId 在树中重复出现),避免生成重复 rowId 导致 React key 冲突。
|
||||
// 同时也能避免潜在的“循环引用/重复引用”导致的递归问题。
|
||||
if (visitedDocIds.has(node.id)) return;
|
||||
visitedDocIds.add(node.id);
|
||||
|
||||
const assets = assetsByDoc[node.id] ?? [];
|
||||
const hasChildren = node.children.length > 0 || assets.length > 0;
|
||||
const isExpanded = expanded.has(node.id);
|
||||
pageRows.forEach((item) => {
|
||||
const assets = assetsByDoc[item.nodeId] ?? [];
|
||||
const hasChildren = item.childCount > 0 || assets.length > 0;
|
||||
const isExpanded = expanded.has(item.nodeId);
|
||||
rows.push({
|
||||
kind: "doc",
|
||||
rowId: makeDocRowId(node.id),
|
||||
depth,
|
||||
docId: node.id,
|
||||
parentDocId: node.parent_id,
|
||||
node,
|
||||
rowId: makeDocRowId(item.nodeId),
|
||||
depth: item.depth,
|
||||
docId: item.nodeId,
|
||||
parentDocId: item.parentNodeId,
|
||||
node: item.node,
|
||||
hasChildren,
|
||||
isExpanded,
|
||||
});
|
||||
|
||||
if (!isExpanded) return;
|
||||
if (!isExpanded) {
|
||||
return;
|
||||
}
|
||||
|
||||
rows.push({
|
||||
kind: "index",
|
||||
rowId: makeIndexRowId(node.id),
|
||||
depth: depth + 1,
|
||||
docId: node.id,
|
||||
parentDocId: node.id,
|
||||
node,
|
||||
rowId: makeIndexRowId(item.nodeId),
|
||||
depth: item.depth + 1,
|
||||
docId: item.nodeId,
|
||||
parentDocId: item.nodeId,
|
||||
node: item.node,
|
||||
});
|
||||
|
||||
assets.forEach((asset) => {
|
||||
@@ -60,9 +57,9 @@ export function buildVisibleRows({
|
||||
rows.push({
|
||||
kind: "asset-folder",
|
||||
rowId: makeAssetFolderRowId(asset.id),
|
||||
depth: depth + 1,
|
||||
docId: node.id,
|
||||
parentDocId: node.id,
|
||||
depth: item.depth + 1,
|
||||
docId: item.nodeId,
|
||||
parentDocId: item.nodeId,
|
||||
asset,
|
||||
hasChildren,
|
||||
isExpanded,
|
||||
@@ -72,9 +69,9 @@ export function buildVisibleRows({
|
||||
rows.push({
|
||||
kind: "asset",
|
||||
rowId: makeAssetRowId(child.id),
|
||||
depth: depth + 2,
|
||||
docId: node.id,
|
||||
parentDocId: node.id,
|
||||
depth: item.depth + 2,
|
||||
docId: item.nodeId,
|
||||
parentDocId: item.nodeId,
|
||||
asset: child,
|
||||
});
|
||||
});
|
||||
@@ -85,16 +82,12 @@ export function buildVisibleRows({
|
||||
rows.push({
|
||||
kind: "asset",
|
||||
rowId: makeAssetRowId(asset.id),
|
||||
depth: depth + 1,
|
||||
docId: node.id,
|
||||
parentDocId: node.id,
|
||||
depth: item.depth + 1,
|
||||
docId: item.nodeId,
|
||||
parentDocId: item.nodeId,
|
||||
asset,
|
||||
});
|
||||
});
|
||||
|
||||
node.children.forEach((child) => walk(child, depth + 1));
|
||||
};
|
||||
|
||||
nodes.forEach((node) => walk(node, 0));
|
||||
});
|
||||
return rows;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user