feat(tree): checkpoint resource lifecycle work

提交当前顶层 mnote Git 工作区,范围集中在 04-tree-domain 的 resource/trash/filetree 生命周期、mnote-web resource_trash 路由、Convex/Next 兼容接口、sidebar/file-tree 客户端适配、smoke 脚本与对应设计/bug 记录。

不包含被 ignore 的 design/05-editor-mainline/reference-code/leptos-tiptap 嵌套仓库改动。新增 smoke 的测试密码改为运行时读取 MNOTE_E2E_PASSWORD,避免提交明文 credential assignment。
This commit is contained in:
lix-2026
2026-05-16 07:38:45 +08:00
parent 274779c0d8
commit 384da4e44c
85 changed files with 12570 additions and 394 deletions
+11 -11
View File
@@ -643,23 +643,23 @@ async function assertSingleMindmapAssetRowStable(page, documentId, mindmapId, ex
};
}
async function assertFileTreeIndexOpenUsesPageAggregate(page, documentId, mindmapId, failures) {
async function assertFileTreePageMarkdownOpenUsesPageAggregate(page, documentId, mindmapId, failures) {
await openFilesystemView(page);
const opened = await page.evaluate(
({ documentId }) => {
const row =
document.querySelector(`#sidebar-file-tree-root [data-row-id="index:${CSS.escape(documentId)}"]`) ||
Array.from(document.querySelectorAll("#sidebar-file-tree-root [data-row-kind='index']")).find((node) => {
document.querySelector(`#sidebar-file-tree-root [data-row-id="doc:${CSS.escape(documentId)}"]`) ||
Array.from(document.querySelectorAll("#sidebar-file-tree-root [data-row-kind='document']")).find((node) => {
if (!(node instanceof HTMLElement)) return false;
const rowDocumentId = node.getAttribute("data-document-id") || node.getAttribute("data-doc-id") || "";
return rowDocumentId === documentId;
});
if (!(row instanceof HTMLElement)) {
return { clicked: false, reason: "index_row_missing" };
return { clicked: false, reason: "page_markdown_row_missing" };
}
const button = row.querySelector('[data-rust-action="open"], .tree-link');
if (!(button instanceof HTMLElement)) {
return { clicked: false, reason: "index_open_button_missing" };
return { clicked: false, reason: "page_markdown_open_button_missing" };
}
button.click();
return {
@@ -671,12 +671,12 @@ async function assertFileTreeIndexOpenUsesPageAggregate(page, documentId, mindma
{ documentId },
);
if (!opened.clicked) {
failures.push({ code: "filetree_index_open_row_missing", opened });
failures.push({ code: "filetree_page_markdown_open_row_missing", opened });
return opened;
}
if (!opened.objectIdentity.includes(`"objectKind":"index"`) || !opened.objectIdentity.includes(`"documentId":"${documentId}"`)) {
if (!opened.objectIdentity.includes(`"objectKind":"page"`) || !opened.objectIdentity.includes(`"documentId":"${documentId}"`)) {
failures.push({
code: "filetree_index_row_missing_object_identity",
code: "filetree_page_markdown_row_missing_object_identity",
opened,
});
}
@@ -687,14 +687,14 @@ async function assertFileTreeIndexOpenUsesPageAggregate(page, documentId, mindma
const url = new URL(state.url);
if (!url.pathname.includes(`/documents/${encodeURIComponent(documentId)}`)) {
failures.push({
code: "filetree_index_open_did_not_return_document_page",
code: "filetree_page_markdown_open_did_not_return_document_page",
opened,
state,
});
}
if (state.objectEditor === "mindmap" || state.objectIdentity.includes(`resource:mindmap:${documentId}:${mindmapId}`)) {
failures.push({
code: "filetree_index_open_loaded_mindmap_object_identity",
code: "filetree_page_markdown_open_loaded_mindmap_object_identity",
opened,
state,
});
@@ -1294,7 +1294,7 @@ async function main() {
failures,
);
await openDocument(pageA, awayDoc.workspaceId, awayDoc.documentId);
result.indexOpenAfterLongLanguageEdit = await assertFileTreeIndexOpenUsesPageAggregate(
result.indexOpenAfterLongLanguageEdit = await assertFileTreePageMarkdownOpenUsesPageAggregate(
pageA,
doc.documentId,
result.mindmapId,