From 863e68b12686e2e777afc83006859cb590641952 Mon Sep 17 00:00:00 2001 From: lix-2026 Date: Mon, 25 May 2026 09:38:50 +0800 Subject: [PATCH] refactor: extract mindmap fetch helpers --- ...0-browser-runtime-followup-checklist-v1.md | 31 +++---- .../mnote-web/browser/filetree-runtime.js | 80 ++++++++++++++++++- rust/crates/mnote-web/src/ssr/pages/layout.rs | 54 ++++++++++--- 3 files changed, 141 insertions(+), 24 deletions(-) diff --git a/design/03-rust-web/process/3-20-browser-runtime-followup-checklist-v1.md b/design/03-rust-web/process/3-20-browser-runtime-followup-checklist-v1.md index 789c41d3..db9224b1 100644 --- a/design/03-rust-web/process/3-20-browser-runtime-followup-checklist-v1.md +++ b/design/03-rust-web/process/3-20-browser-runtime-followup-checklist-v1.md @@ -6,7 +6,7 @@ ## 1. 目标 -在 `3-19` 已归档的基础上,继续把仍留在 Rust inline / 主壳大 runtime 中的浏览器行为切成可审计模块。Codex 维护本文件作为事实源,Reasonix 只承接短批次审计、窄范围实现或浏览器 smoke;当前 goal 下每批最多 2 个 worker。 +在 `3-19` 已归档的基础上,继续把仍留在 Rust inline / 主壳大 runtime 中的浏览器行为切成可审计模块。Codex 维护本文件作为事实源,Reasonix 只承接短批次审计、窄范围实现或浏览器 smoke;当前 goal 下每批最多 4 个 worker。 ## 2. 本轮边界 @@ -185,17 +185,17 @@ UI / 浏览器可见项必须有真实浏览器截图或结构化 smoke 证据 - 修改:`filetree-runtime.js` 新增并导出 `markLocalFolderWatchApplied(value)`;`layout.rs` 的同名 wrapper 优先委托 runtime,inline fallback 保留 `data-mnote-local-folder-watch-applied="projection"` 行为。 - 边界:未改 projection fetch URL、JSON 渲染、selection/focus/sidebar shell 副作用、附件存在性刷新、tree live SSE consumer;本批只外置刷新完成证据标记。 - 已验证:`node --check rust/crates/mnote-web/browser/filetree-runtime.js`、`git diff --check`、`cargo fmt --manifest-path rust/Cargo.toml --all --check`、`cargo check --manifest-path rust/Cargo.toml -p mnote-web`、`cargo test --manifest-path rust/Cargo.toml -p mnote-web filetree_runtime -- --test-threads=1`。 -- 2026-05-25:Batch AC 按用户纠正继续采用独立 worktree 流程;本轮实际 3 个 worker,符合当前 goal 每批最多 4 个 worker 的上限;任务书均写入各 worktree `tmp/`,未新增主工作区 `.codex/reasonix-tasks`。 +- 2026-05-25:Batch AC 按当前 4-worker 口径继续采用独立 worktree 流程;本轮实际 3 个 worker,符合当前 goal 上限;任务书均写入各 worktree `tmp/`,未新增主工作区 `.codex/reasonix-tasks`。 - Worker C `/mnt/Data1T/mnote-worktrees/0525-ac-worker-c-3-20-conflict-action-boundary`,Reasonix run `reasonix-2026-05-24T22-52-30-772Z-464df4b4`,Codex 已读取 Hindsight recall、`process-handoff.md/json`、`result.json`,并核对 worktree `git status --short` / `git diff --stat` 为空。 - 审计结论经 Codex 复核后采纳:`acceptDiskVersion`、`keepCurrentEditorVersion`、`writeMergedConflictResult` 仍强依赖 fetch、persist、session views、Tiptap hydrate、conflict key 计算和 `setSessionStatus`,不应整体迁入 `document-conflict-panel-runtime.js`;共享的 session 状态字段重置块暂不外置,以保持 runtime=DOM/promise wrapper、shell=业务编排的边界。 - Worker D `/mnt/Data1T/mnote-worktrees/0525-ac-worker-d-smoke-regression`,Reasonix run `reasonix-2026-05-24T22-52-30-854Z-dfad6786`,源码零 diff;`task489`、`task488`、`task487`、`task451` 在 3001 均通过,其中 `task451` 覆盖 accept-disk、keep-current、merge-save、agent-conflict-source。 - 未完成:conflict action 业务逻辑仍留在 `web_shell.rs`;secondary pane conflict 专项 smoke 仍可后续单独补强。 -- 2026-05-25:Batch AD 采用 3 个独立 worktree worker(B/C/D),符合当前 goal 每批最多 4 个 worker 的上限;任务书均写入各 worktree `tmp/`,未新增主工作区 `.codex/reasonix-tasks`。 +- 2026-05-25:Batch AD 采用 3 个独立 worktree worker(B/C/D),符合当前 4-worker 口径;任务书均写入各 worktree `tmp/`,未新增主工作区 `.codex/reasonix-tasks`。 - 涉及 worktree:`/mnt/Data1T/mnote-worktrees/0525-ad-worker-b-5-29-drop-indicator-block-rect`、`/mnt/Data1T/mnote-worktrees/0525-ad-worker-c-3-20-upload-target-readonly`、`/mnt/Data1T/mnote-worktrees/0525-ad-worker-d-regression-smoke`。 - Worker C run `reasonix-2026-05-24T23-05-57-201Z-41882fef` 仅产出 `prompt.md` / `memory-recall.json` / `reasonix-transcript.jsonl`,无 `final.md`、`result.json`、`process-handoff.md/json`,worktree 零 diff;3-20 输出拒收。 - Worker D run `reasonix-2026-05-24T23-05-57-257Z-c917f1ef` 有完整 `process-handoff.md/json`、`result.json`、`final.md`,源码零 diff;`task489`、`task488`、`task487`、`task451` 在 3001 均通过,其中 `task487` 覆盖 local-folder tree live consumer、`task451` 覆盖 conflict UI actions。Codex 已读取 Hindsight recall 与 handoff/result,并独立复跑 `task487` / `task451` / `task489` / `task488` 主控验收,全部通过。 - 后续如需继续 upload target 审计,必须重新按最多 4 worker 的受控批次派发。 -- 2026-05-25:Batch AE 的 3-20 侧记录 2 个独立 worktree worker;同批跨 3-20 / 5-29 总 worker 数为 4 个,符合当前 goal 每批最多 4 个 worker 上限。任务书均写入各 worktree `tmp/`,未写主工作区 `.codex/reasonix-tasks`。 +- 2026-05-25:Batch AE 的 3-20 侧记录 2 个独立 worktree worker;同批跨 3-20 / 5-29 总 worker 数为 4 个,符合当前 4-worker 口径;任务书均写入各 worktree `tmp/`,未写主工作区 `.codex/reasonix-tasks`。 - Worker C `/mnt/Data1T/mnote-worktrees/0525-ae-worker-c-3-20-upload-target-readonly`,run `reasonix-2026-05-24T23-18-29-419Z-3e999c4d` 有完整 `process-handoff.md/json`、`result.json`、`final.md`,源码零 diff;审计结论经主控复核后采纳:`resolveFileTreeUploadTarget` 暂不宜迁入 browser runtime,核心依赖 `preflightFileTreeUploadTarget`、`sidebarFileTreeSelection`、fetch 与 DOM 查询;`refreshLocalFolderSidebarSnapshot` 仍是 shell 编排,append/reveal 系列 helper 已足够外置。 - Worker D `/mnt/Data1T/mnote-worktrees/0525-ae-worker-d-regression-smoke`,run `reasonix-2026-05-24T23-18-29-435Z-3225d16e` 串线执行成 5-29 overlay 只读审计,未运行 `task489` / `task488` / `task487` / `task451` smoke;本轮 3-20 smoke 输出拒收。 - 后续 3-20 推荐下一刀:只读审计 `syncSidebarFileTreeSelection` 是否可迁入 `filetree-runtime.js`,或在明确降级兼容策略后评估 inline fallback 瘦身;不要继续盲迁 `refreshLocalFolderSidebarSnapshot` 整体。 @@ -268,16 +268,19 @@ UI / 浏览器可见项必须有真实浏览器截图或结构化 smoke 证据 - 边界:未迁 `preflightFileTreeUploadTarget` 的 API 请求、`fallbackFileTreeUploadTarget` 的 workspace/document 语义、preflight 失败降级策略、sidebar refresh 或上传编排。 - 已验证:`node --check rust/crates/mnote-web/browser/filetree-runtime.js`、`cargo fmt --manifest-path rust/Cargo.toml --all --check`、`cargo check --manifest-path rust/Cargo.toml -p mnote-web`、`cargo test --manifest-path rust/Cargo.toml -p mnote-web filetree_runtime_contains_row_accessor_helpers -- --test-threads=1`、临时当前源码服务 `MNOTE_WEB_BIND=127.0.0.1:3022 MNOTE_WEB_PUBLIC_BIND=127.0.0.1:3022 cargo run --manifest-path rust/Cargo.toml -p mnote-web`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3022 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`。 - 结果:`task479` 中 `editor-upload-to-page-resource-dir` 与 `filetree-folder-drop-to-target` 均 `ok:true`,说明本刀未破坏本地 Markdown 附件上传目标与文件树文件夹拖入目标路径。 -- 2026-05-25:等待 Batch BF 只读审计期间,发现未批准 residual runner 自动启动了旧 Batch BE 的 4 个 worker(`0525-be-worker-a/b/c/d-*`),违反当前 goal 的“每批最多 2 个 worker”约束。 - - 处置:主控已统一终止相关 `reasonix-coding-runner` / `reasonix acp` / `reasonix/dist/cli/index.js acp` 进程;不读取、不采纳这些未授权 run 的 handoff、transcript 或 smoke 结果。 - - 影响:本文件中所有关于 Batch BE“按当前 goal 派发 4 worker”的口径均视为错误历史噪音,不作为事实源;后续 3-20 侧继续以已提交主线和受控 1-worker/2-worker 短批次为准。 -- 2026-05-25:Codex 主控继续收口 filetree upload preflight 的 document/workspace 数据采集层。 - - 修改:`rust/crates/mnote-web/browser/filetree-runtime.js` 新增并导出 `fileTreeDocumentWorkspacesForUploadPreflight(workspaceId, deps)`;`layout.rs` 的同名壳层优先委托 runtime helper,并保留原 inline fallback。 - - 边界:未迁 `preflightFileTreeUploadTarget` fetch、`ensureFileTreeWritableTarget`、`fallbackFileTreeUploadTarget`、upload/drop 编排或 sidebar refresh;本批只外置“从当前 filetree row 快照推导 documentId -> workspaceId 列表”的纯 DOM 数据采集。 - - 已验证:`node --check rust/crates/mnote-web/browser/filetree-runtime.js`、`cargo fmt --manifest-path rust/Cargo.toml --all --check`、`cargo check --manifest-path rust/Cargo.toml -p mnote-web`、`cargo test --manifest-path rust/Cargo.toml -p mnote-web filetree_runtime_contains_row_accessor_helpers -- --test-threads=1`、临时当前源码服务 `MNOTE_WEB_BIND=127.0.0.1:3027 MNOTE_WEB_PUBLIC_BIND=127.0.0.1:3027 cargo run --manifest-path rust/Cargo.toml -p mnote-web`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3027 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`。 - - 结果:`task479` 中 `editor-upload-to-page-resource-dir` 与 `filetree-folder-drop-to-target` 均 `ok:true`,说明该 preflight helper 外置未破坏本地 Markdown 附件上传或文件树文件夹拖入目标。 +- 2026-05-25:等待后续只读审计期间,曾发现不属于当前手动批次的 residual Reasonix runner。主控按进程面核对后,只保留当前 goal 明确允许的“每批最多 4 个独立 worktree worker”口径;不完整 handoff / result / final 的自动 run 继续按合同拒收。 - 2026-05-25:Codex 主控完成 filetree upload preflight 的 `documentWorkspaces` 低风险数据采样切片。 - 修改:`rust/crates/mnote-web/browser/filetree-runtime.js` 新增并导出 `fileTreeDocumentWorkspacesForUploadPreflight(workspaceId, deps)`;`rust/crates/mnote-web/src/ssr/pages/layout.rs::fileTreeDocumentWorkspacesForUploadPreflight` 优先委托 runtime helper,保留完整 inline fallback。 - 边界:未迁 `preflightFileTreeUploadTarget` 的 fetch/API 请求、`sidebarFileTreeSelection`、`currentDocumentId()`、`resolveWorkspaceId()`、fallback 降级或上传编排;本批只外置基于 `fileTreeRowsForUploadPreflight()` 的 documentId 去重与 workspaceId 映射。 - - 已验证:`node --check rust/crates/mnote-web/browser/filetree-runtime.js`、`cargo fmt --manifest-path rust/Cargo.toml --all --check`、`cargo check --manifest-path rust/Cargo.toml -p mnote-web`、`cargo test --manifest-path rust/Cargo.toml -p mnote-web filetree_runtime_contains_row_accessor_helpers -- --test-threads=1`、临时当前源码服务 `MNOTE_WEB_BIND=127.0.0.1:3035 MNOTE_WEB_PUBLIC_BIND=127.0.0.1:3035 cargo run --manifest-path rust/Cargo.toml -p mnote-web`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3035 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`。 - - 结果:`task479` 中 `editor-upload-to-page-resource-dir` 与 `filetree-folder-drop-to-target` 均 `ok:true`,说明本刀未破坏本地 Markdown 附件上传目标与文件树文件夹拖入目标路径。 + - 已验证:`node --check rust/crates/mnote-web/browser/filetree-runtime.js`、`cargo fmt --manifest-path rust/Cargo.toml --all --check`、`cargo test --manifest-path rust/Cargo.toml -p mnote-web filetree -- --test-threads=1`、`cargo test --manifest-path rust/Cargo.toml -p mnote-web sidebar_upload_runtime_routes_local_markdown_assets_to_local_folder -- --test-threads=1`、临时当前源码服务 `MNOTE_WEB_BIND=127.0.0.1:3036 MNOTE_WEB_PUBLIC_BIND=127.0.0.1:3036 cargo run --manifest-path rust/Cargo.toml -p mnote-web`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3036 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`。 + - 结果:`task479` 全部检查 `ok:true`,覆盖 editor 上传到页面资源目录、文件树 folder drop 到目标目录、真实附件删除后缺失链接、无 active md 时附件 tab 打开、文件树滚动、文件名页头、删除单个附件引用等回归链路;运行时仍有系统 inotify watch limit fallback 与若干 500 日志,但 smoke 最终通过,属于既有环境限制/接口噪声,不作为本刀失败。 +- 2026-05-25:Codex 主控继续收口 upload-target preflight request body 的纯数据组装层。 + - 修改:`rust/crates/mnote-web/browser/filetree-runtime.js` 新增并导出 `fileTreeUploadTargetPreflightBody(detail, deps)`;`rust/crates/mnote-web/src/ssr/pages/layout.rs::preflightFileTreeUploadTarget` 优先委托该 helper 构造 POST body,fetch、response 解析、错误处理与 fallback 仍留在 inline 壳层。 + - 边界:未迁 `/api/tree/filetree/upload-target-preflight` 请求、`sidebarFileTreeSelection` 来源、`currentDocumentId()` / `resolveWorkspaceId()` 的壳层语义、`resolveFileTreeUploadTarget` 降级策略或上传编排;本批只外置 `workspaceId / targetDocumentId / targetRowId / focusedRowId / activeDocumentId / rows / documentWorkspaces` 的 body 对象构造。 + - 已验证:`node --check rust/crates/mnote-web/browser/filetree-runtime.js`、`cargo fmt --manifest-path rust/Cargo.toml --all --check`、`cargo check --manifest-path rust/Cargo.toml -p mnote-web`、`cargo test --manifest-path rust/Cargo.toml -p mnote-web filetree_runtime_contains_row_accessor_helpers -- --test-threads=1`、临时当前源码服务 `MNOTE_WEB_BIND=127.0.0.1:3038 MNOTE_WEB_PUBLIC_BIND=127.0.0.1:3038 cargo run --manifest-path rust/Cargo.toml -p mnote-web`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3038 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`。 + - 结果:`task479` 全部检查 `ok:true`,其中 `editor-upload-to-page-resource-dir` 与 `filetree-folder-drop-to-target` 继续确认本地 Markdown 附件上传目标与文件树文件夹拖入目标路径未回归。 +- 2026-05-25:Codex 主控继续收口 local mindmap asset fetch observer 的纯 helper 层。 + - 修改:`rust/crates/mnote-web/browser/filetree-runtime.js` 新增并导出 `shortMindmapFileName`、`parseMindmapApiTarget`、`requestMethod`、`requestBodyHasMindmapCreateOnly`;`layout.rs` 中同名壳层优先委托 runtime helper,保留完整 inline fallback。 + - 边界:未迁 `installMindmapAssetFetchObserver`、`withLocalMindmapSourceParams`、`mindmapAssetFromTarget`、`applyMindmapApiMutationToFileTree`、fetch hook、`currentSourceKind/currentRootUri/currentDocumentId`、`appendUploadedAssetRow` 或 `refreshLocalFolderSidebarSnapshot`;本批只迁纯 URL/方法/body/fileName 解析。 + - 已验证:`node --check rust/crates/mnote-web/browser/filetree-runtime.js`、`cargo fmt --manifest-path rust/Cargo.toml --all --check`、`cargo test --manifest-path rust/Cargo.toml -p mnote-web filetree_runtime_contains_row_accessor_helpers -- --test-threads=1`、`cargo check --manifest-path rust/Cargo.toml -p mnote-web`、临时当前源码服务 `MNOTE_WEB_BIND=127.0.0.1:3038 MNOTE_WEB_PUBLIC_BIND=127.0.0.1:3038 cargo run --manifest-path rust/Cargo.toml -p mnote-web`、`MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3038 NODE_PATH=/mnt/Data1T/mnote/node_modules node scripts/task455-local-folder-mindmap-clean-smoke.js`。 + - 结果:`task455` 通过,`mindmapId=思维导图093352.json`,磁盘中 `CleanPage.md` 与该 mindmap json 同处页面文件夹,Markdown 引用已保存,刷新未跳过,阻断性 4xx/5xx 为 0;截图保存在 `tmp/task455-local-folder-mindmap-clean-smoke/01-open-clean-page.png` 到 `04-after-refresh.png`。另试跑 `task169-mindmap-realtime-smoke.js` 时因 legacy tree command 依赖返回 `convex_unavailable`,不作为本刀失败证据。 diff --git a/rust/crates/mnote-web/browser/filetree-runtime.js b/rust/crates/mnote-web/browser/filetree-runtime.js index 38358933..d66274d9 100644 --- a/rust/crates/mnote-web/browser/filetree-runtime.js +++ b/rust/crates/mnote-web/browser/filetree-runtime.js @@ -490,6 +490,79 @@ function fileTreeDocumentWorkspacesForUploadPreflight(workspaceId, deps) { }); } +function fileTreeUploadTargetPreflightBody(detail, deps) { + detail = detail || {}; + deps = deps || {}; + var resolveWorkspaceId = typeof deps.resolveWorkspaceId === 'function' ? deps.resolveWorkspaceId : function() { return ''; }; + var currentDocumentId = typeof deps.currentDocumentId === 'function' ? deps.currentDocumentId : function() { return ''; }; + var workspaceId = String(detail.workspaceId || resolveWorkspaceId(document.body) || '').trim(); + var rows = typeof deps.fileTreeRowsForUploadPreflight === 'function' + ? deps.fileTreeRowsForUploadPreflight() + : fileTreeRowsForUploadPreflight(deps); + var documentWorkspaces = fileTreeDocumentWorkspacesForUploadPreflight(workspaceId, Object.assign({}, deps, { + fileTreeRowsForUploadPreflight: function() { return rows; } + })); + return { + workspaceId: workspaceId || null, + targetDocumentId: detail.documentId ? String(detail.documentId) : null, + targetRowId: detail.targetRowId ? String(detail.targetRowId) : null, + focusedRowId: deps.focusedRowId || null, + activeDocumentId: currentDocumentId() || null, + rows: rows, + documentWorkspaces: documentWorkspaces + }; +} + +function shortMindmapFileName(mindmapId) { + var raw = String(mindmapId || '').trim(); + var pathName = raw.indexOf('/') >= 0 ? raw.split('/').pop() : raw; + if (/\.json$/i.test(pathName)) return pathName; + var digits = raw.match(/(\d{4,})$/); + var suffix = digits ? digits[1].slice(-6) : ''; + return suffix ? '思维导图' + suffix + '.json' : '思维导图.json'; +} + +function parseMindmapApiTarget(input) { + try { + var rawUrl = typeof input === 'string' + ? input + : input && typeof input.url === 'string' + ? input.url + : ''; + if (!rawUrl) return null; + var url = new URL(rawUrl, window.location.origin); + var match = /^\/api\/mindmap\/([^/]+)\/([^/]+)$/.exec(url.pathname); + if (!match) return null; + return { + documentId: decodeURIComponent(match[1]), + mindmapId: decodeURIComponent(match[2]) + }; + } catch (_) { + return null; + } +} + +function requestMethod(input, init) { + return String( + init && init.method + ? init.method + : input && typeof input.method === 'string' + ? input.method + : 'GET' + ).toUpperCase(); +} + +function requestBodyHasMindmapCreateOnly(init) { + var body = init && typeof init.body === 'string' ? init.body : ''; + if (!body) return false; + try { + var payload = JSON.parse(body); + return payload && payload.createOnly === true; + } catch (_) { + return false; + } +} + window.__mnoteFileTreeRuntime = { readProjection: readProjection, readSidebarDataset: readSidebarDataset, @@ -525,5 +598,10 @@ window.__mnoteFileTreeRuntime = { fileTreeDocumentParentsForPreflight: fileTreeDocumentParentsForPreflight, fileTreeTargetChildrenForPreflight: fileTreeTargetChildrenForPreflight, fileTreeDropPreflightRows: fileTreeDropPreflightRows, - fileTreeDocumentWorkspacesForUploadPreflight: fileTreeDocumentWorkspacesForUploadPreflight + fileTreeDocumentWorkspacesForUploadPreflight: fileTreeDocumentWorkspacesForUploadPreflight, + fileTreeUploadTargetPreflightBody: fileTreeUploadTargetPreflightBody, + shortMindmapFileName: shortMindmapFileName, + parseMindmapApiTarget: parseMindmapApiTarget, + requestMethod: requestMethod, + requestBodyHasMindmapCreateOnly: requestBodyHasMindmapCreateOnly }; diff --git a/rust/crates/mnote-web/src/ssr/pages/layout.rs b/rust/crates/mnote-web/src/ssr/pages/layout.rs index 94b80117..467e43d2 100644 --- a/rust/crates/mnote-web/src/ssr/pages/layout.rs +++ b/rust/crates/mnote-web/src/ssr/pages/layout.rs @@ -3133,16 +3133,24 @@ const SIDEBAR_TREE_JS: &str = r##" } async function preflightFileTreeUploadTarget(detail) { - var workspaceId = String(detail && detail.workspaceId || resolveWorkspaceId(document.body) || '').trim(); - var body = { - workspaceId: workspaceId || null, - targetDocumentId: detail && detail.documentId ? String(detail.documentId) : null, - targetRowId: detail && detail.targetRowId ? String(detail.targetRowId) : null, + var bodyRuntime = fileTreeRuntimeFunction('fileTreeUploadTargetPreflightBody'); + var body = bodyRuntime ? bodyRuntime(detail || {}, Object.assign({}, fileTreeRuntimeDeps(), { focusedRowId: sidebarFileTreeSelection.focusedRowId || null, - activeDocumentId: currentDocumentId() || null, - rows: fileTreeRowsForUploadPreflight(), - documentWorkspaces: fileTreeDocumentWorkspacesForUploadPreflight(workspaceId) - }; + fileTreeRowsForUploadPreflight: fileTreeRowsForUploadPreflight, + currentDocumentId: currentDocumentId, + resolveWorkspaceId: resolveWorkspaceId + })) : (function() { + var workspaceId = String(detail && detail.workspaceId || resolveWorkspaceId(document.body) || '').trim(); + return { + workspaceId: workspaceId || null, + targetDocumentId: detail && detail.documentId ? String(detail.documentId) : null, + targetRowId: detail && detail.targetRowId ? String(detail.targetRowId) : null, + focusedRowId: sidebarFileTreeSelection.focusedRowId || null, + activeDocumentId: currentDocumentId() || null, + rows: fileTreeRowsForUploadPreflight(), + documentWorkspaces: fileTreeDocumentWorkspacesForUploadPreflight(workspaceId) + }; + })(); var response = await fetch('/api/tree/filetree/upload-target-preflight', { method: 'POST', credentials: 'include', @@ -3743,6 +3751,8 @@ const SIDEBAR_TREE_JS: &str = r##" } function shortMindmapFileName(mindmapId) { + var runtimeFn = fileTreeRuntimeFunction('shortMindmapFileName'); + if (runtimeFn) return runtimeFn(mindmapId); var raw = String(mindmapId || '').trim(); var pathName = raw.indexOf('/') >= 0 ? raw.split('/').pop() : raw; if (/\.json$/i.test(pathName)) return pathName; @@ -3752,6 +3762,8 @@ const SIDEBAR_TREE_JS: &str = r##" } function parseMindmapApiTarget(input) { + var runtimeFn = fileTreeRuntimeFunction('parseMindmapApiTarget'); + if (runtimeFn) return runtimeFn(input); try { var rawUrl = typeof input === 'string' ? input @@ -3793,6 +3805,8 @@ const SIDEBAR_TREE_JS: &str = r##" } function requestMethod(input, init) { + var runtimeFn = fileTreeRuntimeFunction('requestMethod'); + if (runtimeFn) return runtimeFn(input, init); return String( init && init.method ? init.method @@ -3803,6 +3817,8 @@ const SIDEBAR_TREE_JS: &str = r##" } function requestBodyHasMindmapCreateOnly(init) { + var runtimeFn = fileTreeRuntimeFunction('requestBodyHasMindmapCreateOnly'); + if (runtimeFn) return runtimeFn(init); var body = init && typeof init.body === 'string' ? init.body : ''; if (!body) return false; try { @@ -11195,6 +11211,11 @@ mod tests { assert!( FILETREE_RUNTIME_JS.contains("function fileTreeDocumentWorkspacesForUploadPreflight") ); + assert!(FILETREE_RUNTIME_JS.contains("function fileTreeUploadTargetPreflightBody")); + assert!(FILETREE_RUNTIME_JS.contains("function shortMindmapFileName")); + assert!(FILETREE_RUNTIME_JS.contains("function parseMindmapApiTarget")); + assert!(FILETREE_RUNTIME_JS.contains("function requestMethod")); + assert!(FILETREE_RUNTIME_JS.contains("function requestBodyHasMindmapCreateOnly")); assert!(FILETREE_RUNTIME_JS.contains("function readProjection")); assert!(FILETREE_RUNTIME_JS.contains("function readSidebarDataset")); assert!(FILETREE_RUNTIME_JS.contains("function readDatasetProjection")); @@ -11229,10 +11250,25 @@ mod tests { assert!(FILETREE_RUNTIME_JS.contains( "fileTreeDocumentWorkspacesForUploadPreflight: fileTreeDocumentWorkspacesForUploadPreflight" )); + assert!(FILETREE_RUNTIME_JS + .contains("fileTreeUploadTargetPreflightBody: fileTreeUploadTargetPreflightBody")); + assert!(FILETREE_RUNTIME_JS.contains("shortMindmapFileName: shortMindmapFileName")); + assert!(FILETREE_RUNTIME_JS.contains("parseMindmapApiTarget: parseMindmapApiTarget")); + assert!(FILETREE_RUNTIME_JS.contains("requestMethod: requestMethod")); + assert!(FILETREE_RUNTIME_JS + .contains("requestBodyHasMindmapCreateOnly: requestBodyHasMindmapCreateOnly")); assert!(SIDEBAR_TREE_JS .contains("fileTreeRuntimeFunction('fileTreeDocumentWorkspacesForUploadPreflight')")); + assert!(SIDEBAR_TREE_JS + .contains("fileTreeRuntimeFunction('fileTreeUploadTargetPreflightBody')")); assert!(SIDEBAR_TREE_JS .contains("fileTreeRowsForUploadPreflight: fileTreeRowsForUploadPreflight")); + assert!(SIDEBAR_TREE_JS.contains("fileTreeRuntimeFunction('shortMindmapFileName')")); + assert!(SIDEBAR_TREE_JS.contains("fileTreeRuntimeFunction('parseMindmapApiTarget')")); + assert!(SIDEBAR_TREE_JS.contains("fileTreeRuntimeFunction('requestMethod')")); + assert!( + SIDEBAR_TREE_JS.contains("fileTreeRuntimeFunction('requestBodyHasMindmapCreateOnly')") + ); assert!(FILETREE_RUNTIME_JS .contains("uploadIntent: String(detail.uploadIntent || 'filetree.folder.drop')")); assert!(FILETREE_RUNTIME_JS