From f961c1e2a10eb3f99b8ae1c425e70a491f1e2267 Mon Sep 17 00:00:00 2001 From: lix-2026 Date: Tue, 26 May 2026 14:34:47 +0800 Subject: [PATCH] Fix filetree SSR tab selection --- rust/crates/mnote-web/src/routes/gateway.rs | 7 ++ .../mnote-web/src/routes/mindmap_shell.rs | 2 + rust/crates/mnote-web/src/routes/web_shell.rs | 11 +++ rust/crates/mnote-web/src/ssr/pages/layout.rs | 1 + rust/crates/mnote-web/src/workspace_shell.rs | 78 +++++++++++++++++-- 5 files changed, 94 insertions(+), 5 deletions(-) diff --git a/rust/crates/mnote-web/src/routes/gateway.rs b/rust/crates/mnote-web/src/routes/gateway.rs index 90587975..b515058e 100644 --- a/rust/crates/mnote-web/src/routes/gateway.rs +++ b/rust/crates/mnote-web/src/routes/gateway.rs @@ -484,6 +484,11 @@ pub async fn root_entry( &workspace_projection, Some(sidebar_tree_html.as_str()), Some(file_tree_html.as_str()), + if requests_filetree_first { + Some("filetree") + } else { + None + }, ); let workspace_name = workspace_projection.workspace_name.clone(); let active_page_id = selected_active_page_id.unwrap_or_default(); @@ -663,6 +668,7 @@ pub async fn trash_entry( &workspace_projection, Some(sidebar_tree_html.as_str()), Some(file_tree_html.as_str()), + None, ); let trash_workbench_html = render_local_trash_workbench_html( &workspace_id, @@ -725,6 +731,7 @@ pub async fn trash_entry( &workspace_projection, Some(sidebar_tree_html.as_str()), Some(file_tree_html.as_str()), + None, ); let dataset = load_sidebar_dataset(state.config(), &context, &workspace_id) .await diff --git a/rust/crates/mnote-web/src/routes/mindmap_shell.rs b/rust/crates/mnote-web/src/routes/mindmap_shell.rs index 89cc9ad9..eab47c0e 100644 --- a/rust/crates/mnote-web/src/routes/mindmap_shell.rs +++ b/rust/crates/mnote-web/src/routes/mindmap_shell.rs @@ -73,6 +73,7 @@ pub async fn mindmap_object_shell( &workspace_projection, Some(sidebar_tree_html.as_str()), Some(file_tree_html.as_str()), + None, ); ( Some(workspace_name), @@ -107,6 +108,7 @@ pub async fn mindmap_object_shell( &workspace_projection, Some(sidebar_tree_html.as_str()), Some(file_tree_html.as_str()), + None, ); ( Some(workspace_name), diff --git a/rust/crates/mnote-web/src/routes/web_shell.rs b/rust/crates/mnote-web/src/routes/web_shell.rs index 2712e75d..209d2051 100644 --- a/rust/crates/mnote-web/src/routes/web_shell.rs +++ b/rust/crates/mnote-web/src/routes/web_shell.rs @@ -49,6 +49,7 @@ pub struct DocumentShellQuery { pub workspace_id: Option, pub source_kind: Option, pub root_uri: Option, + pub tree_view: Option, pub secondary_document_id: Option, pub secondary_source_kind: Option, pub secondary_root_uri: Option, @@ -142,6 +143,11 @@ pub async fn document_page_shell( .map(str::trim) .filter(|value| !value.is_empty()) == Some("local_folder"); + let requests_filetree_first = query + .tree_view + .as_deref() + .map(str::trim) + .is_some_and(|value| value == "filetree"); let (sidebar_tree_html, file_tree_html) = if is_local_folder { let root_uri = query.root_uri.as_deref().unwrap_or_default(); ( @@ -168,6 +174,11 @@ pub async fn document_page_shell( &workspace_projection, Some(sidebar_tree_html.as_str()), Some(file_tree_html.as_str()), + if requests_filetree_first { + Some("filetree") + } else { + None + }, ); let workspace_name = workspace_projection.workspace_name.clone(); let page_subtree_json = diff --git a/rust/crates/mnote-web/src/ssr/pages/layout.rs b/rust/crates/mnote-web/src/ssr/pages/layout.rs index 06c54ae9..14a717eb 100644 --- a/rust/crates/mnote-web/src/ssr/pages/layout.rs +++ b/rust/crates/mnote-web/src/ssr/pages/layout.rs @@ -87,6 +87,7 @@ pub fn PageLayout( &projection, Some(sidebar_tree_html.as_str()), None, + None, ) }); let tree_live_bootstrap = serde_json::json!({ diff --git a/rust/crates/mnote-web/src/workspace_shell.rs b/rust/crates/mnote-web/src/workspace_shell.rs index c19cc936..381cd739 100644 --- a/rust/crates/mnote-web/src/workspace_shell.rs +++ b/rust/crates/mnote-web/src/workspace_shell.rs @@ -336,7 +336,7 @@ mod tests { Some("doc_root"), "开发用户 的工作区", ); - let html = render_workspace_shell_sidebar_html(&projection, None, None); + let html = render_workspace_shell_sidebar_html(&projection, None, None, None); assert!(html.contains("data-testid=\"wolai-sidebar-row\"")); assert!(html.contains("data-node-id=\"doc_root\"")); @@ -370,6 +370,7 @@ mod tests { &projection, Some(r#"
    "#), Some(r#"
      "#), + None, ); assert!(html.contains(r#"data-mnote-sidebar-tree-tab="page""#)); @@ -381,6 +382,37 @@ mod tests { assert!(!html.contains("wolai-file-tree-section")); } + #[test] + fn workspace_shell_sidebar_html_can_render_filetree_tab_initially_active() { + let dataset = json!({ + "workspaces": [{ "id": "ws_demo", "name": "开发用户 的工作区" }], + "documents": [ + { "id": "doc_root", "workspace_id": "ws_demo", "title": "Root", "parent_id": null, "sort_order": 0 } + ] + }); + let projection = build_workspace_shell_projection( + &dataset, + "ws_demo", + Some("doc_root"), + "开发用户 的工作区", + ); + let html = render_workspace_shell_sidebar_html( + &projection, + Some(r#"
        "#), + Some(r#"
          "#), + Some("filetree"), + ); + + assert!(html.contains( + r#"class="wolai-sidebar-tab wolai-sidebar-tab-muted" data-mnote-sidebar-tree-tab="page" aria-selected="false""# + )); + assert!(html.contains( + r#"class="wolai-sidebar-tab wolai-sidebar-tab-active" data-mnote-sidebar-tree-tab="filetree" aria-selected="true""# + )); + assert!(html.contains(r#"data-mnote-sidebar-tree-panel="page" hidden"#)); + assert!(html.contains(r#"data-mnote-sidebar-tree-panel="filetree">, file_tree_html: Option<&str>, + initial_tree_mode: Option<&str>, ) -> String { let starred_rows = if projection.starred_items.is_empty() { String::new() @@ -481,6 +515,40 @@ pub fn render_workspace_shell_sidebar_html( } else { String::new() }; + let filetree_initially_active = initial_tree_mode + .map(str::trim) + .is_some_and(|value| value == "filetree") + && !file_tree_content.trim().is_empty(); + let page_tab_class = if filetree_initially_active { + "wolai-sidebar-tab wolai-sidebar-tab-muted" + } else { + "wolai-sidebar-tab wolai-sidebar-tab-active" + }; + let page_aria_selected = if filetree_initially_active { + "false" + } else { + "true" + }; + let filetree_tab_class = if filetree_initially_active { + "wolai-sidebar-tab wolai-sidebar-tab-active" + } else { + "wolai-sidebar-tab wolai-sidebar-tab-muted" + }; + let filetree_aria_selected = if filetree_initially_active { + "true" + } else { + "false" + }; + let page_panel_hidden = if filetree_initially_active { + " hidden" + } else { + "" + }; + let filetree_panel_hidden = if filetree_initially_active { + "" + } else { + " hidden" + }; let bottom_entries = projection .bottom_entries .iter() @@ -526,7 +594,7 @@ pub fn render_workspace_shell_sidebar_html( ); format!( - r#"{status_markers}
          {}星标置顶
          {starred_rows}
          {my_pages}
          "#, + r#"{status_markers}
          {}星标置顶
          {starred_rows}
          {my_pages}
          {file_tree_content}
          "#, render_symbol("star", "wolai-section-icon"), render_symbol("folder_open", "wolai-folder-icon"), escape_html(&projection.workspace_id),