feat: 收口 tree-first graph 主链与前端测试修复

This commit is contained in:
lix-2026
2026-04-18 05:43:49 +08:00
parent d8de820d93
commit d3876e56eb
33 changed files with 2421 additions and 345 deletions
+38 -16
View File
@@ -1,7 +1,7 @@
import type { SidebarInitialData } from "@/components/sidebar/types";
import type { DocumentRecord } from "@/lib/documents";
import {
buildKernelSidebarProjection,
buildKernelSidebarProjection as buildProjectionContract,
buildSidebarTreeFromKernelProjection,
type KernelSidebarProjection,
} from "@/lib/kernel-sidebar";
@@ -64,6 +64,41 @@ export type SidebarDatasetListQueryResult = {
mindmap_asset_children: Record<string, string[]>;
};
const EMPTY_KERNEL_SIDEBAR_PROJECTION: KernelSidebarProjection = {
projectionId: "kernel_projection:sidebar_tree:missing",
projection: "sidebar_tree",
rootNodeId: null,
items: [],
edges: [],
};
function isKernelSidebarProjection(value: unknown): value is KernelSidebarProjection {
return (
Boolean(value) &&
typeof value === "object" &&
Array.isArray((value as KernelSidebarProjection).items) &&
Array.isArray((value as KernelSidebarProjection).edges)
);
}
function readKernelSidebarProjection(
result: SidebarDatasetListQueryResult,
): KernelSidebarProjection {
const snakeCaseProjection =
"kernel_sidebar_projection" in result ? result.kernel_sidebar_projection : undefined;
if (isKernelSidebarProjection(snakeCaseProjection)) {
return snakeCaseProjection;
}
const camelCaseProjection =
"kernelSidebarProjection" in result ? result.kernelSidebarProjection : undefined;
if (isKernelSidebarProjection(camelCaseProjection)) {
return camelCaseProjection;
}
return EMPTY_KERNEL_SIDEBAR_PROJECTION;
}
function normalizeStringArray(values: Iterable<string>): string[] {
return Array.from(new Set(values)).filter((value) => value.trim().length > 0);
}
@@ -220,7 +255,7 @@ export function buildSidebarDatasetListQueryResult(
input: SidebarDatasetInput,
): SidebarDatasetListQueryResult {
const derived = deriveSidebarDataset(input);
const kernelSidebarProjection = buildKernelSidebarProjection(input.documents);
const kernelSidebarProjection = buildProjectionContract(input.documents);
return {
active_workspace_id: input.activeWorkspaceId,
@@ -242,20 +277,7 @@ export function buildSidebarDatasetListQueryResult(
export function mapSidebarDatasetListQueryResultToInitialData(
result: SidebarDatasetListQueryResult,
): SidebarInitialData {
// 说明:兼容旧的 Convex `sidebar.dataset.list` 返回体。
// 若上游暂未附带 `kernel_sidebar_projection`,这里按 documents 现算一份,
// 避免 SSR 因契约未完全切齐而直接崩掉。
const candidateProjection =
result.kernel_sidebar_projection ??
result.kernelSidebarProjection ??
null;
const kernelSidebarProjection =
candidateProjection &&
typeof candidateProjection === "object" &&
Array.isArray(candidateProjection.items) &&
Array.isArray(candidateProjection.edges)
? candidateProjection
: buildKernelSidebarProjection(result.documents ?? []);
const kernelSidebarProjection = readKernelSidebarProjection(result);
return {
activeWorkspaceId: result.active_workspace_id,