fix local office resource editing
- add local-folder OnlyOffice sign/callback writeback and edit-tab handling - align main resource tabs, attachment edit menu, slash isolation, and filetree context behavior - record Sidex/Hermes gap reviews and Reasonix task checklists
This commit is contained in:
@@ -1554,7 +1554,6 @@ fn create_default_local_workspace_for_actor_at_base(
|
||||
|
||||
let manifest = ensure_default_workspace_manifest(actor_id, &canonical_root)?;
|
||||
ensure_default_workspace_directories(&canonical_root)?;
|
||||
ensure_default_workspace_home_page(&canonical_root)?;
|
||||
Ok(json!({
|
||||
"ok": true,
|
||||
"workspace": {
|
||||
@@ -1782,36 +1781,6 @@ fn ensure_default_workspace_directories(root: &Path) -> Result<(), WebError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ensure_default_workspace_home_page(root: &Path) -> Result<(), WebError> {
|
||||
let page_dir = root.join("初始化的新页面");
|
||||
let page = page_dir.join("初始化的新页面.md");
|
||||
if page.exists() {
|
||||
return Ok(());
|
||||
}
|
||||
if !page.starts_with(root) {
|
||||
return Err(WebError::bad_request_code(
|
||||
"local_workspace_root_escape",
|
||||
"默认本地工作区首页不能越过 root",
|
||||
));
|
||||
}
|
||||
fs::create_dir_all(&page_dir).map_err(|error| {
|
||||
WebError::bad_request_code(
|
||||
"local_workspace_create_failed",
|
||||
format!(
|
||||
"无法创建默认本地工作区首页目录 {}: {error}",
|
||||
page_dir.display()
|
||||
),
|
||||
)
|
||||
})?;
|
||||
let content = "";
|
||||
fs::write(&page, content).map_err(|error| {
|
||||
WebError::bad_request_code(
|
||||
"local_workspace_create_failed",
|
||||
format!("无法创建默认本地工作区首页 {}: {error}", page.display()),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn local_workspace_manifest_path(root: &Path) -> PathBuf {
|
||||
root.join(".mnote").join("workspace.json")
|
||||
}
|
||||
@@ -3781,6 +3750,12 @@ fn move_local_directory(
|
||||
|
||||
fn trash_local_entry(root: &Path, entry_id: &str) -> Result<Value, WebError> {
|
||||
if let Some(directory) = resolve_local_directory_id(root, entry_id)? {
|
||||
// 若目录是页面 bundle(包含同名 .md),按 Markdown 页面生命周期入 trash
|
||||
if let Some(main_md) = nested_bundle_main_markdown(&directory) {
|
||||
let relative = normalize_relative_path(root, &main_md)?;
|
||||
let page_id = local_markdown_path_page_id(&relative);
|
||||
return trash_local_markdown_page(root, &page_id);
|
||||
}
|
||||
return trash_local_directory(root, entry_id, &directory);
|
||||
}
|
||||
if let Some(file) = resolve_local_raw_file_id(root, entry_id)? {
|
||||
@@ -6961,13 +6936,13 @@ mod tests {
|
||||
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,
|
||||
resolve_local_markdown_page_aggregate, save_local_markdown_page,
|
||||
update_local_markdown_title, validate_local_access_root, write_local_markdown_asset,
|
||||
write_local_markdown_page_body, write_local_mindmap_data, write_sync_conflict_report,
|
||||
LocalAccessGrantRequest, LocalAccessValidateRootRequest, LocalFileOpenQuery,
|
||||
LocalResourceWriteRequest, LocalShareGrantRequest, LocalUploadFile,
|
||||
local_folder_watch_revision, local_markdown_path_page_id,
|
||||
local_resource_write_editor_blocks, local_workspace_id, open_local_file,
|
||||
record_shared_cache, record_sync_pending_change, resolve_local_markdown_page_aggregate,
|
||||
save_local_markdown_page, update_local_markdown_title, validate_local_access_root,
|
||||
write_local_markdown_asset, write_local_markdown_page_body, write_local_mindmap_data,
|
||||
write_sync_conflict_report, LocalAccessGrantRequest, LocalAccessValidateRootRequest,
|
||||
LocalFileOpenQuery, LocalResourceWriteRequest, LocalShareGrantRequest, LocalUploadFile,
|
||||
SharedCacheRecordRequest, SyncConflictReportRequest, SyncPendingChangeRequest,
|
||||
};
|
||||
use crate::context::RequestContext;
|
||||
@@ -8216,10 +8191,10 @@ fn main() {}
|
||||
|
||||
assert_eq!(std::path::Path::new(root_path), expected_root.as_path());
|
||||
assert!(expected_root.join(".mnote").join("workspace.json").exists());
|
||||
assert!(expected_root
|
||||
.join("初始化的新页面")
|
||||
.join("初始化的新页面.md")
|
||||
.exists());
|
||||
assert!(
|
||||
!expected_root.join("初始化的新页面").exists(),
|
||||
"默认工作区不应创建'初始化的新页面'目录"
|
||||
);
|
||||
assert!(!expected_root.join("pages").exists());
|
||||
assert!(!expected_root.join("assets").exists());
|
||||
assert!(!expected_root.join("mindmaps").exists());
|
||||
@@ -8516,6 +8491,39 @@ fn main() {}
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn local_tree_command_delete_page_bundle_directory_uses_page_trash() {
|
||||
let root = temp_root("mnote-local-delete-page-bundle-dir");
|
||||
init_workspace(&root);
|
||||
std::fs::create_dir_all(root.join("Page")).expect("create page bundle");
|
||||
std::fs::write(root.join("Page").join("Page.md"), "# Page\n").expect("write markdown");
|
||||
std::fs::write(root.join("Page").join("asset.txt"), "asset").expect("write asset");
|
||||
let root_uri = format!("file://{}", root.display());
|
||||
let folder_id = format!("local-dir:{}", encode_local_id_segment("Page"));
|
||||
let page_id = local_markdown_path_page_id("Page/Page.md");
|
||||
|
||||
let result = execute_local_tree_command(&root_uri, "delete", &folder_id, None, None)
|
||||
.expect("delete page bundle");
|
||||
|
||||
assert!(
|
||||
!root.join("Page").exists(),
|
||||
"页面 bundle 目录应整体移入垃圾箱"
|
||||
);
|
||||
assert_eq!(result["id"].as_str(), Some(page_id.as_str()));
|
||||
assert_eq!(result["documentId"].as_str(), Some(page_id.as_str()));
|
||||
assert_eq!(result["resourceKind"].as_str(), Some("markdown_bundle"));
|
||||
assert_ne!(
|
||||
result["resourceKind"].as_str(),
|
||||
Some("local_directory"),
|
||||
"页面 bundle 目录不能作为普通资源目录进入垃圾箱"
|
||||
);
|
||||
let trash_path = result["trashPath"].as_str().expect("trashPath");
|
||||
assert!(root.join(trash_path).join("Page.md").is_file());
|
||||
assert!(root.join(trash_path).join("asset.txt").is_file());
|
||||
|
||||
let _ = std::fs::remove_dir_all(&root);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn local_tree_command_delete_local_file_id_uses_trash_index() {
|
||||
let root = temp_root("mnote-local-delete-local-file-id");
|
||||
|
||||
Reference in New Issue
Block a user