refactor: delegate upload files orchestration
This commit is contained in:
@@ -63,7 +63,7 @@ UI / 浏览器可见项必须有真实浏览器截图或结构化 smoke 证据
|
|||||||
## 6. 本轮执行记录
|
## 6. 本轮执行记录
|
||||||
|
|
||||||
- 2026-05-25:Codex 创建本续跑事实源。
|
- 2026-05-25:Codex 创建本续跑事实源。
|
||||||
- 2026-05-25:修正执行约束:本文件遵循当前 goal 的“每批最多 2 个 worker”;实现 worker 必须在独立 worktree 产出候选 patch,Codex 复核后再选择性合入。
|
- 2026-05-25:修正执行约束:本文件遵循当前 goal 的“每批最多 4 个 worker”;实现 worker 必须在独立 worktree 产出候选 patch,Codex 复核后再选择性合入。
|
||||||
- 2026-05-25:下一批只派发 Worker B(local upload / filetree 下一刀只读审计);Worker A/C/D 暂缓。
|
- 2026-05-25:下一批只派发 Worker B(local upload / filetree 下一刀只读审计);Worker A/C/D 暂缓。
|
||||||
- 2026-05-25:Reasonix local upload / filetree 只读审计尝试未产生 `result.json` / `process-handoff`,且运行期间出现额外 Batch A2 runner,主控已终止进程;该结果不作为正式 handoff 采纳。
|
- 2026-05-25:Reasonix local upload / filetree 只读审计尝试未产生 `result.json` / `process-handoff`,且运行期间出现额外 Batch A2 runner,主控已终止进程;该结果不作为正式 handoff 采纳。
|
||||||
- 可参考的 transcript 结论:`fetchWithTimeout` 是低风险纯工具函数,可先迁入 `local-upload-runtime.js`;`uploadFileToMediaAsset` / `uploadFilesWithResolvedTarget` / `insertUploadedAssetIntoEditor` 仍与 API、editor 插入和 snapshot refresh 耦合,暂不迁。
|
- 可参考的 transcript 结论:`fetchWithTimeout` 是低风险纯工具函数,可先迁入 `local-upload-runtime.js`;`uploadFileToMediaAsset` / `uploadFilesWithResolvedTarget` / `insertUploadedAssetIntoEditor` 仍与 API、editor 插入和 snapshot refresh 耦合,暂不迁。
|
||||||
@@ -92,8 +92,13 @@ UI / 浏览器可见项必须有真实浏览器截图或结构化 smoke 证据
|
|||||||
- 修改:`rust/crates/mnote-web/browser/document-conflict-panel-runtime.js`、`rust/crates/mnote-web/src/routes/web_shell.rs`。
|
- 修改:`rust/crates/mnote-web/browser/document-conflict-panel-runtime.js`、`rust/crates/mnote-web/src/routes/web_shell.rs`。
|
||||||
- 已验证:`node --check rust/crates/mnote-web/browser/document-conflict-panel-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 document_conflict_panel_runtime_contains_dom_helpers -- --test-threads=1`、`cargo test --manifest-path rust/Cargo.toml -p mnote-web mnote_browser_runtime_assets_are_explicitly_mounted -- --test-threads=1`。
|
- 已验证:`node --check rust/crates/mnote-web/browser/document-conflict-panel-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 document_conflict_panel_runtime_contains_dom_helpers -- --test-threads=1`、`cargo test --manifest-path rust/Cargo.toml -p mnote-web mnote_browser_runtime_assets_are_explicitly_mounted -- --test-threads=1`。
|
||||||
- 未完成:conflict merge / accept / keep 业务逻辑、document session lifecycle、secondary pane conflict smoke 仍未迁出;本轮未声称真实冲突 UI 全链路完成。
|
- 未完成:conflict merge / accept / keep 业务逻辑、document session lifecycle、secondary pane conflict smoke 仍未迁出;本轮未声称真实冲突 UI 全链路完成。
|
||||||
- 2026-05-25:根据用户纠正,后续实现 worker 不能在主工作区直接修改;每批最多 2 个 worker,且必须采用独立 worktree 候选 patch或明确只读任务。Codex 读取 Hindsight recall、`process-handoff.md/json`、`result.json`、diff 与验证证据后再选择性合入。
|
- 2026-05-25:根据用户纠正,后续实现 worker 不能在主工作区直接修改;每批最多 4 个 worker,且必须采用独立 worktree 候选 patch 或明确只读任务。Codex 读取 Hindsight recall、`process-handoff.md/json`、`result.json`、diff 与验证证据后再选择性合入。
|
||||||
- 2026-05-25:Codex 主控完成非本地 media upload API 小切片:`local-upload-runtime.js` 新增并导出 `uploadMediaAsset(file, plan, context)`,承接 `/api/media/upload` 的 FormData 构造、fetch 和响应解析;`layout.rs` 的 `uploadFileToMediaAsset` 仍负责 appendUploadedAssetRow、editor 插入和 `wolai:assets-changed` 事件分发,并保留完整 inline fallback。
|
- 2026-05-25:Codex 主控完成非本地 media upload API 小切片:`local-upload-runtime.js` 新增并导出 `uploadMediaAsset(file, plan, context)`,承接 `/api/media/upload` 的 FormData 构造、fetch 和响应解析;`layout.rs` 的 `uploadFileToMediaAsset` 仍负责 appendUploadedAssetRow、editor 插入和 `wolai:assets-changed` 事件分发,并保留完整 inline fallback。
|
||||||
- 修改:`rust/crates/mnote-web/browser/local-upload-runtime.js`、`rust/crates/mnote-web/src/ssr/pages/layout.rs`。
|
- 修改:`rust/crates/mnote-web/browser/local-upload-runtime.js`、`rust/crates/mnote-web/src/ssr/pages/layout.rs`。
|
||||||
- 已验证:`node --check rust/crates/mnote-web/browser/local-upload-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 local_upload_runtime_contains_editor_upload_context_helpers -- --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`、`node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`。
|
- 已验证:`node --check rust/crates/mnote-web/browser/local-upload-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 local_upload_runtime_contains_editor_upload_context_helpers -- --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`、`node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`。
|
||||||
- 未完成:`uploadFileToMediaAsset` / `uploadFilesWithResolvedTarget` 编排壳、conflict merge / accept / keep 业务逻辑、secondary pane conflict smoke 仍未迁出;本轮未改资源归属语义。
|
- 未完成:`uploadFileToMediaAsset` / `uploadFilesWithResolvedTarget` 编排壳、conflict merge / accept / keep 业务逻辑、secondary pane conflict smoke 仍未迁出;本轮未改资源归属语义。
|
||||||
|
- 2026-05-25:Batch C 按用户要求同时派发 3 个独立 worktree 实现 worker:B 修复 5-29 block delete undo,C 迁 `uploadFileToMediaAsset`,D 收口 conflict action boundary;3 个 Reasonix runner 均未产出 `final.md`、`result.json` 或 `process-handoff.md/json`,对应 worktree diff 为空,按采纳规则全部拒绝。Codex 后续只采纳独立复核后的候选 patch。
|
||||||
|
- 2026-05-25:Codex 主控完成 upload files orchestration 小切片:`local-upload-runtime.js` 新增并导出 `uploadFilesWithResolvedTarget(files, detail, options, deps)`,承接文件列表归一化、逐个上传、错误聚合和 alert 提示;`layout.rs` 仍注入 `resolveFileTreeUploadTarget` / `uploadFileToMediaAsset`,保留目标解析、单文件上传和完整 inline fallback。
|
||||||
|
- 修改:`rust/crates/mnote-web/browser/local-upload-runtime.js`、`rust/crates/mnote-web/src/ssr/pages/layout.rs`。
|
||||||
|
- 已验证:`node --check rust/crates/mnote-web/browser/local-upload-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 local_upload_runtime_contains_editor_upload_context_helpers -- --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`、`node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`。
|
||||||
|
- 未完成:`uploadFileToMediaAsset` 编排壳、conflict merge / accept / keep 业务逻辑、secondary pane conflict smoke 仍未迁出;本轮未改资源归属语义。
|
||||||
|
|||||||
@@ -298,6 +298,36 @@ async function insertUploadedAssetIntoEditor(asset, targetRoot, deps) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function uploadFilesWithResolvedTarget(files, detail, options, deps) {
|
||||||
|
deps = deps || {};
|
||||||
|
var resolveFileTreeUploadTarget = typeof deps.resolveFileTreeUploadTarget === 'function' ? deps.resolveFileTreeUploadTarget : null;
|
||||||
|
var uploadFileToMediaAsset = typeof deps.uploadFileToMediaAsset === 'function' ? deps.uploadFileToMediaAsset : null;
|
||||||
|
if (!resolveFileTreeUploadTarget || !uploadFileToMediaAsset) {
|
||||||
|
throw new Error('上传运行时缺少目标解析或上传函数');
|
||||||
|
}
|
||||||
|
var list = Array.from(files || []).filter(Boolean);
|
||||||
|
if (!list.length) return [];
|
||||||
|
var plan = await resolveFileTreeUploadTarget(detail || {});
|
||||||
|
var uploaded = [];
|
||||||
|
var errors = [];
|
||||||
|
for (var i = 0; i < list.length; i += 1) {
|
||||||
|
try {
|
||||||
|
uploaded.push(await uploadFileToMediaAsset(list[i], plan, options || {}));
|
||||||
|
} catch (error) {
|
||||||
|
errors.push(list[i].name + ': ' + (error && error.message ? error.message : '上传失败'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (errors.length) {
|
||||||
|
var message = '部分文件上传失败:\n' + errors.slice(0, 6).join('\n') + (errors.length > 6 ? '\n...' : '');
|
||||||
|
if (typeof deps.alert === 'function') {
|
||||||
|
deps.alert(message);
|
||||||
|
} else {
|
||||||
|
window.alert(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uploaded;
|
||||||
|
}
|
||||||
|
|
||||||
function localAssetOpenUrl(asset, download, context) {
|
function localAssetOpenUrl(asset, download, context) {
|
||||||
if (!isLocalUploadedAsset(asset)) return '';
|
if (!isLocalUploadedAsset(asset)) return '';
|
||||||
var rootUri = String(context && context.rootUri || asset && (asset.rootUri || asset.root_uri) || '').trim() || currentRootUri();
|
var rootUri = String(context && context.rootUri || asset && (asset.rootUri || asset.root_uri) || '').trim() || currentRootUri();
|
||||||
@@ -430,6 +460,7 @@ window.__mnoteLocalUploadRuntime = {
|
|||||||
uploadLocalFolderAsset: uploadLocalFolderAsset,
|
uploadLocalFolderAsset: uploadLocalFolderAsset,
|
||||||
uploadMediaAsset: uploadMediaAsset,
|
uploadMediaAsset: uploadMediaAsset,
|
||||||
insertUploadedAssetIntoEditor: insertUploadedAssetIntoEditor,
|
insertUploadedAssetIntoEditor: insertUploadedAssetIntoEditor,
|
||||||
|
uploadFilesWithResolvedTarget: uploadFilesWithResolvedTarget,
|
||||||
localAssetOpenUrl: localAssetOpenUrl,
|
localAssetOpenUrl: localAssetOpenUrl,
|
||||||
uploadedAssetType: uploadedAssetType,
|
uploadedAssetType: uploadedAssetType,
|
||||||
fileTreeIconKindForFileName: fileTreeIconKindForFileName,
|
fileTreeIconKindForFileName: fileTreeIconKindForFileName,
|
||||||
|
|||||||
@@ -4098,6 +4098,14 @@ const SIDEBAR_TREE_JS: &str = r##"
|
|||||||
installMindmapAssetFetchObserver();
|
installMindmapAssetFetchObserver();
|
||||||
|
|
||||||
async function uploadFilesWithResolvedTarget(files, detail, options) {
|
async function uploadFilesWithResolvedTarget(files, detail, options) {
|
||||||
|
var runtimeFn = localUploadRuntimeFunction('uploadFilesWithResolvedTarget');
|
||||||
|
if (runtimeFn) {
|
||||||
|
return await runtimeFn(files, detail || {}, options || {}, {
|
||||||
|
resolveFileTreeUploadTarget: resolveFileTreeUploadTarget,
|
||||||
|
uploadFileToMediaAsset: uploadFileToMediaAsset,
|
||||||
|
alert: function(message) { window.alert(message); }
|
||||||
|
});
|
||||||
|
}
|
||||||
var list = Array.from(files || []).filter(Boolean);
|
var list = Array.from(files || []).filter(Boolean);
|
||||||
if (!list.length) return [];
|
if (!list.length) return [];
|
||||||
var plan = await resolveFileTreeUploadTarget(detail || {});
|
var plan = await resolveFileTreeUploadTarget(detail || {});
|
||||||
@@ -10965,6 +10973,9 @@ mod tests {
|
|||||||
SIDEBAR_TREE_JS.contains("localUploadRuntimeFunction('insertUploadedAssetIntoEditor')")
|
SIDEBAR_TREE_JS.contains("localUploadRuntimeFunction('insertUploadedAssetIntoEditor')")
|
||||||
);
|
);
|
||||||
assert!(SIDEBAR_TREE_JS.contains("localUploadRuntimeFunction('uploadMediaAsset')"));
|
assert!(SIDEBAR_TREE_JS.contains("localUploadRuntimeFunction('uploadMediaAsset')"));
|
||||||
|
assert!(
|
||||||
|
SIDEBAR_TREE_JS.contains("localUploadRuntimeFunction('uploadFilesWithResolvedTarget')")
|
||||||
|
);
|
||||||
assert!(SIDEBAR_TREE_JS.contains("__mnoteLastEditorUploadRoot"));
|
assert!(SIDEBAR_TREE_JS.contains("__mnoteLastEditorUploadRoot"));
|
||||||
assert!(SIDEBAR_TREE_JS.contains("data-pane-role=\"primary\""));
|
assert!(SIDEBAR_TREE_JS.contains("data-pane-role=\"primary\""));
|
||||||
assert!(SIDEBAR_TREE_JS.contains("insertUploadedAssetIntoEditor(localPayload.asset, editorRootFromUploadOptions(options))"));
|
assert!(SIDEBAR_TREE_JS.contains("insertUploadedAssetIntoEditor(localPayload.asset, editorRootFromUploadOptions(options))"));
|
||||||
@@ -10982,6 +10993,7 @@ mod tests {
|
|||||||
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function uploadLocalFolderAsset"));
|
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function uploadLocalFolderAsset"));
|
||||||
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function uploadMediaAsset"));
|
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function uploadMediaAsset"));
|
||||||
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function insertUploadedAssetIntoEditor"));
|
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function insertUploadedAssetIntoEditor"));
|
||||||
|
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function uploadFilesWithResolvedTarget"));
|
||||||
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("data-mnote-last-upload-inserted"));
|
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("data-mnote-last-upload-inserted"));
|
||||||
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("uploadFilesWithResolvedTarget"));
|
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("uploadFilesWithResolvedTarget"));
|
||||||
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("__mnoteLastEditorUploadRoot"));
|
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("__mnoteLastEditorUploadRoot"));
|
||||||
|
|||||||
Reference in New Issue
Block a user