收口本地工作区清理与资源投影

清理历史 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:
lix-2026
2026-05-20 10:43:38 +08:00
parent 90818cdf75
commit b4c8bcb647
73 changed files with 8073 additions and 8240 deletions
@@ -3,27 +3,46 @@ use crate::context::RequestContext;
use crate::error::WebError;
use crate::routes::web_shell::{
build_page_aggregate_snapshot, load_file_tree_html, load_sidebar_tree_html,
load_workspace_shell_projection,
load_workspace_shell_projection, render_local_file_tree_html, render_local_sidebar_tree_html,
};
use crate::ssr::pages::mindmap::MindmapPage;
use crate::workspace_shell::render_workspace_shell_sidebar_html;
use axum::extract::{Extension, Path, State};
use axum::extract::{Extension, Path, Query, State};
use axum::http::{HeaderMap, HeaderName, HeaderValue};
use axum::response::{Html, IntoResponse, Response};
use serde::Deserialize;
use serde_json::json;
const HEADER_MNOTE_WEB_OWNER: &str = "x-mnote-web-owner";
const HEADER_MNOTE_WEB_SHELL: &str = "x-mnote-web-shell";
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct MindmapShellQuery {
pub source_kind: Option<String>,
pub root_uri: Option<String>,
pub workspace_id: Option<String>,
}
pub async fn mindmap_object_shell(
State(state): State<AppState>,
Extension(context): Extension<RequestContext>,
Path((doc_id, mindmap_id)): Path<(String, String)>,
Query(query): Query<MindmapShellQuery>,
) -> Result<Response, WebError> {
let default_workspace_name = format!("{} 的空间", state.config().dev_user_name);
let aggregate = build_page_aggregate_snapshot(&state, &context, &doc_id, None, None, None)
.await
.ok();
let source_kind = query.source_kind.as_deref();
let root_uri = query.root_uri.as_deref();
let aggregate = build_page_aggregate_snapshot(
&state,
&context,
&doc_id,
query.workspace_id.as_deref(),
source_kind,
root_uri,
)
.await
.ok();
let workspace_id = aggregate
.as_ref()
.map(|value| value.identity.workspace_id.clone())
@@ -33,44 +52,69 @@ pub async fn mindmap_object_shell(
.map(|value| value.head.title.trim().to_string())
.filter(|value| !value.is_empty())
.unwrap_or_else(|| "思维导图".to_string());
let (workspace_name, sidebar_tree_html, workspace_sidebar_html) =
if let Some(workspace_id) = workspace_id.as_deref() {
let workspace_projection = load_workspace_shell_projection(
state.config(),
&context,
workspace_id,
Some(&doc_id),
&default_workspace_name,
)
.await;
let sidebar_tree_html =
load_sidebar_tree_html(state.config(), &context, workspace_id, Some(&doc_id))
.await
.unwrap_or_default();
let active_filetree_row_id = format!("asset:{mindmap_id}");
let file_tree_html = load_file_tree_html(
state.config(),
&context,
workspace_id,
Some(&doc_id),
Some(active_filetree_row_id.as_str()),
)
.await
.unwrap_or_default();
let workspace_name = workspace_projection.workspace_name.clone();
let workspace_sidebar_html = render_workspace_shell_sidebar_html(
&workspace_projection,
Some(sidebar_tree_html.as_str()),
Some(file_tree_html.as_str()),
);
(
Some(workspace_name),
Some(sidebar_tree_html),
Some(workspace_sidebar_html),
)
} else {
(None, None, None)
};
let is_local_folder = source_kind.map(str::trim) == Some("local_folder");
let (workspace_name, sidebar_tree_html, workspace_sidebar_html) = if is_local_folder {
let root_uri = root_uri.unwrap_or_default();
let sidebar_tree_html =
render_local_sidebar_tree_html(root_uri, Some(&doc_id)).unwrap_or_default();
let file_tree_html =
render_local_file_tree_html(root_uri, Some(&doc_id)).unwrap_or_default();
let workspace_projection = load_workspace_shell_projection(
state.config(),
&context,
workspace_id.as_deref().unwrap_or("local-folder"),
Some(&doc_id),
&default_workspace_name,
)
.await;
let workspace_name = workspace_projection.workspace_name.clone();
let workspace_sidebar_html = render_workspace_shell_sidebar_html(
&workspace_projection,
Some(sidebar_tree_html.as_str()),
Some(file_tree_html.as_str()),
);
(
Some(workspace_name),
Some(sidebar_tree_html),
Some(workspace_sidebar_html),
)
} else if let Some(workspace_id) = workspace_id.as_deref() {
let workspace_projection = load_workspace_shell_projection(
state.config(),
&context,
workspace_id,
Some(&doc_id),
&default_workspace_name,
)
.await;
let sidebar_tree_html =
load_sidebar_tree_html(state.config(), &context, workspace_id, Some(&doc_id))
.await
.unwrap_or_default();
let active_filetree_row_id = format!("asset:{mindmap_id}");
let file_tree_html = load_file_tree_html(
state.config(),
&context,
workspace_id,
Some(&doc_id),
Some(active_filetree_row_id.as_str()),
)
.await
.unwrap_or_default();
let workspace_name = workspace_projection.workspace_name.clone();
let workspace_sidebar_html = render_workspace_shell_sidebar_html(
&workspace_projection,
Some(sidebar_tree_html.as_str()),
Some(file_tree_html.as_str()),
);
(
Some(workspace_name),
Some(sidebar_tree_html),
Some(workspace_sidebar_html),
)
} else {
(None, None, None)
};
let editor_bootstrap = json!({
"documentId": format!("__mindmap_object__:{doc_id}:{mindmap_id}"),
"workspaceId": workspace_id
@@ -99,6 +143,8 @@ pub async fn mindmap_object_shell(
"documentId": doc_id,
"mindmapId": mindmap_id
},
"sourceKind": source_kind.unwrap_or("convex_workspace"),
"rootUri": root_uri.unwrap_or(""),
"revision": serde_json::Value::Null,
"conflictDetectionKey": serde_json::Value::Null,
"pageOptions": {
@@ -114,6 +160,8 @@ pub async fn mindmap_object_shell(
"shell": "mindmap",
"documentId": doc_id,
"mindmapId": mindmap_id,
"sourceKind": source_kind.unwrap_or("convex_workspace"),
"rootUri": root_uri.unwrap_or(""),
"projection": {
"schema": "mnote.mindmap.simple_mind_map_scene.v1",
"runtime": "simple-mind-map",
@@ -151,7 +199,7 @@ pub async fn mindmap_object_shell(
<title>{}</title>
<style>{}</style>
</head>
<body data-mnote-web-owner="mnote-web" data-mnote-shell="mindmap" data-document-id="{}" data-mindmap-id="{}">
<body data-mnote-web-owner="mnote-web" data-mnote-shell="mindmap" data-document-id="{}" data-mindmap-id="{}" data-mnote-source-kind="{}" data-mnote-root-uri="{}">
{}
<script id="__MNOTE_MINDMAP_EDITOR_BOOTSTRAP__" type="application/json">{}</script>
<script id="__MNOTE_MINDMAP_SHELL__" type="application/json">{}</script>
@@ -162,6 +210,8 @@ pub async fn mindmap_object_shell(
crate::ssr::MNOTE_CSS,
escape_html(&doc_id),
escape_html(&mindmap_id),
escape_html(source_kind.unwrap_or("convex_workspace")),
escape_html(root_uri.unwrap_or("")),
body_content,
escape_script_json(&editor_bootstrap_json),
escape_script_json(&contract_json),