收口本地工作区清理与资源投影
清理历史 Electron、Graphify、沙箱和截图等仓库跟踪残留,补充 CodeGraph 与 Convex active deploy source 协作说明。 新增 tree-first 下一阶段设计稿和 2026-05-20 清理总结,记录本地工作区、路径身份和 Zed/Lapce/VSCode 参考收口方向。 扩展 Rust Web 本地文件夹、DocumentBuffer、mindmap 资源、tree runtime 和页面聚合链路,并补充 task455 local-folder mindmap clean smoke。 验证:git diff --check 通过;pnpm store status --store-dir .pnpm-store 通过;npm ls --depth=0 --json 通过;find -L node_modules 未发现断链。cargo test -p mnote-web 当前 418 passed / 35 failed。
This commit is contained in:
@@ -443,48 +443,8 @@ pub(crate) fn collect_page_tree_render_rows(projection: &Value) -> Vec<PageTreeR
|
||||
rows
|
||||
}
|
||||
|
||||
fn short_mindmap_file_name(raw: &str, asset_id: Option<&str>) -> String {
|
||||
let source = asset_id
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.unwrap_or(raw.trim());
|
||||
let digits = source
|
||||
.chars()
|
||||
.rev()
|
||||
.take_while(|ch| ch.is_ascii_digit())
|
||||
.collect::<String>()
|
||||
.chars()
|
||||
.rev()
|
||||
.collect::<String>();
|
||||
let suffix = if digits.len() >= 4 {
|
||||
digits[digits.len().saturating_sub(4)..].to_string()
|
||||
} else {
|
||||
source
|
||||
.trim_start_matches("mindmap")
|
||||
.trim_start_matches(|ch| ch == '-' || ch == '_')
|
||||
.chars()
|
||||
.take(6)
|
||||
.collect::<String>()
|
||||
};
|
||||
if suffix.trim().is_empty() {
|
||||
"思维导图.json".to_string()
|
||||
} else {
|
||||
format!("思维导图-{suffix}.json")
|
||||
}
|
||||
}
|
||||
|
||||
fn normalize_filetree_mindmap_title(
|
||||
raw_title: &str,
|
||||
asset_id: Option<&str>,
|
||||
icon_kind: &str,
|
||||
resource_kind: Option<&str>,
|
||||
) -> String {
|
||||
fn normalize_filetree_mindmap_title(raw_title: &str) -> String {
|
||||
let title = raw_title.trim();
|
||||
let is_mindmap = icon_kind == "mindmap" || resource_kind == Some("mindmap");
|
||||
let generated = title.starts_with("mindmap-") || title.starts_with("mindmap_");
|
||||
if is_mindmap && (generated || title.chars().count() > 24) {
|
||||
return short_mindmap_file_name(title, asset_id);
|
||||
}
|
||||
if title.is_empty() {
|
||||
"无标题".to_string()
|
||||
} else {
|
||||
@@ -592,14 +552,7 @@ pub(crate) fn collect_filetree_render_rows(
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.map(ToOwned::to_owned),
|
||||
title: normalize_filetree_mindmap_title(
|
||||
raw_title,
|
||||
asset_id.as_deref(),
|
||||
&icon_kind,
|
||||
resource_meta
|
||||
.and_then(|meta| meta.get("resourceKind"))
|
||||
.and_then(Value::as_str),
|
||||
),
|
||||
title: normalize_filetree_mindmap_title(raw_title),
|
||||
depth: item.get("depth").and_then(Value::as_u64).unwrap_or(0) as u32,
|
||||
expandable: item
|
||||
.get("expandable")
|
||||
@@ -7336,8 +7289,10 @@ mod tests {
|
||||
.expect("body");
|
||||
let html = String::from_utf8(body.to_vec()).expect("utf8");
|
||||
assert!(html.contains("local_folder"));
|
||||
assert!(html.contains("Frontmatter Title"));
|
||||
assert!(html.contains("Child H1"));
|
||||
assert!(html.contains("README"));
|
||||
assert!(html.contains("child"));
|
||||
assert!(!html.contains("Frontmatter Title"));
|
||||
assert!(!html.contains("Child H1"));
|
||||
assert!(html.contains(">docs<") || html.contains("docs"));
|
||||
assert!(!html.contains("image.png"));
|
||||
}
|
||||
@@ -7380,8 +7335,23 @@ mod tests {
|
||||
.as_str()
|
||||
.expect("document id")
|
||||
.to_string();
|
||||
assert!(root.join("新页面.md").exists());
|
||||
assert!(root.join(".mnote").join("page-ids.json").exists());
|
||||
let created_relative_path = payload["result"]["execution"]["relativePath"]
|
||||
.as_str()
|
||||
.expect("created relative path");
|
||||
let (created_dir, created_file) = created_relative_path
|
||||
.split_once('/')
|
||||
.expect("created nested bundle path");
|
||||
assert!(created_dir.starts_with("新页面"));
|
||||
assert_eq!(created_file, format!("{created_dir}.md"));
|
||||
assert!(root.join(created_dir).join(created_file).exists());
|
||||
assert_eq!(
|
||||
document_id,
|
||||
format!(
|
||||
"local-md:{}",
|
||||
crate::routes::local_folder_source::encode_local_id_segment(created_relative_path)
|
||||
)
|
||||
);
|
||||
assert!(!root.join(".mnote").join("page-ids.json").exists());
|
||||
|
||||
let rename_response = app()
|
||||
.oneshot(
|
||||
@@ -7406,8 +7376,18 @@ mod tests {
|
||||
"{}",
|
||||
String::from_utf8_lossy(&rename_body)
|
||||
);
|
||||
assert!(!root.join("新页面.md").exists());
|
||||
assert!(root.join("重命名页面.md").exists());
|
||||
assert!(!root.join(created_dir).exists());
|
||||
assert!(root.join("重命名页面").join("重命名页面.md").exists());
|
||||
let rename_payload: Value = serde_json::from_slice(&rename_body).expect("rename json");
|
||||
let renamed_document_id = rename_payload["result"]["documentId"]
|
||||
.as_str()
|
||||
.expect("renamed document id")
|
||||
.to_string();
|
||||
assert_eq!(
|
||||
renamed_document_id,
|
||||
"local-md:~E9~87~8D~E5~91~BD~E5~90~8D~E9~A1~B5~E9~9D~A2~2F~E9~87~8D~E5~91~BD~E5~90~8D~E9~A1~B5~E9~9D~A2.md"
|
||||
);
|
||||
assert!(!root.join(".mnote").join("page-ids.json").exists());
|
||||
|
||||
std::fs::create_dir_all(root.join("docs")).expect("create docs dir");
|
||||
let move_response = app()
|
||||
@@ -7417,15 +7397,38 @@ mod tests {
|
||||
.uri("/api/tree/commands")
|
||||
.header("content-type", "application/json")
|
||||
.body(Body::from(format!(
|
||||
r#"{{"action":"move","sourceKind":"local_folder","rootUri":"{root_uri}","documentId":"{document_id}","parentId":"local-dir:docs","sortOrder":0}}"#
|
||||
r#"{{"action":"move","sourceKind":"local_folder","rootUri":"{root_uri}","documentId":"{renamed_document_id}","parentId":"local-dir:docs","sortOrder":0}}"#
|
||||
)))
|
||||
.expect("request"),
|
||||
)
|
||||
.await
|
||||
.expect("response");
|
||||
assert_eq!(move_response.status(), StatusCode::OK);
|
||||
assert!(!root.join("重命名页面.md").exists());
|
||||
assert!(root.join("docs").join("重命名页面.md").exists());
|
||||
let move_status = move_response.status();
|
||||
let move_body = axum::body::to_bytes(move_response.into_body(), usize::MAX)
|
||||
.await
|
||||
.expect("move body");
|
||||
assert_eq!(
|
||||
move_status,
|
||||
StatusCode::OK,
|
||||
"{}",
|
||||
String::from_utf8_lossy(&move_body)
|
||||
);
|
||||
assert!(!root.join("重命名页面").exists());
|
||||
assert!(root
|
||||
.join("docs")
|
||||
.join("重命名页面")
|
||||
.join("重命名页面.md")
|
||||
.exists());
|
||||
let move_payload: Value = serde_json::from_slice(&move_body).expect("move json");
|
||||
let moved_document_id = move_payload["result"]["documentId"]
|
||||
.as_str()
|
||||
.expect("moved document id")
|
||||
.to_string();
|
||||
assert_eq!(
|
||||
moved_document_id,
|
||||
"local-md:docs~2F~E9~87~8D~E5~91~BD~E5~90~8D~E9~A1~B5~E9~9D~A2~2F~E9~87~8D~E5~91~BD~E5~90~8D~E9~A1~B5~E9~9D~A2.md"
|
||||
);
|
||||
assert!(!root.join(".mnote").join("page-ids.json").exists());
|
||||
|
||||
let copy_response = app()
|
||||
.oneshot(
|
||||
@@ -7434,7 +7437,7 @@ mod tests {
|
||||
.uri("/api/tree/commands")
|
||||
.header("content-type", "application/json")
|
||||
.body(Body::from(format!(
|
||||
r#"{{"action":"copy","sourceKind":"local_folder","rootUri":"{root_uri}","documentId":"{document_id}","parentId":"local-dir:docs"}}"#
|
||||
r#"{{"action":"copy","sourceKind":"local_folder","rootUri":"{root_uri}","documentId":"{moved_document_id}","parentId":"local-dir:docs"}}"#
|
||||
)))
|
||||
.expect("request"),
|
||||
)
|
||||
@@ -7455,7 +7458,11 @@ mod tests {
|
||||
.as_str()
|
||||
.expect("copied document id")
|
||||
.to_string();
|
||||
assert!(root.join("docs").join("重命名页面 2.md").exists());
|
||||
assert!(root
|
||||
.join("docs")
|
||||
.join("重命名页面 2")
|
||||
.join("重命名页面 2.md")
|
||||
.exists());
|
||||
|
||||
let folder_response = app()
|
||||
.oneshot(
|
||||
@@ -7480,20 +7487,22 @@ mod tests {
|
||||
.uri("/api/tree/commands")
|
||||
.header("content-type", "application/json")
|
||||
.body(Body::from(format!(
|
||||
r#"{{"action":"delete","sourceKind":"local_folder","rootUri":"{root_uri}","documentId":"{document_id}"}}"#
|
||||
r#"{{"action":"delete","sourceKind":"local_folder","rootUri":"{root_uri}","documentId":"{moved_document_id}"}}"#
|
||||
)))
|
||||
.expect("request"),
|
||||
)
|
||||
.await
|
||||
.expect("response");
|
||||
assert_eq!(delete_response.status(), StatusCode::OK);
|
||||
assert!(!root.join("docs").join("重命名页面.md").exists());
|
||||
assert!(!root.join("docs").join("重命名页面").exists());
|
||||
assert!(root
|
||||
.join(".mnote")
|
||||
.join("trash")
|
||||
.join("重命名页面")
|
||||
.join("重命名页面.md")
|
||||
.exists());
|
||||
assert!(root.join(".mnote").join("trash-index.json").exists());
|
||||
assert!(!root.join(".mnote").join("page-ids.json").exists());
|
||||
|
||||
let restore_response = app()
|
||||
.oneshot(
|
||||
@@ -7502,14 +7511,33 @@ mod tests {
|
||||
.uri("/api/tree/commands")
|
||||
.header("content-type", "application/json")
|
||||
.body(Body::from(format!(
|
||||
r#"{{"action":"restore","sourceKind":"local_folder","rootUri":"{root_uri}","documentId":"{document_id}"}}"#
|
||||
r#"{{"action":"restore","sourceKind":"local_folder","rootUri":"{root_uri}","documentId":"{moved_document_id}"}}"#
|
||||
)))
|
||||
.expect("request"),
|
||||
)
|
||||
.await
|
||||
.expect("response");
|
||||
assert_eq!(restore_response.status(), StatusCode::OK);
|
||||
assert!(root.join("docs").join("重命名页面.md").exists());
|
||||
let restore_status = restore_response.status();
|
||||
let restore_body = axum::body::to_bytes(restore_response.into_body(), usize::MAX)
|
||||
.await
|
||||
.expect("restore body");
|
||||
assert_eq!(
|
||||
restore_status,
|
||||
StatusCode::OK,
|
||||
"{}",
|
||||
String::from_utf8_lossy(&restore_body)
|
||||
);
|
||||
assert!(root
|
||||
.join("docs")
|
||||
.join("重命名页面")
|
||||
.join("重命名页面.md")
|
||||
.exists());
|
||||
let restore_payload: Value = serde_json::from_slice(&restore_body).expect("restore json");
|
||||
assert_eq!(
|
||||
restore_payload["result"]["documentId"].as_str(),
|
||||
Some(moved_document_id.as_str())
|
||||
);
|
||||
assert!(!root.join(".mnote").join("page-ids.json").exists());
|
||||
|
||||
let purge_response = app()
|
||||
.oneshot(
|
||||
@@ -7525,7 +7553,7 @@ mod tests {
|
||||
.await
|
||||
.expect("response");
|
||||
assert_eq!(purge_response.status(), StatusCode::OK);
|
||||
assert!(!root.join("docs").join("重命名页面 2.md").exists());
|
||||
assert!(!root.join("docs").join("重命名页面 2").exists());
|
||||
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user