diff --git a/rust/crates/mnote-web/src/routes/local_folder_source.rs b/rust/crates/mnote-web/src/routes/local_folder_source.rs index 58eb6b2b..0f38c537 100644 --- a/rust/crates/mnote-web/src/routes/local_folder_source.rs +++ b/rust/crates/mnote-web/src/routes/local_folder_source.rs @@ -4309,8 +4309,9 @@ fn resolve_local_directory_id(root: &Path, entry_id: &str) -> Result Result, WebError> { let trimmed = entry_id.trim(); let Some(relative_path) = trimmed - .strip_prefix("local:node:") + .strip_prefix("local-file:") .or_else(|| trimmed.strip_prefix("local:asset:")) + .or_else(|| trimmed.strip_prefix("local:node:")) else { return Ok(None); }; @@ -7675,6 +7676,37 @@ fn main() {} 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"); + init_workspace(&root); + std::fs::create_dir_all(root.join("docs")).expect("create docs"); + std::fs::write(root.join("docs").join("photo.png"), b"png").expect("write asset"); + let root_uri = format!("file://{}", root.display()); + + let result = execute_local_tree_command( + &root_uri, + "delete", + "local-file:docs/photo.png", + None, + None, + ) + .expect("delete local-file asset"); + + assert_eq!(result["resourceKind"].as_str(), Some("local_file")); + assert_eq!( + result["trashEntryId"].as_str(), + Some("local-file:docs/photo.png") + ); + assert!(!root.join("docs").join("photo.png").exists()); + assert!(root.join(".mnote").join("trash").join("photo.png").exists()); + let trash_index = std::fs::read_to_string(root.join(".mnote").join("trash-index.json")) + .expect("trash index"); + assert!(trash_index.contains("local-file:docs/photo.png")); + + 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"); diff --git a/rust/crates/mnote-web/src/routes/resource_trash.rs b/rust/crates/mnote-web/src/routes/resource_trash.rs index d7b0c6f7..a7525fdb 100644 --- a/rust/crates/mnote-web/src/routes/resource_trash.rs +++ b/rust/crates/mnote-web/src/routes/resource_trash.rs @@ -4,11 +4,14 @@ use crate::error::WebError; use crate::routes::command_support::{ execute_runtime_command_via_convex_with_artifacts, runtime_context, }; +use crate::routes::local_folder_source::{ + ensure_local_workspace_access, execute_local_tree_command, +}; use crate::transport::convex::{ execute_convex_mutation_by_name, execute_convex_query_by_name, persist_runtime_command_artifacts, }; -use axum::extract::{Extension, Path, State}; +use axum::extract::{Extension, Path, Query, State}; use axum::http::{HeaderMap, HeaderName, HeaderValue, StatusCode}; use axum::Json; use bridge_runtime::{ @@ -51,6 +54,13 @@ pub struct MindmapTrashRequest { pub action: String, } +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct MindmapLocalQuery { + pub source_kind: Option, + pub root_uri: Option, +} + #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct TableTrashRequest { @@ -761,10 +771,30 @@ pub async fn mindmap_delete( State(state): State, Extension(context): Extension, Path((doc_id, mindmap_id)): Path<(String, String)>, + Query(query): Query, ) -> Result<(StatusCode, HeaderMap, Json), WebError> { let user_id = current_user_id(&state, &context).await; let doc_id = require_id(&context, &doc_id, "docId")?; let mindmap_id = require_id(&context, &mindmap_id, "mindmapId")?; + if query.source_kind.as_deref() == Some("local_folder") { + let root_uri = query + .root_uri + .as_deref() + .map(str::trim) + .filter(|value| !value.is_empty()) + .ok_or_else(|| { + WebError::bad_request_code("local_folder_root_required", "缺少本地文件夹 rootUri") + .with_context(&context) + })?; + ensure_local_workspace_access(&context, root_uri) + .map_err(|error| error.with_context(&context))?; + let execution = execute_local_tree_command(root_uri, "delete", &mindmap_id, None, None) + .map_err(|error| error.with_context(&context))?; + return Ok(ok_response( + &context, + annotate_resource_lifecycle_result(execution, "tree.resource.archive", "mindmap"), + )); + } let workspace_id = fetch_document_workspace_id(&state, &context, doc_id).await; let command = resource_command( &context, @@ -1199,6 +1229,64 @@ mod tests { serde_json::from_slice(&body).expect("json") } + #[tokio::test] + async fn local_folder_mindmap_delete_moves_resource_file_to_trash() { + let root = + std::env::temp_dir().join(format!("mnote-local-mindmap-trash-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&root); + std::fs::create_dir_all(root.join("Page")).expect("create page"); + std::fs::write(root.join("Page").join("Page.md"), "# Page\n").expect("write md"); + std::fs::write( + root.join("Page").join("map.mindmap.json"), + r#"{"data":{"uid":"root","text":"KMIND"},"children":[]}"#, + ) + .expect("write mindmap"); + let root_uri = format!("file://{}", root.display()); + crate::routes::local_folder_source::initialize_local_workspace_for_actor( + "user_real", + &root_uri, + ) + .expect("init workspace"); + + let response = app() + .oneshot( + Request::builder() + .method("DELETE") + .uri(format!( + "/api/mindmap/local-md:Page~2FPage.md/local-file:Page%2Fmap.mindmap.json?sourceKind=local_folder&rootUri={root_uri}" + )) + .header("x-mnote-actor-id", "user_real") + .header("x-mnote-actor-type", "user") + .body(Body::empty()) + .expect("request"), + ) + .await + .expect("response"); + let status = response.status(); + let body = to_bytes(response.into_body(), usize::MAX) + .await + .expect("body"); + let payload: Value = serde_json::from_slice(&body).expect("json"); + + assert_eq!(status, StatusCode::OK, "{}", String::from_utf8_lossy(&body)); + assert_eq!( + payload["result"]["canonicalCommand"], + "tree.resource.archive" + ); + assert_eq!(payload["result"]["sourceKind"], "local_folder"); + assert!(!root.join("Page").join("map.mindmap.json").exists()); + assert!(root + .join(".mnote") + .join("trash") + .join("map.mindmap.json") + .exists()); + let trash_index = std::fs::read_to_string(root.join(".mnote").join("trash-index.json")) + .expect("trash index"); + assert!(trash_index.contains("local-file:Page/map.mindmap.json")); + + let _ = std::fs::remove_dir_all(&root); + } + #[tokio::test] async fn media_trash_routes_delete_restore_purge_and_empty() { let deleted = post_json( diff --git a/rust/crates/mnote-web/src/routes/tree.rs b/rust/crates/mnote-web/src/routes/tree.rs index 09d38b56..d2fb2d92 100644 --- a/rust/crates/mnote-web/src/routes/tree.rs +++ b/rust/crates/mnote-web/src/routes/tree.rs @@ -7567,7 +7567,7 @@ mod tests { std::fs::write(root.join("docs").join("photo.png"), b"png").expect("write asset"); let root_uri = format!("file://{}", root.display()); init_local_workspace(&root, "user_test"); - let asset_id = "local:asset:docs/photo.png"; + let asset_id = "local-file:docs/photo.png"; let delete_response = app() .oneshot( diff --git a/rust/crates/mnote-web/src/ssr/pages/layout.rs b/rust/crates/mnote-web/src/ssr/pages/layout.rs index a2e5c9ea..d98006c0 100644 --- a/rust/crates/mnote-web/src/ssr/pages/layout.rs +++ b/rust/crates/mnote-web/src/ssr/pages/layout.rs @@ -2648,15 +2648,20 @@ const SIDEBAR_TREE_JS: &str = r##" function appendUploadedAssetRow(asset, documentId) { var assetId = String(asset && asset.id || '').trim(); - if (!assetId) return; - if (revealFileTreeAssetRow(assetId)) return; + if (!assetId) return false; + if (revealFileTreeAssetRow(assetId)) return true; + var objectKind = String(asset && (asset.objectKind || asset.resourceKind || '') || '').trim(); + if (!objectKind && (String(asset && (asset.asset_type || asset.assetType) || '').trim() === 'mindmap' || /\.mindmap\.json$/i.test(assetId))) { + objectKind = 'mindmap'; + } var targetDocumentId = String(documentId || asset.document_id || asset.documentId || currentDocumentId() || '').trim(); var parentRow = targetDocumentId ? document.querySelector('.tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape('doc:' + targetDocumentId) + '"]') : null; + if (!parentRow && currentSourceKind() === 'local_folder' && objectKind === 'mindmap') return false; if (!parentRow) parentRow = document.querySelector('.tree-row[data-shell-mode="filetree"][data-row-kind="document"]'); var root = document.querySelector('#sidebar-file-tree-root .tree-root'); - if (!root && !parentRow) return; + if (!root && !parentRow) return false; var parentLi = parentRow ? parentRow.closest('.tree-node') : null; var children = parentLi ? parentLi.querySelector(':scope > .tree-children') : null; if (parentLi && !children) { @@ -2675,10 +2680,6 @@ const SIDEBAR_TREE_JS: &str = r##" var container = children || root; var li = document.createElement('li'); li.className = 'tree-node'; - var objectKind = String(asset && (asset.objectKind || asset.resourceKind || '') || '').trim(); - if (!objectKind && (String(asset && (asset.asset_type || asset.assetType) || '').trim() === 'mindmap' || /\.mindmap\.json$/i.test(assetId))) { - objectKind = 'mindmap'; - } var objectIdentity = { objectKind: objectKind || 'attachment', documentId: targetDocumentId || null, @@ -2697,6 +2698,7 @@ const SIDEBAR_TREE_JS: &str = r##" container.appendChild(li); revealFileTreeRow(li.querySelector('.tree-row')); document.documentElement.setAttribute('data-mnote-last-upload-asset-id', assetId); + return true; } function removeFileTreeAssetRow(assetId) { @@ -2826,7 +2828,8 @@ const SIDEBAR_TREE_JS: &str = r##" if (!target || !target.documentId || !target.mindmapId) return; var asset = mindmapAssetFromTarget(target.documentId, target.mindmapId, payload && payload.writeResult); if (!asset) return; - appendUploadedAssetRow(asset, target.documentId); + var appended = appendUploadedAssetRow(asset, target.documentId); + if (!appended && currentSourceKind() === 'local_folder') void refreshLocalFolderSidebarSnapshot(); document.documentElement.setAttribute('data-mnote-assets-local-applied', 'true'); document.documentElement.setAttribute('data-mnote-last-mindmap-asset-id', asset.id || target.mindmapId); } @@ -8914,6 +8917,8 @@ mod tests { assert!(SIDEBAR_TREE_JS.contains("withLocalMindmapSourceParams")); assert!(SIDEBAR_TREE_JS.contains("url.searchParams.set('sourceKind', 'local_folder')")); assert!(SIDEBAR_TREE_JS.contains("url.searchParams.set('rootUri', rootUri)")); + assert!(SIDEBAR_TREE_JS.contains("if (!parentRow && currentSourceKind() === 'local_folder' && objectKind === 'mindmap') return false;")); + assert!(SIDEBAR_TREE_JS.contains("if (!appended && currentSourceKind() === 'local_folder') void refreshLocalFolderSidebarSnapshot();")); assert!(SIDEBAR_TREE_JS .contains("data-mnote-last-mindmap-asset-open-mode', 'local-mindmap-object-shell'")); assert!(SIDEBAR_TREE_JS.contains("buildLocalOnlyOfficeOpenUrl")); diff --git a/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island.d.ts b/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island.d.ts index bb66b8a4..2ea9a196 100644 --- a/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island.d.ts +++ b/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island.d.ts @@ -48,32 +48,32 @@ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembl export interface InitOutput { readonly memory: WebAssembly.Memory; - readonly mount: (a: any, b: any) => [number, number, number]; readonly mount_mindmap_shell: (a: any, b: any) => [number, number, number]; - readonly unmount: (a: number) => [number, number]; readonly unmount_mindmap_shell: (a: number) => [number, number]; - readonly __wbg_intounderlyingbytesource_free: (a: number, b: number) => void; - readonly intounderlyingbytesource_autoAllocateChunkSize: (a: number) => number; - readonly intounderlyingbytesource_cancel: (a: number) => void; - readonly intounderlyingbytesource_pull: (a: number, b: any) => any; - readonly intounderlyingbytesource_start: (a: number, b: any) => void; - readonly intounderlyingbytesource_type: (a: number) => number; + readonly mount: (a: any, b: any) => [number, number, number]; + readonly unmount: (a: number) => [number, number]; readonly __wbg_intounderlyingsink_free: (a: number, b: number) => void; - readonly intounderlyingsink_abort: (a: number, b: any) => any; - readonly intounderlyingsink_close: (a: number) => any; readonly intounderlyingsink_write: (a: number, b: any) => any; + readonly intounderlyingsink_close: (a: number) => any; + readonly intounderlyingsink_abort: (a: number, b: any) => any; + readonly __wbg_intounderlyingbytesource_free: (a: number, b: number) => void; + readonly intounderlyingbytesource_type: (a: number) => number; + readonly intounderlyingbytesource_autoAllocateChunkSize: (a: number) => number; + readonly intounderlyingbytesource_start: (a: number, b: any) => void; + readonly intounderlyingbytesource_pull: (a: number, b: any) => any; + readonly intounderlyingbytesource_cancel: (a: number) => void; readonly __wbg_intounderlyingsource_free: (a: number, b: number) => void; - readonly intounderlyingsource_cancel: (a: number) => void; readonly intounderlyingsource_pull: (a: number, b: any) => any; - readonly wasm_bindgen__convert__closures_____invoke__h854f4676fa692669: (a: number, b: number, c: any) => [number, number]; - readonly wasm_bindgen__convert__closures_____invoke__h1a94ffe1b1ed8350: (a: number, b: number, c: any, d: any) => void; - readonly wasm_bindgen__convert__closures_____invoke__h280638b828d42e1f: (a: number, b: number, c: any) => void; - readonly wasm_bindgen__convert__closures_____invoke__h4916074fb8b30849: (a: number, b: number, c: any) => void; - readonly wasm_bindgen__convert__closures_____invoke__h10d35e1548938147: (a: number, b: number, c: any) => void; - readonly wasm_bindgen__convert__closures_____invoke__h280638b828d42e1f_4: (a: number, b: number, c: any) => void; - readonly wasm_bindgen__convert__closures_____invoke__h68fbbcff54846097: (a: number, b: number) => void; - readonly wasm_bindgen__convert__closures_____invoke__had164c21c04063ef: (a: number, b: number) => void; - readonly wasm_bindgen__convert__closures_____invoke__h5921057d3102c7f1: (a: number, b: number) => void; + readonly intounderlyingsource_cancel: (a: number) => void; + readonly wasm_bindgen__convert__closures_____invoke__h3a3182d847094e12: (a: number, b: number, c: any) => [number, number]; + readonly wasm_bindgen__convert__closures_____invoke__h0accad0f5d87788a: (a: number, b: number, c: any, d: any) => void; + readonly wasm_bindgen__convert__closures_____invoke__h396914cf76a9e7a5: (a: number, b: number, c: any) => void; + readonly wasm_bindgen__convert__closures_____invoke__hde8e7b4803478c08: (a: number, b: number, c: any) => void; + readonly wasm_bindgen__convert__closures_____invoke__h0abd2b2fe4652e2a: (a: number, b: number, c: any) => void; + readonly wasm_bindgen__convert__closures_____invoke__h396914cf76a9e7a5_4: (a: number, b: number, c: any) => void; + readonly wasm_bindgen__convert__closures_____invoke__h794babeffd4f821f: (a: number, b: number) => void; + readonly wasm_bindgen__convert__closures_____invoke__h2b648e7ac8ec1fb5: (a: number, b: number) => void; + readonly wasm_bindgen__convert__closures_____invoke__h0b7fb40a8610550c: (a: number, b: number) => void; readonly __wbindgen_malloc: (a: number, b: number) => number; readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number; readonly __externref_table_alloc: () => number; diff --git a/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island.js b/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island.js index a7c4fe62..dbc574e3 100644 --- a/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island.js +++ b/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island.js @@ -824,7 +824,7 @@ function __wbg_get_imports() { const a = state0.a; state0.a = 0; try { - return wasm_bindgen__convert__closures_____invoke__h1a94ffe1b1ed8350(a, state0.b, arg0, arg1); + return wasm_bindgen__convert__closures_____invoke__h0accad0f5d87788a(a, state0.b, arg0, arg1); } finally { state0.a = a; } @@ -1223,43 +1223,43 @@ function __wbg_get_imports() { } }, arguments); }, __wbindgen_cast_0000000000000001: function(arg0, arg1) { - // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1114, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. - const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h280638b828d42e1f); + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1129, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h396914cf76a9e7a5); return ret; }, __wbindgen_cast_0000000000000002: function(arg0, arg1) { - // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1176, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`. - const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h854f4676fa692669); + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 1181, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h3a3182d847094e12); return ret; }, __wbindgen_cast_0000000000000003: function(arg0, arg1) { - // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 984, ret: Unit, inner_ret: Some(Unit) }, mutable: false }) -> Externref`. - const ret = makeClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h4916074fb8b30849); + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [Externref], shim_idx: 957, ret: Unit, inner_ret: Some(Unit) }, mutable: false }) -> Externref`. + const ret = makeClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__hde8e7b4803478c08); return ret; }, __wbindgen_cast_0000000000000004: function(arg0, arg1) { - // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 1082, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. - const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h10d35e1548938147); + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 1079, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h0abd2b2fe4652e2a); return ret; }, __wbindgen_cast_0000000000000005: function(arg0, arg1) { - // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 1114, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. - const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h280638b828d42e1f_4); + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [NamedExternref("Event")], shim_idx: 1129, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h396914cf76a9e7a5_4); return ret; }, __wbindgen_cast_0000000000000006: function(arg0, arg1) { - // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 1084, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. - const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h68fbbcff54846097); + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 1081, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h794babeffd4f821f); return ret; }, __wbindgen_cast_0000000000000007: function(arg0, arg1) { - // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 1099, ret: Unit, inner_ret: Some(Unit) }, mutable: false }) -> Externref`. - const ret = makeClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__had164c21c04063ef); + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 1096, ret: Unit, inner_ret: Some(Unit) }, mutable: false }) -> Externref`. + const ret = makeClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h2b648e7ac8ec1fb5); return ret; }, __wbindgen_cast_0000000000000008: function(arg0, arg1) { - // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 1116, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. - const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h5921057d3102c7f1); + // Cast intrinsic for `Closure(Closure { owned: true, function: Function { arguments: [], shim_idx: 1132, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`. + const ret = makeMutClosure(arg0, arg1, wasm_bindgen__convert__closures_____invoke__h0b7fb40a8610550c); return ret; }, __wbindgen_cast_0000000000000009: function(arg0) { @@ -1302,43 +1302,43 @@ function __wbg_get_imports() { }; } -function wasm_bindgen__convert__closures_____invoke__h68fbbcff54846097(arg0, arg1) { - wasm.wasm_bindgen__convert__closures_____invoke__h68fbbcff54846097(arg0, arg1); +function wasm_bindgen__convert__closures_____invoke__h794babeffd4f821f(arg0, arg1) { + wasm.wasm_bindgen__convert__closures_____invoke__h794babeffd4f821f(arg0, arg1); } -function wasm_bindgen__convert__closures_____invoke__had164c21c04063ef(arg0, arg1) { - wasm.wasm_bindgen__convert__closures_____invoke__had164c21c04063ef(arg0, arg1); +function wasm_bindgen__convert__closures_____invoke__h2b648e7ac8ec1fb5(arg0, arg1) { + wasm.wasm_bindgen__convert__closures_____invoke__h2b648e7ac8ec1fb5(arg0, arg1); } -function wasm_bindgen__convert__closures_____invoke__h5921057d3102c7f1(arg0, arg1) { - wasm.wasm_bindgen__convert__closures_____invoke__h5921057d3102c7f1(arg0, arg1); +function wasm_bindgen__convert__closures_____invoke__h0b7fb40a8610550c(arg0, arg1) { + wasm.wasm_bindgen__convert__closures_____invoke__h0b7fb40a8610550c(arg0, arg1); } -function wasm_bindgen__convert__closures_____invoke__h280638b828d42e1f(arg0, arg1, arg2) { - wasm.wasm_bindgen__convert__closures_____invoke__h280638b828d42e1f(arg0, arg1, arg2); +function wasm_bindgen__convert__closures_____invoke__h396914cf76a9e7a5(arg0, arg1, arg2) { + wasm.wasm_bindgen__convert__closures_____invoke__h396914cf76a9e7a5(arg0, arg1, arg2); } -function wasm_bindgen__convert__closures_____invoke__h4916074fb8b30849(arg0, arg1, arg2) { - wasm.wasm_bindgen__convert__closures_____invoke__h4916074fb8b30849(arg0, arg1, arg2); +function wasm_bindgen__convert__closures_____invoke__hde8e7b4803478c08(arg0, arg1, arg2) { + wasm.wasm_bindgen__convert__closures_____invoke__hde8e7b4803478c08(arg0, arg1, arg2); } -function wasm_bindgen__convert__closures_____invoke__h10d35e1548938147(arg0, arg1, arg2) { - wasm.wasm_bindgen__convert__closures_____invoke__h10d35e1548938147(arg0, arg1, arg2); +function wasm_bindgen__convert__closures_____invoke__h0abd2b2fe4652e2a(arg0, arg1, arg2) { + wasm.wasm_bindgen__convert__closures_____invoke__h0abd2b2fe4652e2a(arg0, arg1, arg2); } -function wasm_bindgen__convert__closures_____invoke__h280638b828d42e1f_4(arg0, arg1, arg2) { - wasm.wasm_bindgen__convert__closures_____invoke__h280638b828d42e1f_4(arg0, arg1, arg2); +function wasm_bindgen__convert__closures_____invoke__h396914cf76a9e7a5_4(arg0, arg1, arg2) { + wasm.wasm_bindgen__convert__closures_____invoke__h396914cf76a9e7a5_4(arg0, arg1, arg2); } -function wasm_bindgen__convert__closures_____invoke__h854f4676fa692669(arg0, arg1, arg2) { - const ret = wasm.wasm_bindgen__convert__closures_____invoke__h854f4676fa692669(arg0, arg1, arg2); +function wasm_bindgen__convert__closures_____invoke__h3a3182d847094e12(arg0, arg1, arg2) { + const ret = wasm.wasm_bindgen__convert__closures_____invoke__h3a3182d847094e12(arg0, arg1, arg2); if (ret[1]) { throw takeFromExternrefTable0(ret[0]); } } -function wasm_bindgen__convert__closures_____invoke__h1a94ffe1b1ed8350(arg0, arg1, arg2, arg3) { - wasm.wasm_bindgen__convert__closures_____invoke__h1a94ffe1b1ed8350(arg0, arg1, arg2, arg3); +function wasm_bindgen__convert__closures_____invoke__h0accad0f5d87788a(arg0, arg1, arg2, arg3) { + wasm.wasm_bindgen__convert__closures_____invoke__h0accad0f5d87788a(arg0, arg1, arg2, arg3); } diff --git a/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island_bg.wasm b/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island_bg.wasm index 9a624d51..4480c762 100644 Binary files a/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island_bg.wasm and b/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island_bg.wasm differ diff --git a/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island_bg.wasm.d.ts b/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island_bg.wasm.d.ts index 521e839f..d9d33c43 100644 --- a/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island_bg.wasm.d.ts +++ b/rust/spikes/leptos-tiptap-spike/generated/island/mnote-leptos-tiptap-spike-island_bg.wasm.d.ts @@ -1,32 +1,32 @@ /* tslint:disable */ /* eslint-disable */ export const memory: WebAssembly.Memory; -export const mount: (a: any, b: any) => [number, number, number]; export const mount_mindmap_shell: (a: any, b: any) => [number, number, number]; -export const unmount: (a: number) => [number, number]; export const unmount_mindmap_shell: (a: number) => [number, number]; -export const __wbg_intounderlyingbytesource_free: (a: number, b: number) => void; -export const intounderlyingbytesource_autoAllocateChunkSize: (a: number) => number; -export const intounderlyingbytesource_cancel: (a: number) => void; -export const intounderlyingbytesource_pull: (a: number, b: any) => any; -export const intounderlyingbytesource_start: (a: number, b: any) => void; -export const intounderlyingbytesource_type: (a: number) => number; +export const mount: (a: any, b: any) => [number, number, number]; +export const unmount: (a: number) => [number, number]; export const __wbg_intounderlyingsink_free: (a: number, b: number) => void; -export const intounderlyingsink_abort: (a: number, b: any) => any; -export const intounderlyingsink_close: (a: number) => any; export const intounderlyingsink_write: (a: number, b: any) => any; +export const intounderlyingsink_close: (a: number) => any; +export const intounderlyingsink_abort: (a: number, b: any) => any; +export const __wbg_intounderlyingbytesource_free: (a: number, b: number) => void; +export const intounderlyingbytesource_type: (a: number) => number; +export const intounderlyingbytesource_autoAllocateChunkSize: (a: number) => number; +export const intounderlyingbytesource_start: (a: number, b: any) => void; +export const intounderlyingbytesource_pull: (a: number, b: any) => any; +export const intounderlyingbytesource_cancel: (a: number) => void; export const __wbg_intounderlyingsource_free: (a: number, b: number) => void; -export const intounderlyingsource_cancel: (a: number) => void; export const intounderlyingsource_pull: (a: number, b: any) => any; -export const wasm_bindgen__convert__closures_____invoke__h854f4676fa692669: (a: number, b: number, c: any) => [number, number]; -export const wasm_bindgen__convert__closures_____invoke__h1a94ffe1b1ed8350: (a: number, b: number, c: any, d: any) => void; -export const wasm_bindgen__convert__closures_____invoke__h280638b828d42e1f: (a: number, b: number, c: any) => void; -export const wasm_bindgen__convert__closures_____invoke__h4916074fb8b30849: (a: number, b: number, c: any) => void; -export const wasm_bindgen__convert__closures_____invoke__h10d35e1548938147: (a: number, b: number, c: any) => void; -export const wasm_bindgen__convert__closures_____invoke__h280638b828d42e1f_4: (a: number, b: number, c: any) => void; -export const wasm_bindgen__convert__closures_____invoke__h68fbbcff54846097: (a: number, b: number) => void; -export const wasm_bindgen__convert__closures_____invoke__had164c21c04063ef: (a: number, b: number) => void; -export const wasm_bindgen__convert__closures_____invoke__h5921057d3102c7f1: (a: number, b: number) => void; +export const intounderlyingsource_cancel: (a: number) => void; +export const wasm_bindgen__convert__closures_____invoke__h3a3182d847094e12: (a: number, b: number, c: any) => [number, number]; +export const wasm_bindgen__convert__closures_____invoke__h0accad0f5d87788a: (a: number, b: number, c: any, d: any) => void; +export const wasm_bindgen__convert__closures_____invoke__h396914cf76a9e7a5: (a: number, b: number, c: any) => void; +export const wasm_bindgen__convert__closures_____invoke__hde8e7b4803478c08: (a: number, b: number, c: any) => void; +export const wasm_bindgen__convert__closures_____invoke__h0abd2b2fe4652e2a: (a: number, b: number, c: any) => void; +export const wasm_bindgen__convert__closures_____invoke__h396914cf76a9e7a5_4: (a: number, b: number, c: any) => void; +export const wasm_bindgen__convert__closures_____invoke__h794babeffd4f821f: (a: number, b: number) => void; +export const wasm_bindgen__convert__closures_____invoke__h2b648e7ac8ec1fb5: (a: number, b: number) => void; +export const wasm_bindgen__convert__closures_____invoke__h0b7fb40a8610550c: (a: number, b: number) => void; export const __wbindgen_malloc: (a: number, b: number) => number; export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number; export const __externref_table_alloc: () => number; diff --git a/rust/spikes/leptos-tiptap-spike/src/lib.rs b/rust/spikes/leptos-tiptap-spike/src/lib.rs index 9049ba84..08827c1a 100644 --- a/rust/spikes/leptos-tiptap-spike/src/lib.rs +++ b/rust/spikes/leptos-tiptap-spike/src/lib.rs @@ -3349,6 +3349,38 @@ mod tests { "mnote.leptos-tiptap-spike.document:mindmap-object:doc-a:mind-a" ); } + + #[test] + fn mindmap_empty_paragraph_has_textblock_boundary_size() { + let node = json!({ + "type": "paragraph", + "attrs": { + "mnoteBlockType": "mindmap", + "mindmapId": "思维导图123456.json", + "rootNodeId": "root", + "projectionVersion": 1 + } + }); + assert_eq!(prosemirror_node_size(&node), Some(2)); + + let document = json!({ + "type": "doc", + "content": [ + {"type": "paragraph", "content": [{"type": "text", "text": "上"}]}, + node, + {"type": "paragraph", "content": [{"type": "text", "text": "下"}]} + ] + }); + + assert_eq!( + top_level_block_boundary_position(&document, 1, true), + Some(3) + ); + assert_eq!( + top_level_block_boundary_position(&document, 1, false), + Some(5) + ); + } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -5335,7 +5367,13 @@ fn prosemirror_node_size(node: &Value) -> Option { Some("hardBreak") | Some("horizontalRule") => Some(1), _ => { let Some(children) = node.get("content").and_then(Value::as_array) else { - return Some(1); + return Some(match node.get("type").and_then(Value::as_str) { + Some("paragraph") | Some("heading") | Some("blockquote") + | Some("codeBlock") | Some("bulletList") | Some("orderedList") + | Some("taskList") | Some("listItem") | Some("taskItem") | Some("table") + | Some("tableRow") | Some("tableCell") | Some("tableHeader") => 2, + _ => 1, + }); }; let content_size = children.iter().try_fold(0_u32, |acc, child| {