Align resource tabs with workbench review

This commit is contained in:
lix-2026
2026-05-20 19:04:05 +08:00
parent 4c62ea7e35
commit acf1305a7e
14 changed files with 964 additions and 13 deletions
@@ -2964,6 +2964,17 @@ pub fn execute_local_tree_command(
document_id: &str,
parent_id: Option<&str>,
title: Option<&str>,
) -> Result<Value, WebError> {
execute_local_tree_command_with_sort(root_uri, action, document_id, parent_id, title, None)
}
pub fn execute_local_tree_command_with_sort(
root_uri: &str,
action: &str,
document_id: &str,
parent_id: Option<&str>,
title: Option<&str>,
sort_order: Option<i64>,
) -> Result<Value, WebError> {
let root_path = parse_file_root_uri(root_uri)?;
let canonical_root = root_path.canonicalize().map_err(|error| {
@@ -2988,7 +2999,7 @@ pub fn execute_local_tree_command(
parent_id,
title.unwrap_or("外部文件"),
),
"move" => move_local_entry(&canonical_root, document_id, parent_id),
"move" => move_local_entry(&canonical_root, document_id, parent_id, sort_order),
"delete" | "trash" => trash_local_entry(&canonical_root, document_id),
"restore" => restore_local_entry(&canonical_root, document_id),
"purge" => purge_local_entry(&canonical_root, document_id),
@@ -3511,11 +3522,24 @@ fn move_local_entry(
root: &Path,
document_id: &str,
parent_id: Option<&str>,
sort_order: Option<i64>,
) -> Result<Value, WebError> {
if let Some(directory) = resolve_local_directory_id(root, document_id)? {
return move_local_directory(root, &directory, parent_id);
let result = if let Some(directory) = resolve_local_directory_id(root, document_id)? {
move_local_directory(root, &directory, parent_id)?
} else {
move_local_markdown_page(root, document_id, parent_id)?
};
if let Some(sort_order) = sort_order.filter(|value| *value >= 0) {
if let Some(object) = result.as_object() {
let mut enriched = object.clone();
enriched.insert(
"_unsupportedFields".to_string(),
json!({ "sortOrder": sort_order }),
);
return Ok(Value::Object(enriched));
}
}
move_local_markdown_page(root, document_id, parent_id)
Ok(result)
}
fn move_local_markdown_page(
@@ -6637,8 +6661,8 @@ mod tests {
create_local_access_grant, create_share_grant, editor_blocks_to_markdown_for_file,
encode_local_id_segment, ensure_local_path_read_access,
ensure_local_workspace_access_for_actor, ensure_local_workspace_read_access_for_actor,
execute_local_tree_command, get_local_access_policy, get_share_grants,
initialize_local_page_id, initialize_local_workspace_for_actor,
execute_local_tree_command, execute_local_tree_command_with_sort, get_local_access_policy,
get_share_grants, initialize_local_page_id, initialize_local_workspace_for_actor,
load_local_folder_file_tree_snapshot, load_local_folder_page_tree_snapshot,
local_folder_watch_revision, local_resource_write_editor_blocks, local_workspace_id,
open_local_file, record_shared_cache, record_sync_pending_change,
@@ -6653,7 +6677,7 @@ mod tests {
use axum::extract::{Extension, Path as AxumPath, Query};
use axum::http::{HeaderMap, Method, StatusCode};
use axum::Json;
use serde_json::Value;
use serde_json::{json, Value};
use std::sync::Mutex;
fn env_lock() -> &'static Mutex<()> {
@@ -8226,6 +8250,73 @@ fn main() {}
let _ = std::fs::remove_dir_all(&root);
}
#[test]
fn local_tree_command_delete_chinese_named_asset_in_subdir_uses_trash_index() {
let root = temp_root("mnote-local-delete-chinese-asset");
init_workspace(&root);
std::fs::create_dir_all(root.join("Page")).expect("create Page dir");
std::fs::write(root.join("Page").join("资源.ext"), b"chinese asset content")
.expect("write asset");
let root_uri = format!("file://{}", root.display());
let asset_id = "local-file:Page/资源.ext";
let result = execute_local_tree_command(&root_uri, "delete", asset_id, None, None)
.expect("delete chinese-named asset");
assert_eq!(result["resourceKind"].as_str(), Some("local_file"));
assert_eq!(result["trashEntryId"].as_str(), Some(asset_id));
assert!(!root.join("Page").join("资源.ext").exists());
assert!(root.join(".mnote").join("trash").join("资源.ext").exists());
let trash_index = std::fs::read_to_string(root.join(".mnote").join("trash-index.json"))
.expect("trash index");
assert!(
trash_index.contains(asset_id),
"trash index should contain {asset_id}: {trash_index}"
);
let restored = execute_local_tree_command(&root_uri, "restore", asset_id, None, None)
.expect("restore chinese-named asset");
assert_eq!(restored["documentId"].as_str(), Some(asset_id));
assert!(root.join("Page").join("资源.ext").is_file());
assert!(!root.join(".mnote").join("trash").join("资源.ext").exists());
execute_local_tree_command(&root_uri, "delete", asset_id, None, None)
.expect("re-delete chinese-named asset");
let purged = execute_local_tree_command(&root_uri, "purge", asset_id, None, None)
.expect("purge chinese-named asset");
assert_eq!(purged["ok"].as_bool(), Some(true));
assert!(!root.join(".mnote").join("trash").join("资源.ext").exists());
let trash_index_after_purge =
std::fs::read_to_string(root.join(".mnote").join("trash-index.json"))
.expect("trash index after purge");
assert!(
!trash_index_after_purge.contains(asset_id),
"trash index should not contain purged {asset_id}: {trash_index_after_purge}"
);
let _ = std::fs::remove_dir_all(&root);
}
#[test]
fn local_tree_command_move_with_sort_order_annotates_unsupported() {
let root = temp_root("mnote-local-move-sort-order");
init_workspace(&root);
std::fs::write(root.join("source.md"), "# Source\n").expect("write source");
let root_uri = format!("file://{}", root.display());
let doc_id = "local-md:source.md";
let result =
execute_local_tree_command_with_sort(&root_uri, "move", doc_id, None, None, Some(42))
.expect("move with sort_order should succeed");
assert_eq!(result["_unsupportedFields"]["sortOrder"], json!(42));
assert!(root.join("source.md").is_file());
let result_without_sort = execute_local_tree_command(&root_uri, "move", doc_id, None, None)
.expect("move without sort_order");
assert!(result_without_sort.get("_unsupportedFields").is_none());
let _ = std::fs::remove_dir_all(&root);
}
#[test]
fn local_markdown_save_refreshes_search_index_after_write() {
let root = temp_root("mnote-local-save-refresh-search-index");