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
@@ -236,6 +236,51 @@ mod tests {
.contains("\"name\":\"page.head.updateTitle\""));
}
#[test]
fn tree_resource_lifecycle_commands_have_convex_mapping() {
let cases = [
("tree.resource.archive", "mediaAssets:patchById"),
("tree.resource.restore", "mediaAssets:patchById"),
("tree.resource.purge", "mediaAssets:purgeById"),
("tree.resource.rename", "mediaAssets:patchById"),
];
for (command_name, function_name) in cases {
let command = CommandEnvelope {
name: command_name.into(),
command_id: format!("cmd_{command_name}"),
idempotency_key: Some(format!("idem_{command_name}")),
actor: ActorPayload {
actor_type: "human".into(),
actor_id: "user_1".into(),
session_id: Some("session_1".into()),
},
source: SourcePayload {
channel: "next-route".into(),
client: "wolai-frontend".into(),
},
target: Some(TargetRef {
workspace_id: Some("ws_1".into()),
page_id: Some("doc_1".into()),
block_id: None,
}),
payload: 1,
reason: None,
refs: vec![],
dry_run: false,
validate_only: false,
};
let request =
build_write_request(&demo_context(), &command).expect("write request should build");
assert_eq!(request.function_name, function_name);
assert_eq!(request.workspace_id.as_deref(), Some("ws_1"));
assert!(request
.payload_json
.contains(&format!("\"name\":\"{command_name}\"")));
}
}
#[test]
fn document_save_command_maps_to_documents_update_content() {
let command = CommandEnvelope {
@@ -44,6 +44,10 @@ pub fn map_command_name_to_convex(command_name: &str) -> &'static str {
"tree.resource.copy" => "mediaAssets:batchCopy",
"tree.resource.move" => "mediaAssets:batchMove",
"tree.resource.upload" => "mediaAssets:createWithStorage",
"tree.resource.archive" => "mediaAssets:patchById",
"tree.resource.restore" => "mediaAssets:patchById",
"tree.resource.purge" => "mediaAssets:purgeById",
"tree.resource.rename" => "mediaAssets:patchById",
"tree.filetree.drop.preflight" => "tree:fileTreeDropPreflight",
"tree.filetree.delete.preflight" => "tree:fileTreeDeletePreflight",
"tree.filetree.paste.preflight" => "tree:fileTreePastePreflight",