Optimize local folder file tree lazy loading
This commit is contained in:
@@ -2,7 +2,8 @@ use crate::app::AppState;
|
||||
use crate::context::RequestContext;
|
||||
use crate::error::WebError;
|
||||
use crate::routes::local_folder_source::{
|
||||
ensure_local_workspace_read_access_with_state, load_local_folder_file_tree_snapshot,
|
||||
ensure_local_workspace_read_access_with_state, load_local_folder_file_tree_children_snapshot,
|
||||
load_local_folder_file_tree_snapshot, load_local_folder_file_tree_snapshot_with_reveal,
|
||||
load_local_folder_page_tree_snapshot,
|
||||
};
|
||||
use crate::routes::query_support::resolve_effective_workspace_id;
|
||||
@@ -28,6 +29,7 @@ pub struct KernelProjectionQuery {
|
||||
pub max_results: Option<usize>,
|
||||
pub source_kind: Option<String>,
|
||||
pub root_uri: Option<String>,
|
||||
pub parent_relative_path: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
@@ -88,7 +90,27 @@ async fn project_projection(
|
||||
ensure_local_workspace_read_access_with_state(&state, &context, root_uri)
|
||||
.map_err(|error| error.with_context(&context))?;
|
||||
let snapshot = if projection == KernelProjectionKind::FileTree {
|
||||
load_local_folder_file_tree_snapshot(root_uri)?
|
||||
if let Some(parent_relative_path) = query
|
||||
.parent_relative_path
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
{
|
||||
load_local_folder_file_tree_children_snapshot(root_uri, parent_relative_path)?
|
||||
} else if query
|
||||
.root_node_id
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| !value.is_empty())
|
||||
.is_some()
|
||||
{
|
||||
load_local_folder_file_tree_snapshot_with_reveal(
|
||||
root_uri,
|
||||
query.root_node_id.as_deref(),
|
||||
)?
|
||||
} else {
|
||||
load_local_folder_file_tree_snapshot(root_uri)?
|
||||
}
|
||||
} else {
|
||||
load_local_folder_page_tree_snapshot(root_uri)?
|
||||
};
|
||||
@@ -371,6 +393,56 @@ mod tests {
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn local_folder_file_projection_can_load_direct_children_by_parent_path() {
|
||||
let root = std::env::temp_dir().join(format!(
|
||||
"mnote-local-kernel-children-projection-{}",
|
||||
std::process::id()
|
||||
));
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
std::fs::create_dir_all(root.join("docs").join("nested")).expect("create nested dirs");
|
||||
std::fs::write(root.join("docs").join("README.md"), "# README\n").expect("write readme");
|
||||
std::fs::write(root.join("docs").join("nested").join("deep.md"), "# Deep\n")
|
||||
.expect("write deep");
|
||||
let root_uri = format!("file://{}", root.display());
|
||||
initialize_local_workspace_for_actor("dev-user", &root_uri).expect("init local workspace");
|
||||
|
||||
let response = app()
|
||||
.oneshot(
|
||||
Request::builder()
|
||||
.uri(format!(
|
||||
"/api/tree/projections/file?workspaceId=local-ws:dev-user:my-space&sourceKind=local_folder&rootUri={root_uri}&parentRelativePath=docs"
|
||||
))
|
||||
.header("x-mnote-actor-id", "dev-user")
|
||||
.header("x-mnote-actor-type", "user")
|
||||
.body(Body::empty())
|
||||
.expect("request"),
|
||||
)
|
||||
.await
|
||||
.expect("response");
|
||||
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
let body = to_bytes(response.into_body(), usize::MAX)
|
||||
.await
|
||||
.expect("body");
|
||||
let payload: Value = serde_json::from_slice(&body).expect("json");
|
||||
let items = payload["result"]["items"].as_array().expect("items");
|
||||
let titles = items
|
||||
.iter()
|
||||
.filter_map(|item| item["title"].as_str())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(payload["result"]["parentRelativePath"], "docs");
|
||||
assert!(titles.contains(&"README.md"));
|
||||
assert!(titles.contains(&"nested"));
|
||||
assert!(!titles.contains(&"deep.md"));
|
||||
assert!(items
|
||||
.iter()
|
||||
.all(|item| item["parentNodeId"].as_str() == Some("local:node:docs")));
|
||||
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn tree_projection_routes_keep_ok_response_shape() {
|
||||
let response = app()
|
||||
|
||||
Reference in New Issue
Block a user