refactor: split sidebar workspace runtime

This commit is contained in:
lix-2026
2026-05-26 01:31:28 +08:00
parent ff9a779a6c
commit 5a18631af8
6 changed files with 1093 additions and 1005 deletions
@@ -163,7 +163,7 @@ cargo test --manifest-path rust/Cargo.toml -p mnote-web --lib routes::web_shell
拆分项: 拆分项:
- [ ] C1. `sidebar-workspace-runtime.js`workspace source switch、sidebar tabs、collapse/resize 状态。 - [x] C1. `sidebar-workspace-runtime.js`workspace source switch、sidebar tabs、collapse/resize 状态。
- [ ] C2. `sidebar-page-tree-runtime.js`page tree row selection、rename title patch、breadcrumb/title sync。 - [ ] C2. `sidebar-page-tree-runtime.js`page tree row selection、rename title patch、breadcrumb/title sync。
- [ ] C3. `sidebar-filetree-open-runtime.js`local markdown / resource open target、active resource tab dispatch。 - [ ] C3. `sidebar-filetree-open-runtime.js`local markdown / resource open target、active resource tab dispatch。
- [ ] C4. `sidebar-filetree-command-runtime.js`create/rename/delete/copy/move/trash/restore/purge command payload。 - [ ] C4. `sidebar-filetree-command-runtime.js`create/rename/delete/copy/move/trash/restore/purge command payload。
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+5
View File
@@ -126,6 +126,10 @@ pub fn build_router(state: AppState) -> Router {
"/api/mnote-browser-runtime/sidebar-shell-runtime.js", "/api/mnote-browser-runtime/sidebar-shell-runtime.js",
get(web_shell::sidebar_shell_runtime_asset), get(web_shell::sidebar_shell_runtime_asset),
) )
.route(
"/api/mnote-browser-runtime/sidebar-workspace-runtime.js",
get(web_shell::sidebar_workspace_runtime_asset),
)
.route( .route(
"/api/mnote-browser-runtime/sidebar-tree-runtime.js", "/api/mnote-browser-runtime/sidebar-tree-runtime.js",
get(web_shell::sidebar_tree_runtime_asset), get(web_shell::sidebar_tree_runtime_asset),
@@ -579,6 +583,7 @@ mod tests {
"/api/mnote-browser-runtime/filetree-dnd-runtime.js", "/api/mnote-browser-runtime/filetree-dnd-runtime.js",
"/api/mnote-browser-runtime/filetree-keyboard-runtime.js", "/api/mnote-browser-runtime/filetree-keyboard-runtime.js",
"/api/mnote-browser-runtime/sidebar-shell-runtime.js", "/api/mnote-browser-runtime/sidebar-shell-runtime.js",
"/api/mnote-browser-runtime/sidebar-workspace-runtime.js",
"/api/mnote-browser-runtime/sidebar-tree-runtime.js", "/api/mnote-browser-runtime/sidebar-tree-runtime.js",
"/api/mnote-browser-runtime/tree-live-controller.js", "/api/mnote-browser-runtime/tree-live-controller.js",
"/api/mnote-browser-runtime/tree-shell-runtime.js", "/api/mnote-browser-runtime/tree-shell-runtime.js",
@@ -742,6 +742,20 @@ pub async fn sidebar_shell_runtime_asset() -> Response {
.unwrap_or_else(|_| Response::new(Body::empty())) .unwrap_or_else(|_| Response::new(Body::empty()))
} }
pub async fn sidebar_workspace_runtime_asset() -> Response {
const JS: &str = include_str!("../../browser/sidebar-workspace-runtime.js");
Response::builder()
.status(StatusCode::OK)
.header(
header::CONTENT_TYPE,
"application/javascript; charset=utf-8",
)
.header(header::CACHE_CONTROL, "no-store")
.header(HEADER_MNOTE_WEB_OWNER, "mnote-web")
.body(Body::from(JS))
.unwrap_or_else(|_| Response::new(Body::empty()))
}
pub async fn filetree_keyboard_runtime_asset() -> Response { pub async fn filetree_keyboard_runtime_asset() -> Response {
const JS: &str = include_str!("../../browser/filetree-keyboard-runtime.js"); const JS: &str = include_str!("../../browser/filetree-keyboard-runtime.js");
Response::builder() Response::builder()
+34 -31
View File
@@ -201,6 +201,8 @@ mod tests {
const SIDEBAR_TREE_RUNTIME_JS: &str = include_str!("../../../browser/sidebar-tree-runtime.js"); const SIDEBAR_TREE_RUNTIME_JS: &str = include_str!("../../../browser/sidebar-tree-runtime.js");
const SIDEBAR_SHELL_RUNTIME_JS: &str = const SIDEBAR_SHELL_RUNTIME_JS: &str =
include_str!("../../../browser/sidebar-shell-runtime.js"); include_str!("../../../browser/sidebar-shell-runtime.js");
const SIDEBAR_WORKSPACE_RUNTIME_JS: &str =
include_str!("../../../browser/sidebar-workspace-runtime.js");
const FILETREE_CONTEXT_MENU_RUNTIME_JS: &str = const FILETREE_CONTEXT_MENU_RUNTIME_JS: &str =
include_str!("../../../browser/filetree-context-menu-runtime.js"); include_str!("../../../browser/filetree-context-menu-runtime.js");
const FILETREE_DND_RUNTIME_JS: &str = include_str!("../../../browser/filetree-dnd-runtime.js"); const FILETREE_DND_RUNTIME_JS: &str = include_str!("../../../browser/filetree-dnd-runtime.js");
@@ -301,18 +303,18 @@ mod tests {
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("sidebarFileTreeClipboard")); assert!(SIDEBAR_TREE_RUNTIME_JS.contains("sidebarFileTreeClipboard"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("pasteSidebarFileTreeClipboard")); assert!(SIDEBAR_TREE_RUNTIME_JS.contains("pasteSidebarFileTreeClipboard"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("MNOTE_RECENT_LOCAL_ROOTS_KEY_PREFIX")); assert!(SIDEBAR_TREE_RUNTIME_JS.contains("MNOTE_RECENT_LOCAL_ROOTS_KEY_PREFIX"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("function recentLocalRootsStorageKey")); assert!(SIDEBAR_WORKSPACE_RUNTIME_JS.contains("function recentLocalRootsStorageKey"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("data-mnote-actor-id")); assert!(SIDEBAR_WORKSPACE_RUNTIME_JS.contains("data-mnote-actor-id"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("requestOpenLocalFolder")); assert!(SIDEBAR_WORKSPACE_RUNTIME_JS.contains("requestOpenLocalFolder"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("autoOpenRecentLocalRootOnHome")); assert!(SIDEBAR_WORKSPACE_RUNTIME_JS.contains("autoOpenRecentLocalRootOnHome"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("sourceKind', 'local_folder")); assert!(SIDEBAR_WORKSPACE_RUNTIME_JS.contains("sourceKind', 'local_folder"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("switchToCloudWorkspace")); assert!(SIDEBAR_WORKSPACE_RUNTIME_JS.contains("switchToCloudWorkspace"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("mnote-switch-cloud-workspace")); assert!(SIDEBAR_WORKSPACE_RUNTIME_JS.contains("mnote-switch-cloud-workspace"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("mnote-recent-local-root")); assert!(SIDEBAR_WORKSPACE_RUNTIME_JS.contains("mnote-recent-local-root"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("mnote-local-folder-authorized-roots")); assert!(SIDEBAR_WORKSPACE_RUNTIME_JS.contains("mnote-local-folder-authorized-roots"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("mnote-local-folder-authorized-root")); assert!(SIDEBAR_WORKSPACE_RUNTIME_JS.contains("mnote-local-folder-authorized-root"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("已授权文件夹")); assert!(SIDEBAR_WORKSPACE_RUNTIME_JS.contains("已授权文件夹"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("fetch('/api/user/access-policy'")); assert!(SIDEBAR_WORKSPACE_RUNTIME_JS.contains("fetch('/api/user/access-policy'"));
} }
#[test] #[test]
@@ -338,12 +340,12 @@ mod tests {
#[test] #[test]
fn page_ai_local_source_passes_file_reference_fields_to_agent_run() { fn page_ai_local_source_passes_file_reference_fields_to_agent_run() {
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("function currentRootUri()")); assert!(SIDEBAR_WORKSPACE_RUNTIME_JS.contains("function currentRootUri()"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("sourceKind: currentSourceKind()")); assert!(SIDEBAR_TREE_RUNTIME_JS.contains("sourceKind: currentSourceKind()"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("rootUri: currentRootUri()")); assert!(SIDEBAR_TREE_RUNTIME_JS.contains("rootUri: currentRootUri()"));
assert!(SIDEBAR_TREE_RUNTIME_JS assert!(SIDEBAR_WORKSPACE_RUNTIME_JS
.contains("if (sourceKind && !payload.sourceKind) payload.sourceKind = sourceKind")); .contains("if (sourceKind && !payload.sourceKind) payload.sourceKind = sourceKind"));
assert!(SIDEBAR_TREE_RUNTIME_JS assert!(SIDEBAR_WORKSPACE_RUNTIME_JS
.contains("if (rootUri && !payload.rootUri) payload.rootUri = rootUri")); .contains("if (rootUri && !payload.rootUri) payload.rootUri = rootUri"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("pageContext: scopedContext.pageContext")); assert!(SIDEBAR_TREE_RUNTIME_JS.contains("pageContext: scopedContext.pageContext"));
assert!( assert!(
@@ -449,15 +451,15 @@ mod tests {
"进入本地文件夹前不能用 document.body 推导 workspaceId;它会在无 workspaceId URL 时回退成 default" "进入本地文件夹前不能用 document.body 推导 workspaceId;它会在无 workspaceId URL 时回退成 default"
); );
assert!( assert!(
SIDEBAR_TREE_RUNTIME_JS.contains("rememberCurrentCloudWorkspaceId()"), SIDEBAR_WORKSPACE_RUNTIME_JS.contains("rememberCurrentCloudWorkspaceId()"),
"进入本地文件夹前应从 URL 或 DOM 子树读取真实 workspaceId" "进入本地文件夹前应从 URL 或 DOM 子树读取真实 workspaceId"
); );
assert!( assert!(
SIDEBAR_TREE_RUNTIME_JS.contains("normalized.indexOf('local-ws:') === 0"), SIDEBAR_WORKSPACE_RUNTIME_JS.contains("normalized.indexOf('local-ws:') === 0"),
"本地文件夹 workspaceId 不能写入 lastCloudWorkspaceId" "本地文件夹 workspaceId 不能写入 lastCloudWorkspaceId"
); );
assert!( assert!(
SIDEBAR_TREE_RUNTIME_JS.contains("stored.trim().indexOf('local-ws:') !== 0"), SIDEBAR_WORKSPACE_RUNTIME_JS.contains("stored.trim().indexOf('local-ws:') !== 0"),
"切回工作区时不能复用 local-ws:* 作为旧云 workspace" "切回工作区时不能复用 local-ws:* 作为旧云 workspace"
); );
assert!( assert!(
@@ -471,7 +473,7 @@ mod tests {
fn sidebar_tree_runtime_polls_local_folder_without_browser_reload() { fn sidebar_tree_runtime_polls_local_folder_without_browser_reload() {
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("startLocalFolderSidebarWatch")); assert!(SIDEBAR_TREE_RUNTIME_JS.contains("startLocalFolderSidebarWatch"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("refreshLocalFolderSidebarSnapshot")); assert!(SIDEBAR_TREE_RUNTIME_JS.contains("refreshLocalFolderSidebarSnapshot"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("function currentWorkspaceId()")); assert!(SIDEBAR_WORKSPACE_RUNTIME_JS.contains("function currentWorkspaceId()"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("var rootUri = currentRootUri();")); assert!(SIDEBAR_TREE_RUNTIME_JS.contains("var rootUri = currentRootUri();"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("/api/tree/local-folder-watch")); assert!(SIDEBAR_TREE_RUNTIME_JS.contains("/api/tree/local-folder-watch"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("/api/tree/projections/sidebar")); assert!(SIDEBAR_TREE_RUNTIME_JS.contains("/api/tree/projections/sidebar"));
@@ -791,21 +793,22 @@ mod tests {
#[test] #[test]
fn sidebar_local_folder_authorized_root_normalizes_plain_path_root_uri() { fn sidebar_local_folder_authorized_root_normalizes_plain_path_root_uri() {
assert!( assert!(SIDEBAR_WORKSPACE_RUNTIME_JS
SIDEBAR_TREE_RUNTIME_JS.contains("function normalizeGrantedLocalFolderRootUri(grant)") .contains("function normalizeGrantedLocalFolderRootUri(grant)"));
); assert!(SIDEBAR_WORKSPACE_RUNTIME_JS
assert!( .contains("if (rootPath) return pathToFileRootUri(rootPath);"));
SIDEBAR_TREE_RUNTIME_JS.contains("if (rootPath) return pathToFileRootUri(rootPath);") assert!(SIDEBAR_WORKSPACE_RUNTIME_JS
); .contains("if (rootUri) return pathToFileRootUri(rootUri);"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("if (rootUri) return pathToFileRootUri(rootUri);")); assert!(SIDEBAR_WORKSPACE_RUNTIME_JS
assert!(SIDEBAR_TREE_RUNTIME_JS
.contains("var rootUri = normalizeGrantedLocalFolderRootUri(grant);")); .contains("var rootUri = normalizeGrantedLocalFolderRootUri(grant);"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("function isDefaultWorkspaceAutoGrant(grant)"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("if (isDefaultWorkspaceAutoGrant(grant)) return;"));
assert!(SIDEBAR_TREE_RUNTIME_JS.contains("function recentLocalRootLabel(rootUri)"));
assert!( assert!(
SIDEBAR_TREE_RUNTIME_JS.contains("button.textContent = recentLocalRootLabel(rootUri);") SIDEBAR_WORKSPACE_RUNTIME_JS.contains("function isDefaultWorkspaceAutoGrant(grant)")
); );
assert!(SIDEBAR_WORKSPACE_RUNTIME_JS
.contains("if (isDefaultWorkspaceAutoGrant(grant)) return;"));
assert!(SIDEBAR_WORKSPACE_RUNTIME_JS.contains("function recentLocalRootLabel(rootUri)"));
assert!(SIDEBAR_WORKSPACE_RUNTIME_JS
.contains("button.textContent = recentLocalRootLabel(rootUri);"));
assert!(!SIDEBAR_TREE_RUNTIME_JS assert!(!SIDEBAR_TREE_RUNTIME_JS
.contains("button.textContent = rootUri.replace(/^file:\\/\\//, '')")); .contains("button.textContent = rootUri.replace(/^file:\\/\\//, '')"));
} }