refactor: extract media upload runtime helper
This commit is contained in:
@@ -93,3 +93,7 @@ UI / 浏览器可见项必须有真实浏览器截图或结构化 smoke 证据
|
|||||||
- 已验证:`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 不能在主工作区直接修改;每批最多 2 个 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。
|
||||||
|
- 修改:`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` / `uploadFilesWithResolvedTarget` 编排壳、conflict merge / accept / keep 业务逻辑、secondary pane conflict smoke 仍未迁出;本轮未改资源归属语义。
|
||||||
|
|||||||
@@ -183,6 +183,26 @@ async function uploadLocalFolderAsset(file, plan, context) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function uploadMediaAsset(file, plan, context) {
|
||||||
|
var form = new FormData();
|
||||||
|
form.append('file', file);
|
||||||
|
form.append('workspaceId', plan && plan.workspaceId || '');
|
||||||
|
form.append('documentId', plan && plan.targetDocumentId || '');
|
||||||
|
if (plan && plan.targetMindmapId) form.append('mindmapId', plan.targetMindmapId);
|
||||||
|
var response = await fetchWithTimeout('/api/media/upload', {
|
||||||
|
method: 'POST',
|
||||||
|
credentials: 'include',
|
||||||
|
body: form
|
||||||
|
}, Number(context && context.timeoutMs) || 15000, '上传');
|
||||||
|
var payload = await response.json().catch(function() { return null; });
|
||||||
|
if (!response.ok || !payload || !payload.asset) {
|
||||||
|
throw new Error(payload && payload.error ? payload.error : '上传失败');
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
asset: payload.asset
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async function insertUploadedAssetIntoEditor(asset, targetRoot, deps) {
|
async function insertUploadedAssetIntoEditor(asset, targetRoot, deps) {
|
||||||
deps = deps || {};
|
deps = deps || {};
|
||||||
var editorRoot = targetRoot instanceof HTMLElement
|
var editorRoot = targetRoot instanceof HTMLElement
|
||||||
@@ -408,6 +428,7 @@ window.__mnoteLocalUploadRuntime = {
|
|||||||
openEditorUploadFilePicker: openEditorUploadFilePicker,
|
openEditorUploadFilePicker: openEditorUploadFilePicker,
|
||||||
fetchWithTimeout: fetchWithTimeout,
|
fetchWithTimeout: fetchWithTimeout,
|
||||||
uploadLocalFolderAsset: uploadLocalFolderAsset,
|
uploadLocalFolderAsset: uploadLocalFolderAsset,
|
||||||
|
uploadMediaAsset: uploadMediaAsset,
|
||||||
insertUploadedAssetIntoEditor: insertUploadedAssetIntoEditor,
|
insertUploadedAssetIntoEditor: insertUploadedAssetIntoEditor,
|
||||||
localAssetOpenUrl: localAssetOpenUrl,
|
localAssetOpenUrl: localAssetOpenUrl,
|
||||||
uploadedAssetType: uploadedAssetType,
|
uploadedAssetType: uploadedAssetType,
|
||||||
|
|||||||
@@ -4058,19 +4058,29 @@ const SIDEBAR_TREE_JS: &str = r##"
|
|||||||
}));
|
}));
|
||||||
return localPayload.asset;
|
return localPayload.asset;
|
||||||
}
|
}
|
||||||
var form = new FormData();
|
var mediaUploadRuntime = localUploadRuntimeFunction('uploadMediaAsset');
|
||||||
form.append('file', file);
|
var payload = null;
|
||||||
form.append('workspaceId', plan.workspaceId);
|
if (mediaUploadRuntime) {
|
||||||
form.append('documentId', plan.targetDocumentId);
|
var mediaResult = await mediaUploadRuntime(file, plan, { timeoutMs: 15000 });
|
||||||
if (plan.targetMindmapId) form.append('mindmapId', plan.targetMindmapId);
|
payload = mediaResult && mediaResult.asset ? { asset: mediaResult.asset } : null;
|
||||||
var response = await fetchWithTimeout('/api/media/upload', {
|
if (!payload || !payload.asset) {
|
||||||
method: 'POST',
|
throw new Error('上传失败');
|
||||||
credentials: 'include',
|
}
|
||||||
body: form
|
} else {
|
||||||
}, 15000, '上传');
|
var form = new FormData();
|
||||||
var payload = await response.json().catch(function() { return null; });
|
form.append('file', file);
|
||||||
if (!response.ok || !payload || !payload.asset) {
|
form.append('workspaceId', plan.workspaceId);
|
||||||
throw new Error(payload && payload.error ? payload.error : '上传失败');
|
form.append('documentId', plan.targetDocumentId);
|
||||||
|
if (plan.targetMindmapId) form.append('mindmapId', plan.targetMindmapId);
|
||||||
|
var response = await fetchWithTimeout('/api/media/upload', {
|
||||||
|
method: 'POST',
|
||||||
|
credentials: 'include',
|
||||||
|
body: form
|
||||||
|
}, 15000, '上传');
|
||||||
|
payload = await response.json().catch(function() { return null; });
|
||||||
|
if (!response.ok || !payload || !payload.asset) {
|
||||||
|
throw new Error(payload && payload.error ? payload.error : '上传失败');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
appendUploadedAssetRow(payload.asset, plan.targetDocumentId);
|
appendUploadedAssetRow(payload.asset, plan.targetDocumentId);
|
||||||
if (options && options.insertIntoEditor) {
|
if (options && options.insertIntoEditor) {
|
||||||
@@ -10954,6 +10964,7 @@ mod tests {
|
|||||||
assert!(
|
assert!(
|
||||||
SIDEBAR_TREE_JS.contains("localUploadRuntimeFunction('insertUploadedAssetIntoEditor')")
|
SIDEBAR_TREE_JS.contains("localUploadRuntimeFunction('insertUploadedAssetIntoEditor')")
|
||||||
);
|
);
|
||||||
|
assert!(SIDEBAR_TREE_JS.contains("localUploadRuntimeFunction('uploadMediaAsset')"));
|
||||||
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))"));
|
||||||
@@ -10969,6 +10980,7 @@ mod tests {
|
|||||||
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function openEditorUploadFilePicker"));
|
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function openEditorUploadFilePicker"));
|
||||||
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function fetchWithTimeout"));
|
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function fetchWithTimeout"));
|
||||||
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 insertUploadedAssetIntoEditor"));
|
assert!(LOCAL_UPLOAD_RUNTIME_JS.contains("function insertUploadedAssetIntoEditor"));
|
||||||
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"));
|
||||||
|
|||||||
Reference in New Issue
Block a user