收窄改造缺失来源拒绝范围
可补选的必填与可选引用统一按最佳努力恢复 仅对三个无来源替换入口的 action 拒绝改造 细化快速编辑与来源绑定错误提示 补充权威设计说明和回归测试
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -4942,6 +4942,47 @@ describe('useImageCanvasGenerationWorkflow', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('best-effort restores a required reference that the target panel can replace', () => {
|
||||
render(
|
||||
<GenerationWorkflowHarness
|
||||
initialLayers={[
|
||||
createLayer({
|
||||
sourceType: 'generated',
|
||||
assetKind: 'character',
|
||||
generationInputs: {
|
||||
version: 2,
|
||||
action: 'character.generate',
|
||||
fields: [
|
||||
{ id: 'prompt', title: '角色设定', value: '红发骑士' },
|
||||
{ id: 'model', title: '模型', value: DEFAULT_IMAGE_MODEL },
|
||||
{ id: 'style', title: '风格', value: 'none' },
|
||||
{ id: 'aspectRatio', title: '比例', value: '1:1' },
|
||||
{ id: 'imageSize', title: '尺寸', value: '1K' },
|
||||
],
|
||||
references: [
|
||||
{
|
||||
id: 'specReference',
|
||||
title: '角色规范',
|
||||
refType: 'project-resource',
|
||||
refId: 'resource-missing-character-spec',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '打开图片改造' }));
|
||||
|
||||
expect(screen.getByTestId('dialog').textContent).toContain(
|
||||
'character:idle:open',
|
||||
);
|
||||
expect(screen.getByTestId('reference-pick-warning').textContent).toBe(
|
||||
'部分原参考素材不在当前画布或来自面板上传,未恢复,请重新选择。',
|
||||
);
|
||||
});
|
||||
|
||||
it('warns and submits current defaults when V2 parameters are invalid', async () => {
|
||||
generateEditorImageMock.mockResolvedValueOnce(
|
||||
createGenerated({ prompt: '森林场景' }),
|
||||
@@ -5055,7 +5096,7 @@ describe('useImageCanvasGenerationWorkflow', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('does not legacy-fallback when a V2 required source is unavailable', () => {
|
||||
it('refuses redraw only when quick edit cannot replace its missing source', () => {
|
||||
render(
|
||||
<GenerationWorkflowHarness
|
||||
initialLayers={[
|
||||
@@ -5085,7 +5126,7 @@ describe('useImageCanvasGenerationWorkflow', () => {
|
||||
|
||||
expect(screen.getByTestId('dialog').textContent).toBe('-');
|
||||
expect(screen.getByTestId('reference-pick-warning').textContent).toBe(
|
||||
'原必需参考素材不在当前画布或来自面板上传,无法改造。',
|
||||
'原编辑目标不在当前画布,当前快速编辑面板无法重新选择编辑目标,无法改造。',
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -34,8 +34,10 @@ import {
|
||||
PERFECT_PIXEL_RECONCILIATION_WINDOW_MS,
|
||||
} from './ImageCanvasEditorModel';
|
||||
import type {
|
||||
CanvasGenerationAction,
|
||||
CanvasGenerationDialogState,
|
||||
CanvasHistoryAction,
|
||||
CanvasGenerationInputReference,
|
||||
CanvasLayer,
|
||||
CanvasTool,
|
||||
CanvasViewport,
|
||||
@@ -167,6 +169,44 @@ function getCanvasGenerationRedrawWarning({
|
||||
return null;
|
||||
}
|
||||
|
||||
const NON_REPLACEABLE_SOURCE_WARNING_BY_ACTION: Partial<
|
||||
Record<CanvasGenerationAction, string>
|
||||
> = {
|
||||
'image.edit':
|
||||
'原编辑目标不在当前画布,当前快速编辑面板无法重新选择编辑目标,无法改造。',
|
||||
'character-animation.generate':
|
||||
'原角色图层不在当前画布,当前角色动作面板无法重新选择来源角色,无法改造。',
|
||||
'ui-design.extract-assets':
|
||||
'原 UI 设计图不在当前画布,当前素材提取面板无法重新选择来源设计图,无法改造。',
|
||||
};
|
||||
|
||||
function getMissingNonReplaceableSourceWarning({
|
||||
action,
|
||||
references,
|
||||
unavailableReferences,
|
||||
}: {
|
||||
action: CanvasGenerationAction;
|
||||
references: CanvasGenerationInputReference[];
|
||||
unavailableReferences: CanvasGenerationInputReference[];
|
||||
}) {
|
||||
const warning = NON_REPLACEABLE_SOURCE_WARNING_BY_ACTION[action];
|
||||
if (!warning) {
|
||||
return null;
|
||||
}
|
||||
const unavailableSourceKeys = new Set(
|
||||
unavailableReferences
|
||||
.filter((reference) => reference.id === 'source')
|
||||
.map((reference) => `${reference.refType}:${reference.refId}`),
|
||||
);
|
||||
const hasAvailableSource = references
|
||||
.filter((reference) => reference.id === 'source')
|
||||
.some(
|
||||
(reference) =>
|
||||
!unavailableSourceKeys.has(`${reference.refType}:${reference.refId}`),
|
||||
);
|
||||
return hasAvailableSource ? null : warning;
|
||||
}
|
||||
|
||||
type CropExpandResizeDragState = {
|
||||
pointerId: number;
|
||||
handle: CropExpandResizeHandle;
|
||||
@@ -1819,6 +1859,17 @@ export function useImageCanvasGenerationWorkflow({
|
||||
layers,
|
||||
)
|
||||
: [];
|
||||
const missingNonReplaceableSourceWarning = normalizedGenerationInputs
|
||||
? getMissingNonReplaceableSourceWarning({
|
||||
action: normalizedGenerationInputs.action,
|
||||
references: normalizedGenerationInputs.references,
|
||||
unavailableReferences,
|
||||
})
|
||||
: null;
|
||||
if (missingNonReplaceableSourceWarning) {
|
||||
showGenerationWarning(missingNonReplaceableSourceWarning);
|
||||
return;
|
||||
}
|
||||
if (
|
||||
isNormalizedGenerationInputs &&
|
||||
normalizedGenerationInputs.action === 'ui-design.extract-assets'
|
||||
@@ -1835,7 +1886,9 @@ export function useImageCanvasGenerationWorkflow({
|
||||
: null;
|
||||
if (!extractionSource) {
|
||||
showGenerationWarning(
|
||||
'原 UI 设计图不在当前画布或来自面板上传,无法改造。',
|
||||
NON_REPLACEABLE_SOURCE_WARNING_BY_ACTION[
|
||||
'ui-design.extract-assets'
|
||||
]!,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -1908,11 +1961,7 @@ export function useImageCanvasGenerationWorkflow({
|
||||
return;
|
||||
}
|
||||
if (isNormalizedGenerationInputs) {
|
||||
showGenerationWarning(
|
||||
unavailableReferences.length
|
||||
? '原必需参考素材不在当前画布或来自面板上传,无法改造。'
|
||||
: '该生成配方当前无法恢复,无法改造。',
|
||||
);
|
||||
showGenerationWarning('该生成配方当前无法恢复,无法改造。');
|
||||
return;
|
||||
}
|
||||
if (sourceLayer.mediaType === 'audio') {
|
||||
|
||||
Reference in New Issue
Block a user