修复视频首帧选择弹窗交互
问题:选择作品图片后需等待 Agent 整轮响应,弹窗长时间不关闭。 修复:选择后立即关闭弹窗并继续提交 Asset ID,失败信息转到主对话区;补充慢响应回归测试。
This commit is contained in:
@@ -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.
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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 () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user