chore: 收口 review 执行清单与 runtime 验证
- 补齐 design/10-review 执行清单、验收标准与相关设计治理记录 - 迁移已完成的 tree、mindmap、runtime fallback、AI kernel 等设计和缺陷条目 - 推进 Rust Web runtime、tree/sidebar、page aggregate、mindmap 与 OnlyOffice 路由侧验证支撑 - 增加 task177-task180 smoke/audit 脚本及前端相关测试覆盖
This commit is contained in:
@@ -2814,13 +2814,17 @@ fn build_tree_shell_html(
|
||||
}
|
||||
if (sourceKind === "convex_workspace") {
|
||||
for (const item of deletableItems) {
|
||||
const documentId = getFileTreeRowDocumentId(item);
|
||||
await sendCommand({
|
||||
action: "delete",
|
||||
workspaceId,
|
||||
documentId: getFileTreeRowDocumentId(item),
|
||||
documentId,
|
||||
});
|
||||
applyRemovedDocumentLocally(documentId);
|
||||
}
|
||||
if (!deletableItems.every((item) => !fileTreeRowById.has(item.rowId))) {
|
||||
scheduleRefresh();
|
||||
}
|
||||
scheduleRefresh();
|
||||
return true;
|
||||
}
|
||||
postToHost("tree.filetree.delete", {
|
||||
@@ -2986,6 +2990,113 @@ fn build_tree_shell_html(
|
||||
}, 80);
|
||||
};
|
||||
|
||||
const addTreeItemLocally = (item) => {
|
||||
if (!item?.nodeId || itemById.has(item.nodeId)) return false;
|
||||
normalizedItems.push(item);
|
||||
itemById.set(item.nodeId, item);
|
||||
fileTreeRowById.set(item.rowId, item);
|
||||
const parentId = item.parentNodeId && itemById.has(item.parentNodeId) ? item.parentNodeId : null;
|
||||
if (parentId) {
|
||||
const bucket = childrenByParentId.get(parentId) || [];
|
||||
bucket.push(item);
|
||||
bucket.sort(compareItems);
|
||||
childrenByParentId.set(parentId, bucket);
|
||||
const parentItem = itemById.get(parentId);
|
||||
if (parentItem) parentItem.childCount = Math.max(parentItem.childCount || 0, bucket.length);
|
||||
expanded.add(parentId);
|
||||
} else {
|
||||
roots.push(item);
|
||||
roots.sort(compareItems);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const applyCreatedDocumentLocally = (result, parentId, title) => {
|
||||
const documentId =
|
||||
typeof result?.documentId === "string" && result.documentId.trim()
|
||||
? result.documentId.trim()
|
||||
: typeof result?.id === "string" && result.id.trim()
|
||||
? result.id.trim()
|
||||
: "";
|
||||
if (!documentId) return false;
|
||||
const createdAt = normalizeText(result?.updatedAt || result?.execution?.updated_at);
|
||||
const parentNodeId = parentId && itemById.has(parentId) ? parentId : null;
|
||||
const item = {
|
||||
rowId: `doc:${documentId}`,
|
||||
rowKind: "document",
|
||||
nodeId: documentId,
|
||||
parentNodeId,
|
||||
title: normalizeText(result?.title, title || "无标题"),
|
||||
depth: parentNodeId ? normalizeNumber(itemById.get(parentNodeId)?.depth, 0) + 1 : 0,
|
||||
childCount: 0,
|
||||
position: normalizeNumber(result?.sortOrder ?? result?.execution?.sort_order ?? Date.now()),
|
||||
expandedByDefault: true,
|
||||
iconHint: "page",
|
||||
capabilities: ["open", "rename", "delete", "move", "create"],
|
||||
resourceMeta: {
|
||||
resourceKind: "document",
|
||||
documentId,
|
||||
assetId: "",
|
||||
assetKind: "",
|
||||
objectIdentity: { objectKind: "page", documentId, blockId: null, assetId: null },
|
||||
blockAssetRelation: null,
|
||||
},
|
||||
updatedAt: createdAt,
|
||||
};
|
||||
if (!addTreeItemLocally(item)) return false;
|
||||
currentFocusedDocumentId = documentId;
|
||||
focusedNodeId = documentId;
|
||||
currentActiveDocumentId = documentId;
|
||||
renderTree();
|
||||
return true;
|
||||
};
|
||||
|
||||
const removeTreeItemEverywhere = (item) => {
|
||||
if (!item) return;
|
||||
const itemIndex = normalizedItems.indexOf(item);
|
||||
if (itemIndex >= 0) normalizedItems.splice(itemIndex, 1);
|
||||
itemById.delete(item.nodeId);
|
||||
fileTreeRowById.delete(item.rowId);
|
||||
const rootIndex = roots.indexOf(item);
|
||||
if (rootIndex >= 0) roots.splice(rootIndex, 1);
|
||||
const bucket = item.parentNodeId ? childrenByParentId.get(item.parentNodeId) : null;
|
||||
if (bucket) {
|
||||
const bucketIndex = bucket.indexOf(item);
|
||||
if (bucketIndex >= 0) bucket.splice(bucketIndex, 1);
|
||||
if (bucket.length === 0) childrenByParentId.delete(item.parentNodeId);
|
||||
}
|
||||
};
|
||||
|
||||
const applyRemovedDocumentLocally = (documentId) => {
|
||||
const normalizedDocumentId = normalizeText(documentId);
|
||||
if (!normalizedDocumentId) return false;
|
||||
const removedNodeIds = new Set([normalizedDocumentId]);
|
||||
let changed = false;
|
||||
let expandedDuringScan = true;
|
||||
while (expandedDuringScan) {
|
||||
expandedDuringScan = false;
|
||||
normalizedItems.forEach((item) => {
|
||||
if (item.parentNodeId && removedNodeIds.has(item.parentNodeId) && !removedNodeIds.has(item.nodeId)) {
|
||||
removedNodeIds.add(item.nodeId);
|
||||
expandedDuringScan = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
normalizedItems.slice().forEach((item) => {
|
||||
const itemDocumentId = getFileTreeRowDocumentId(item) || item.resourceMeta?.documentId || item.nodeId;
|
||||
if (removedNodeIds.has(item.nodeId) || itemDocumentId === normalizedDocumentId) {
|
||||
removeTreeItemEverywhere(item);
|
||||
changed = true;
|
||||
}
|
||||
});
|
||||
if (!changed) return false;
|
||||
if (currentActiveDocumentId === normalizedDocumentId) currentActiveDocumentId = roots[0]?.nodeId || "";
|
||||
if (currentFocusedDocumentId === normalizedDocumentId) currentFocusedDocumentId = currentActiveDocumentId;
|
||||
focusedNodeId = resolveFocusedNodeIdFromHostState();
|
||||
renderTree();
|
||||
return true;
|
||||
};
|
||||
|
||||
if (sourceKind === "local_folder" && rootUri) {
|
||||
let localWatchRevision = initialLocalWatchRevision;
|
||||
let localWatchRefreshTimer = 0;
|
||||
@@ -4335,6 +4446,14 @@ fn build_tree_shell_html(
|
||||
payload: { documentId },
|
||||
});
|
||||
}
|
||||
if (sourceKind === "convex_workspace" && applyCreatedDocumentLocally(result, parentId, title)) {
|
||||
if (mode === "filetree") {
|
||||
beginInlineRename("filetree", `doc:${documentId}`);
|
||||
} else {
|
||||
beginInlineRename("page", documentId);
|
||||
}
|
||||
return;
|
||||
}
|
||||
scheduleRefresh({
|
||||
renameRowId: localCreatedRowIdFromCommandResult(result, "markdown"),
|
||||
});
|
||||
@@ -6688,6 +6807,10 @@ mod tests {
|
||||
assert!(html.contains("data-testid=\"tree-node-toggle\""));
|
||||
assert!(html.contains("hydrateInitialPageTree"));
|
||||
assert!(html.contains("const usedRustInitialPageRenderer = hydrateInitialPageTree();"));
|
||||
assert!(html.contains("applyCreatedDocumentLocally"));
|
||||
assert!(html.contains("applyRemovedDocumentLocally"));
|
||||
assert!(html.contains("sourceKind === \"convex_workspace\" && applyCreatedDocumentLocally"));
|
||||
assert!(html.contains("if (!deletableItems.every((item) => !fileTreeRowById.has(item.rowId)))"));
|
||||
assert!(html.contains("application/x-mnote-page-tree-node"));
|
||||
assert!(html.contains("页面已拖放到"));
|
||||
assert!(html.contains("setAttribute(\"role\", \"treeitem\")"));
|
||||
|
||||
Reference in New Issue
Block a user