收口本地工作区清理与资源投影
清理历史 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:
@@ -521,6 +521,7 @@ pub async fn content(
|
||||
}
|
||||
|
||||
pub async fn page_body_write(
|
||||
State(state): State<AppState>,
|
||||
Extension(context): Extension<RequestContext>,
|
||||
Json(body): Json<core_protocol::PageBodyWriteRequest>,
|
||||
) -> Result<(StatusCode, HeaderMap, Json<Value>), WebError> {
|
||||
@@ -548,7 +549,7 @@ pub async fn page_body_write(
|
||||
}
|
||||
ensure_local_workspace_access(&context, root_uri)
|
||||
.map_err(|error| error.with_context(&context))?;
|
||||
let result = write_local_markdown_page_body(&body)?;
|
||||
let result = write_local_markdown_page_body(&body, Some(&state.buffer_store))?;
|
||||
Ok(ok_response(&context, result))
|
||||
}
|
||||
|
||||
@@ -580,23 +581,26 @@ pub async fn save(
|
||||
.expected_file_version
|
||||
.as_deref()
|
||||
.or(body.conflict_detection_key.as_deref());
|
||||
let result = write_local_markdown_page_body(&core_protocol::PageBodyWriteRequest {
|
||||
document_id: document_id.to_string(),
|
||||
workspace_id: body.workspace_id.clone().unwrap_or_default(),
|
||||
source_kind: core_protocol::WorkspaceSourceKind::LocalFolder,
|
||||
root_uri: root_uri.to_string(),
|
||||
expected_file_version: expected_file_version.map(ToOwned::to_owned),
|
||||
base_content_hash: body.base_content_hash.clone(),
|
||||
content_format: body
|
||||
.content_format
|
||||
.clone()
|
||||
.unwrap_or_else(|| "editorBlocks".into()),
|
||||
content: body.content.clone(),
|
||||
editor_source: body
|
||||
.editor_source
|
||||
.clone()
|
||||
.or_else(|| Some("documents/save-compat".into())),
|
||||
})?;
|
||||
let result = write_local_markdown_page_body(
|
||||
&core_protocol::PageBodyWriteRequest {
|
||||
document_id: document_id.to_string(),
|
||||
workspace_id: body.workspace_id.clone().unwrap_or_default(),
|
||||
source_kind: core_protocol::WorkspaceSourceKind::LocalFolder,
|
||||
root_uri: root_uri.to_string(),
|
||||
expected_file_version: expected_file_version.map(ToOwned::to_owned),
|
||||
base_content_hash: body.base_content_hash.clone(),
|
||||
content_format: body
|
||||
.content_format
|
||||
.clone()
|
||||
.unwrap_or_else(|| "editorBlocks".into()),
|
||||
content: body.content.clone(),
|
||||
editor_source: body
|
||||
.editor_source
|
||||
.clone()
|
||||
.or_else(|| Some("documents/save-compat".into())),
|
||||
},
|
||||
Some(&state.buffer_store),
|
||||
)?;
|
||||
return Ok(ok_response(&context, result));
|
||||
}
|
||||
let effective_workspace_id =
|
||||
@@ -1368,10 +1372,10 @@ mod tests {
|
||||
std::process::id()
|
||||
));
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
std::fs::create_dir_all(&root).expect("create local root");
|
||||
std::fs::create_dir_all(root.join("Old Local Title")).expect("create local page bundle");
|
||||
std::fs::write(
|
||||
root.join("README.md"),
|
||||
"---\nmnote_id: local-stable\ntitle: Old Title\n---\n# Old\n",
|
||||
root.join("Old Local Title").join("Old Local Title.md"),
|
||||
"# Old\n",
|
||||
)
|
||||
.expect("write md");
|
||||
let root_uri = format!("file://{}", root.display());
|
||||
@@ -1380,7 +1384,7 @@ mod tests {
|
||||
&root_uri,
|
||||
)
|
||||
.expect("init local workspace");
|
||||
let document_id = "local-mdid:local-stable";
|
||||
let document_id = "local-md:Old~20Local~20Title~2FOld~20Local~20Title.md";
|
||||
|
||||
let title_response = app()
|
||||
.oneshot(
|
||||
@@ -1404,6 +1408,14 @@ mod tests {
|
||||
.await
|
||||
.expect("title response");
|
||||
assert_eq!(title_response.status(), StatusCode::OK);
|
||||
let title_body = to_bytes(title_response.into_body(), usize::MAX)
|
||||
.await
|
||||
.expect("title body");
|
||||
let title_payload: Value = serde_json::from_slice(&title_body).expect("title json");
|
||||
let renamed_document_id = title_payload["result"]["documentId"]
|
||||
.as_str()
|
||||
.expect("renamed document id")
|
||||
.to_string();
|
||||
|
||||
let save_response = app()
|
||||
.oneshot(
|
||||
@@ -1415,7 +1427,7 @@ mod tests {
|
||||
.header("x-mnote-actor-type", "user")
|
||||
.body(Body::from(
|
||||
serde_json::json!({
|
||||
"documentId": document_id,
|
||||
"documentId": renamed_document_id,
|
||||
"sourceKind": "local_folder",
|
||||
"rootUri": root_uri,
|
||||
"content": [
|
||||
@@ -1460,7 +1472,7 @@ mod tests {
|
||||
.header("x-mnote-actor-type", "user")
|
||||
.body(Body::from(
|
||||
serde_json::json!({
|
||||
"documentId": document_id,
|
||||
"documentId": renamed_document_id,
|
||||
"sourceKind": "local_folder",
|
||||
"rootUri": root_uri,
|
||||
"options": {
|
||||
@@ -1476,17 +1488,23 @@ mod tests {
|
||||
.expect("options response");
|
||||
assert_eq!(options_response.status(), StatusCode::OK);
|
||||
|
||||
let markdown = std::fs::read_to_string(root.join("README.md")).expect("read md");
|
||||
assert!(markdown.contains("mnote_id: local-stable"));
|
||||
assert!(markdown.contains("title: New Local Title"));
|
||||
let markdown =
|
||||
std::fs::read_to_string(root.join("New Local Title").join("New Local Title.md"))
|
||||
.expect("read md");
|
||||
assert!(markdown.contains("## Saved Heading"));
|
||||
assert!(markdown.contains("Saved body"));
|
||||
|
||||
let options = std::fs::read_to_string(root.join(".mnote").join("page-options.json"))
|
||||
.expect("read page options");
|
||||
let options_json: Value = serde_json::from_str(&options).expect("options json");
|
||||
assert_eq!(options_json["pages"][document_id]["wideLayout"], true);
|
||||
assert_eq!(options_json["pages"][document_id]["showToc"], false);
|
||||
assert_eq!(
|
||||
options_json["pages"][&renamed_document_id]["wideLayout"],
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
options_json["pages"][&renamed_document_id]["showToc"],
|
||||
false
|
||||
);
|
||||
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
}
|
||||
@@ -1510,7 +1528,7 @@ mod tests {
|
||||
&root_uri,
|
||||
)
|
||||
.expect("init local workspace");
|
||||
let document_id = "local-mdid:expected-file-version";
|
||||
let document_id = "local-md:README.md";
|
||||
let aggregate = crate::routes::local_folder_source::resolve_local_markdown_page_aggregate(
|
||||
&root_uri,
|
||||
document_id,
|
||||
@@ -1582,7 +1600,7 @@ mod tests {
|
||||
assert!(payload["details"]["conflict"]["currentDiskVersion"]
|
||||
.as_str()
|
||||
.unwrap_or("")
|
||||
.starts_with("local-md:local-mdid:expected-file-version:"));
|
||||
.starts_with("local-md:local-md:README.md:"));
|
||||
assert!(payload["details"]["conflict"]["suggestedActions"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
|
||||
Reference in New Issue
Block a user