修复视频首帧选择弹窗交互

问题:选择作品图片后需等待 Agent 整轮响应,弹窗长时间不关闭。
修复:选择后立即关闭弹窗并继续提交 Asset ID,失败信息转到主对话区;补充慢响应回归测试。
This commit is contained in:
2026-08-06 13:00:07 +08:00
parent 929b124852
commit 7b23cce67a
3 changed files with 54 additions and 4 deletions

View File

@@ -0,0 +1,43 @@
# Task: 修复作品图片选择与视频首帧附件提交
## Identity
- Task ID: 20260806-video-source-picker-4d8a
- Mode: Feature
- Branch: codex/fix-video-source-selection
- Worktree: D:\Datas\OthersProjects\makelore-video-source-selection
- Base commit: 929b12485257e03faa45495a8eb429b63fdec038
- Owner: codex
- Status: Completed
## Scope
- 修复从作品列表选择视频首帧后弹窗持续停留的问题。
- 保持 `resultAssets[].assetId` 到 Gateway `attachment_asset_ids` 的现有传递链路。
- 增加慢 Agent 响应场景的回归测试。
## Intent And Constraints
- 用户确认选择后立即关闭弹窗,不等待整轮 Agent 响应。
- Agent 请求失败时在主对话区展示错误,不把错误留在已关闭弹窗中。
- 不触碰原客户端工作区中的其他未提交改动。
## Outcome
- 作品图片选择后弹窗立即关闭,同时继续提交真实 Asset ID。
- 请求失败会回到对话区错误提示,用户仍可重新选择。
- 回归测试覆盖 Agent Promise 未完成时的弹窗状态。
## Verification
- `vitest image-canvas-page + works-square-design-workspace`38 passed。
- `pnpm typecheck`:通过。
- `pnpm build:vite`:通过(仅保留既有 chunk 体积提示)。
## Follow-ups
- None recorded.
## Promotion Candidates
- None recorded.

View File

@@ -547,15 +547,14 @@ export function ImageCanvas() {
const requestedWorkspaceId = workspace.workspaceId; const requestedWorkspaceId = workspace.workspaceId;
setFirstFrameBusyKey(asset.assetId); setFirstFrameBusyKey(asset.assetId);
setFirstFrameError(null); setFirstFrameError(null);
setActionError(null);
setSubmitting(true); setSubmitting(true);
setFirstFramePickerOpen(false);
try { try {
await sendMessage('使用作品图片作为视频首帧', [asset.assetId]); await sendMessage('使用作品图片作为视频首帧', [asset.assetId]);
if (useImageWorkspaceStore.getState().activeWorkspaceId === requestedWorkspaceId) {
setFirstFramePickerOpen(false);
}
} catch (error) { } catch (error) {
if (useImageWorkspaceStore.getState().activeWorkspaceId === requestedWorkspaceId) { if (useImageWorkspaceStore.getState().activeWorkspaceId === requestedWorkspaceId) {
setFirstFrameError(error instanceof Error ? error.message : String(error)); setActionError(error instanceof Error ? error.message : String(error));
} }
} finally { } finally {
setFirstFrameBusyKey(null); setFirstFrameBusyKey(null);

View File

@@ -570,6 +570,8 @@ describe('ImageCanvas Workspace-first design experience', () => {
}); });
it('submits a successful work Asset id when it is selected as the video first frame', async () => { it('submits a successful work Asset id when it is selected as the video first frame', async () => {
const pendingSelection = deferred<DesignWorkspace>();
sendImageWorkspaceMessageMock.mockReturnValueOnce(pendingSelection.promise);
fetchImageWorkspaceProjectMock.mockResolvedValueOnce({ fetchImageWorkspaceProjectMock.mockResolvedValueOnce({
...workspaceFixture(), ...workspaceFixture(),
turnRevision: 2, turnRevision: 2,
@@ -603,6 +605,12 @@ describe('ImageCanvas Workspace-first design experience', () => {
expect.stringMatching(/^turn-/), expect.stringMatching(/^turn-/),
['asset-one'], ['asset-one'],
)); ));
expect(screen.queryByRole('dialog', { name: '选择视频首帧' })).not.toBeInTheDocument();
await act(async () => {
pendingSelection.resolve(workspaceFixture());
await pendingSelection.promise;
});
}); });
it('uploads a local first-frame image and submits its Asset id to the Agent', async () => { it('uploads a local first-frame image and submits its Asset id to the Agent', async () => {