迁移画布素材生成元数据
扩展 editor_project_resource 和 editor_asset 保存素材类别与生成输入快照 调整前端资源与素材读写链路并停止把素材元数据写入新 layout 在服务端保存 layout 时回填并清洗旧图层元数据 更新图片画布契约文档、共享决策和相关测试期望
This commit is contained in:
@@ -905,6 +905,15 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
sourceType: 'generated',
|
||||
width: 2048,
|
||||
height: 1152,
|
||||
assetKind: 'spec',
|
||||
generationInputs: expect.objectContaining({
|
||||
fields: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
title: '玩法设定',
|
||||
value: '平台跳跃玩法',
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
@@ -915,7 +924,6 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
layers: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
title: expect.stringMatching(/角色规范/u),
|
||||
assetKind: 'spec',
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
@@ -1791,7 +1799,6 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
layers: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
title: expect.stringMatching(/角色形象/u),
|
||||
assetKind: 'character',
|
||||
objectKey:
|
||||
'generated-character-drafts/editor/character-images/editor-character-1/image.png',
|
||||
assetObjectId: 'asset-object-editor-character-1',
|
||||
@@ -1807,6 +1814,16 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
objectKey:
|
||||
'generated-character-drafts/editor/character-images/editor-character-1/image.png',
|
||||
assetObjectId: 'asset-object-editor-character-1',
|
||||
assetKind: 'character',
|
||||
generationInputs: expect.objectContaining({
|
||||
fields: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
title: '角色设定',
|
||||
value:
|
||||
'银发游侠,蓝色披风,弓箭手,适合像素风战棋。',
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
@@ -1990,22 +2007,27 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
expect(within(iconInfoPanel).getByText('图标规范')).toBeTruthy();
|
||||
expect(within(iconInfoPanel).getByText('清爽按钮图标规范')).toBeTruthy();
|
||||
await waitFor(() => {
|
||||
expect(saveEditorProjectLayoutMock).toHaveBeenCalledWith(
|
||||
expect(createEditorProjectResourceMock).toHaveBeenCalledWith(
|
||||
'editor-project-icons',
|
||||
expect.objectContaining({
|
||||
layers: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
title: '返回按钮',
|
||||
assetKind: 'icon',
|
||||
}),
|
||||
expect.objectContaining({
|
||||
title: '设置按钮',
|
||||
assetKind: 'icon',
|
||||
}),
|
||||
]),
|
||||
assetKind: 'icon',
|
||||
generationInputs: expect.objectContaining({
|
||||
fields: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
title: '素材描述',
|
||||
value: '返回按钮\n设置按钮',
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
expect(createEditorProjectResourceMock).toHaveBeenCalledWith(
|
||||
'editor-project-icons',
|
||||
expect.objectContaining({
|
||||
assetKind: 'icon',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('allows icon asset generation to reference icon specs created from the renamed spec entry', async () => {
|
||||
@@ -2064,15 +2086,18 @@ describe('ImageCanvasEditorView generation integration', () => {
|
||||
}),
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(saveEditorProjectLayoutMock).toHaveBeenCalledWith(
|
||||
expect(createEditorProjectResourceMock).toHaveBeenCalledWith(
|
||||
'editor-project-default',
|
||||
expect.objectContaining({
|
||||
layers: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
title: expect.stringMatching(/图标规范/u),
|
||||
assetKind: 'icon-spec',
|
||||
}),
|
||||
]),
|
||||
assetKind: 'icon-spec',
|
||||
generationInputs: expect.objectContaining({
|
||||
fields: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
title: '玩法设定',
|
||||
value: '背包整理玩法',
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -112,10 +112,24 @@ describe('ImageCanvasEditorModel', () => {
|
||||
|
||||
const snapshot = serializeLayer(layer);
|
||||
expect(snapshot).not.toHaveProperty('src');
|
||||
expect(snapshot).not.toHaveProperty('assetKind');
|
||||
expect(snapshot).not.toHaveProperty('generationInputs');
|
||||
|
||||
const hydrated = hydrateLayer(
|
||||
snapshot,
|
||||
new Map([['resource-generated', { imageSrc: '/read/generated.png' }]]),
|
||||
new Map([
|
||||
[
|
||||
'resource-generated',
|
||||
{
|
||||
imageSrc: '/read/generated.png',
|
||||
assetKind: 'character',
|
||||
generationInputs: {
|
||||
fields: [{ title: '角色设定', value: '骑士' }],
|
||||
references: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
]),
|
||||
);
|
||||
|
||||
expect(hydrated).toMatchObject({
|
||||
@@ -126,6 +140,7 @@ describe('ImageCanvasEditorModel', () => {
|
||||
objectKey: 'generated/object.png',
|
||||
locked: true,
|
||||
});
|
||||
expect(hydrated?.generationInputs?.fields[0]?.value).toBe('骑士');
|
||||
});
|
||||
|
||||
it('hydrates audio media type and sound effect asset kind from saved layout', () => {
|
||||
|
||||
@@ -137,6 +137,8 @@ export function createLayerFromAsset(
|
||||
assetObjectId: asset.assetObjectId,
|
||||
durationSeconds: asset.durationSeconds,
|
||||
sourceAssetId: asset.id,
|
||||
assetKind: asset.assetKind,
|
||||
generationInputs: asset.generationInputs,
|
||||
} satisfies CanvasLayer;
|
||||
}
|
||||
|
||||
@@ -167,8 +169,6 @@ export function serializeLayer(
|
||||
sourceResourceId: layer.sourceResourceId,
|
||||
sourceAssetId: layer.sourceAssetId,
|
||||
groupId: layer.groupId,
|
||||
assetKind: layer.assetKind,
|
||||
generationInputs: layer.generationInputs,
|
||||
hidden: layer.hidden,
|
||||
locked: layer.locked,
|
||||
flipX: layer.flipX,
|
||||
@@ -356,13 +356,14 @@ export function hydrateCanvasGenerationDialog(
|
||||
|
||||
export function hydrateLayer(
|
||||
snapshot: EditorProjectLayerSnapshot,
|
||||
resourcesById: Map<string, { imageSrc: string }>,
|
||||
resourcesById: Map<string, CanvasLayerResourceMetadata>,
|
||||
): CanvasLayer | null {
|
||||
const resourceId =
|
||||
typeof snapshot.resourceId === 'string' ? snapshot.resourceId : '';
|
||||
const layerId = typeof snapshot.layerId === 'string' ? snapshot.layerId : '';
|
||||
const resource = resourcesById.get(resourceId);
|
||||
const snapshotSrc = typeof snapshot.src === 'string' ? snapshot.src : '';
|
||||
const src = snapshotSrc || resourcesById.get(resourceId)?.imageSrc || '';
|
||||
const src = snapshotSrc || resource?.imageSrc || '';
|
||||
const title =
|
||||
typeof snapshot.title === 'string' ? snapshot.title : '画布图片';
|
||||
if (!resourceId || !layerId || !src) {
|
||||
@@ -405,16 +406,16 @@ export function hydrateLayer(
|
||||
assetObjectId: stringOrNull(snapshot.assetObjectId),
|
||||
durationSeconds:
|
||||
audioDurationOrNull(snapshot.durationSeconds) ??
|
||||
audioDurationOrNull(
|
||||
resourcesById.get(resourceId) as
|
||||
| ({ imageSrc: string } & { durationSeconds?: unknown })
|
||||
| undefined,
|
||||
),
|
||||
audioDurationOrNull(resource?.durationSeconds),
|
||||
sourceResourceId: stringOrNull(snapshot.sourceResourceId),
|
||||
sourceAssetId: stringOrNull(snapshot.sourceAssetId),
|
||||
groupId: stringOrNull(snapshot.groupId),
|
||||
assetKind: canvasAssetKindOrNull(snapshot.assetKind),
|
||||
generationInputs: generationInputsOrNull(snapshot.generationInputs),
|
||||
assetKind:
|
||||
canvasAssetKindOrNull(resource?.assetKind) ??
|
||||
canvasAssetKindOrNull(snapshot.assetKind),
|
||||
generationInputs:
|
||||
generationInputsOrNull(resource?.generationInputs) ??
|
||||
generationInputsOrNull(snapshot.generationInputs),
|
||||
hidden: booleanFromSnapshot(snapshot.hidden),
|
||||
locked: booleanFromSnapshot(snapshot.locked),
|
||||
flipX: booleanFromSnapshot(snapshot.flipX),
|
||||
@@ -453,11 +454,20 @@ export function mapAssetLibrarySnapshot(
|
||||
taskId: asset.taskId ?? undefined,
|
||||
objectKey: asset.objectKey ?? undefined,
|
||||
assetObjectId: asset.assetObjectId ?? undefined,
|
||||
assetKind: canvasAssetKindOrNull(asset.assetKind),
|
||||
generationInputs: generationInputsOrNull(asset.generationInputs),
|
||||
durationSeconds: asset.durationSeconds ?? undefined,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
export type CanvasLayerResourceMetadata = {
|
||||
imageSrc: string;
|
||||
durationSeconds?: number | null;
|
||||
assetKind?: string | null;
|
||||
generationInputs?: unknown;
|
||||
};
|
||||
|
||||
export function normalizeAssetLibrary(library: EditorAssetLibrarySnapshot) {
|
||||
const mapped = mapAssetLibrarySnapshot(library);
|
||||
let hasDefaultFolder = false;
|
||||
@@ -666,6 +676,7 @@ export function canvasAssetKindOrNull(value: unknown): CanvasAssetKind | null {
|
||||
value === 'icon' ||
|
||||
value === 'icon-spritesheet' ||
|
||||
value === 'icon-spec' ||
|
||||
value === 'publication-material' ||
|
||||
value === 'ui-design' ||
|
||||
value === 'video' ||
|
||||
value === 'sound-effect' ||
|
||||
|
||||
@@ -41,6 +41,8 @@ export type EditorAsset = {
|
||||
taskId?: string;
|
||||
objectKey?: string;
|
||||
assetObjectId?: string;
|
||||
assetKind?: CanvasAssetKind | null;
|
||||
generationInputs?: CanvasGenerationInputs | null;
|
||||
durationSeconds?: number;
|
||||
uploadStatus?: 'uploading' | 'failed';
|
||||
uploadProgress?: number;
|
||||
|
||||
@@ -264,6 +264,9 @@ export function setupImageCanvasEditorViewTestLifecycle({
|
||||
width: input.width,
|
||||
height: input.height,
|
||||
sourceType: input.sourceType,
|
||||
assetKind: input.assetKind,
|
||||
generationInputs: input.generationInputs,
|
||||
durationSeconds: input.durationSeconds,
|
||||
}));
|
||||
createEditorAssetFolderMock.mockResolvedValue({
|
||||
folderId: 'folder-role-persisted',
|
||||
|
||||
@@ -14,7 +14,11 @@ import {
|
||||
} from '../../services/image-editor/editorProjectClient';
|
||||
import { useAuthUi } from '../auth/AuthUiContext';
|
||||
import { PlatformDangerConfirmDialog } from '../common/PlatformDangerConfirmDialog';
|
||||
import { resolveContextMenuPosition } from './ImageCanvasEditorModel';
|
||||
import {
|
||||
canvasAssetKindOrNull,
|
||||
generationInputsOrNull,
|
||||
resolveContextMenuPosition,
|
||||
} from './ImageCanvasEditorModel';
|
||||
import { ImageCanvasEditorShellView } from './ImageCanvasEditorShellView';
|
||||
import type {
|
||||
AssetPointerDragState,
|
||||
@@ -340,6 +344,9 @@ export function ImageCanvasEditorView() {
|
||||
model: layer.model,
|
||||
provider: layer.provider,
|
||||
taskId: layer.taskId,
|
||||
durationSeconds: layer.durationSeconds,
|
||||
assetKind: layer.assetKind,
|
||||
generationInputs: layer.generationInputs,
|
||||
})
|
||||
.then((asset) => {
|
||||
setAssets((currentAssets) => [
|
||||
@@ -363,6 +370,9 @@ export function ImageCanvasEditorView() {
|
||||
taskId: asset.taskId ?? undefined,
|
||||
objectKey: asset.objectKey ?? undefined,
|
||||
assetObjectId: asset.assetObjectId ?? undefined,
|
||||
durationSeconds: asset.durationSeconds ?? undefined,
|
||||
assetKind: canvasAssetKindOrNull(asset.assetKind),
|
||||
generationInputs: generationInputsOrNull(asset.generationInputs),
|
||||
},
|
||||
]);
|
||||
setAssetFolders((currentFolders) =>
|
||||
|
||||
@@ -29,7 +29,10 @@ vi.mock('../../services/image-editor/editorProjectClient', async () => {
|
||||
};
|
||||
});
|
||||
|
||||
function createLayer(id: string): CanvasLayer {
|
||||
function createLayer(
|
||||
id: string,
|
||||
overrides: Partial<CanvasLayer> = {},
|
||||
): CanvasLayer {
|
||||
return {
|
||||
id,
|
||||
resourceId: `local-${id}`,
|
||||
@@ -44,6 +47,7 @@ function createLayer(id: string): CanvasLayer {
|
||||
zIndex: 3,
|
||||
sourceType: 'uploaded',
|
||||
sourceAssetId: 'asset-a',
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -118,7 +122,14 @@ function ProjectPersistenceHarness({
|
||||
<span data-testid="project-title">{projectTitle}</span>
|
||||
<span data-testid="project-rename">{projectRenameValue}</span>
|
||||
<span data-testid="layers">
|
||||
{layers.map((layer) => `${layer.id}:${layer.resourceId}`).join(',')}
|
||||
{layers
|
||||
.map(
|
||||
(layer) =>
|
||||
`${layer.id}:${layer.resourceId}:${layer.assetKind ?? '-'}:${
|
||||
layer.generationInputs?.fields[0]?.value ?? '-'
|
||||
}`,
|
||||
)
|
||||
.join(',')}
|
||||
</span>
|
||||
<span data-testid="selected">{selectedLayerRef.current ?? '-'}</span>
|
||||
<span data-testid="counter">{layerCounterRef.current}</span>
|
||||
@@ -135,6 +146,24 @@ function ProjectPersistenceHarness({
|
||||
>
|
||||
append
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
persistence.appendCanvasLayersWithResources([
|
||||
createLayer('layer-character', {
|
||||
title: '角色形象',
|
||||
sourceType: 'generated',
|
||||
assetKind: 'character',
|
||||
generationInputs: {
|
||||
fields: [{ title: '角色设定', value: '银发游侠' }],
|
||||
references: [],
|
||||
},
|
||||
}),
|
||||
]);
|
||||
}}
|
||||
>
|
||||
append character
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
@@ -218,11 +247,11 @@ describe('useImageCanvasProjectPersistence', () => {
|
||||
});
|
||||
|
||||
expect(screen.getByTestId('layers').textContent).toBe(
|
||||
'layer-a:local-layer-a',
|
||||
'layer-a:local-layer-a:-:-',
|
||||
);
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('layers').textContent).toBe(
|
||||
'layer-a:resource-added-asset-a',
|
||||
'layer-a:resource-added-asset-a:-:-',
|
||||
);
|
||||
});
|
||||
await waitFor(() => {
|
||||
@@ -241,6 +270,83 @@ describe('useImageCanvasProjectPersistence', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('persists generated layer metadata on the project resource and restores it from resources', async () => {
|
||||
loadOrCreateRecentEditorProjectMock.mockResolvedValueOnce({
|
||||
projectId: 'editor-project-default',
|
||||
title: '已有角色项目',
|
||||
viewport: { x: 0, y: 0, scale: 1 },
|
||||
layers: [
|
||||
{
|
||||
layerId: 'layer-character',
|
||||
resourceId: 'resource-character',
|
||||
title: '角色形象',
|
||||
x: 10,
|
||||
y: 20,
|
||||
width: 320,
|
||||
height: 240,
|
||||
originalWidth: 320,
|
||||
originalHeight: 240,
|
||||
zIndex: 3,
|
||||
sourceType: 'generated',
|
||||
},
|
||||
],
|
||||
resources: [
|
||||
{
|
||||
resourceId: 'resource-character',
|
||||
projectId: 'editor-project-default',
|
||||
imageSrc: '/generated/character.png',
|
||||
width: 320,
|
||||
height: 240,
|
||||
sourceType: 'generated',
|
||||
assetKind: 'character',
|
||||
generationInputs: {
|
||||
fields: [{ title: '角色设定', value: '银发游侠' }],
|
||||
references: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
updatedAt: '2026-06-12T00:00:00.000Z',
|
||||
});
|
||||
createEditorProjectResourceMock.mockResolvedValueOnce({
|
||||
resourceId: 'resource-character-new',
|
||||
projectId: 'editor-project-default',
|
||||
imageSrc: 'data:image/png;base64,YQ==',
|
||||
width: 320,
|
||||
height: 240,
|
||||
sourceType: 'generated',
|
||||
assetKind: 'character',
|
||||
generationInputs: {
|
||||
fields: [{ title: '角色设定', value: '银发游侠' }],
|
||||
references: [],
|
||||
},
|
||||
});
|
||||
|
||||
render(<ProjectPersistenceHarness />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByTestId('layers').textContent).toBe(
|
||||
'layer-character:resource-character:character:银发游侠',
|
||||
);
|
||||
});
|
||||
act(() => {
|
||||
screen.getByRole('button', { name: 'append character' }).click();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(createEditorProjectResourceMock).toHaveBeenCalledWith(
|
||||
'editor-project-default',
|
||||
expect.objectContaining({
|
||||
sourceType: 'generated',
|
||||
assetKind: 'character',
|
||||
generationInputs: {
|
||||
fields: [{ title: '角色设定', value: '银发游侠' }],
|
||||
references: [],
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('saves generation dialogs in the project layout and restores them on load', async () => {
|
||||
const savedDialog: CanvasGenerationDialogState = {
|
||||
id: 'generation-dialog-1',
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
saveEditorProjectLayout,
|
||||
} from '../../services/image-editor/editorProjectClient';
|
||||
import {
|
||||
type CanvasLayerResourceMetadata,
|
||||
hydrateLayer,
|
||||
serializeCanvasLayout,
|
||||
splitCanvasLayoutItems,
|
||||
@@ -108,6 +109,8 @@ export function useImageCanvasProjectPersistence({
|
||||
taskId: layer.taskId,
|
||||
durationSeconds: layer.durationSeconds,
|
||||
sourceResourceId: layer.sourceResourceId,
|
||||
assetKind: layer.assetKind,
|
||||
generationInputs: layer.generationInputs,
|
||||
})
|
||||
.then((resource) => {
|
||||
options.onCreated?.(resource.resourceId);
|
||||
@@ -205,12 +208,14 @@ export function useImageCanvasProjectPersistence({
|
||||
createProjectResourceForLayer(layer, options);
|
||||
});
|
||||
setViewport(project.viewport);
|
||||
const resourcesById = new Map(
|
||||
const resourcesById = new Map<string, CanvasLayerResourceMetadata>(
|
||||
project.resources.map((resource) => [
|
||||
resource.resourceId,
|
||||
{
|
||||
imageSrc: resource.imageSrc,
|
||||
durationSeconds: resource.durationSeconds,
|
||||
assetKind: resource.assetKind,
|
||||
generationInputs: resource.generationInputs,
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
@@ -279,6 +279,11 @@ describe('editorProjectClient', () => {
|
||||
prompt: 'dragon knight',
|
||||
model: 'gpt-image-2',
|
||||
sourceResourceId: 'resource-source',
|
||||
assetKind: 'character',
|
||||
generationInputs: {
|
||||
fields: [{ title: '角色设定', value: 'dragon knight' }],
|
||||
references: [],
|
||||
},
|
||||
});
|
||||
|
||||
expect(requestJsonMock).toHaveBeenCalledWith(
|
||||
@@ -295,6 +300,11 @@ describe('editorProjectClient', () => {
|
||||
prompt: 'dragon knight',
|
||||
model: 'gpt-image-2',
|
||||
sourceResourceId: 'resource-source',
|
||||
assetKind: 'character',
|
||||
generationInputs: {
|
||||
fields: [{ title: '角色设定', value: 'dragon knight' }],
|
||||
references: [],
|
||||
},
|
||||
}),
|
||||
}),
|
||||
'创建图片画布资源失败',
|
||||
@@ -425,6 +435,11 @@ describe('editorProjectClient', () => {
|
||||
width: 640,
|
||||
height: 480,
|
||||
sourceType: 'uploaded',
|
||||
assetKind: 'icon',
|
||||
generationInputs: {
|
||||
fields: [{ title: '素材描述', value: '返回按钮' }],
|
||||
references: [],
|
||||
},
|
||||
});
|
||||
await updateEditorAsset('asset-1', {
|
||||
label: '角色主视觉.png',
|
||||
@@ -444,6 +459,11 @@ describe('editorProjectClient', () => {
|
||||
width: 640,
|
||||
height: 480,
|
||||
sourceType: 'uploaded',
|
||||
assetKind: 'icon',
|
||||
generationInputs: {
|
||||
fields: [{ title: '素材描述', value: '返回按钮' }],
|
||||
references: [],
|
||||
},
|
||||
}),
|
||||
}),
|
||||
'创建图片画布素材失败',
|
||||
|
||||
@@ -29,6 +29,22 @@ export type EditorProjectLayerSnapshot = Record<string, unknown> & {
|
||||
resourceId: string;
|
||||
};
|
||||
|
||||
export type EditorAssetGenerationInputField = {
|
||||
title: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type EditorAssetGenerationInputReference = {
|
||||
title: string;
|
||||
label: string;
|
||||
src: string;
|
||||
};
|
||||
|
||||
export type EditorAssetGenerationInputs = {
|
||||
fields: EditorAssetGenerationInputField[];
|
||||
references: EditorAssetGenerationInputReference[];
|
||||
};
|
||||
|
||||
export type EditorProjectResourceSourceType =
|
||||
| 'uploaded'
|
||||
| 'generated'
|
||||
@@ -50,6 +66,8 @@ export type EditorProjectResourceSnapshot = {
|
||||
taskId?: string | null;
|
||||
durationSeconds?: number | null;
|
||||
sourceResourceId?: string | null;
|
||||
assetKind?: string | null;
|
||||
generationInputs?: EditorAssetGenerationInputs | null;
|
||||
createdAt?: string;
|
||||
updatedAt?: string;
|
||||
};
|
||||
@@ -80,6 +98,8 @@ export type EditorAssetSnapshot = {
|
||||
provider?: string | null;
|
||||
taskId?: string | null;
|
||||
durationSeconds?: number | null;
|
||||
assetKind?: string | null;
|
||||
generationInputs?: EditorAssetGenerationInputs | null;
|
||||
createdAt?: string;
|
||||
updatedAt?: string;
|
||||
};
|
||||
@@ -311,6 +331,8 @@ export type EditorProjectResourceCreateInput = {
|
||||
taskId?: string | null;
|
||||
durationSeconds?: number | null;
|
||||
sourceResourceId?: string | null;
|
||||
assetKind?: string | null;
|
||||
generationInputs?: EditorAssetGenerationInputs | null;
|
||||
};
|
||||
|
||||
export type EditorAssetCreateInput = {
|
||||
@@ -328,6 +350,8 @@ export type EditorAssetCreateInput = {
|
||||
provider?: string | null;
|
||||
taskId?: string | null;
|
||||
durationSeconds?: number | null;
|
||||
assetKind?: string | null;
|
||||
generationInputs?: EditorAssetGenerationInputs | null;
|
||||
};
|
||||
|
||||
export type EditorAssetUpdateInput = {
|
||||
|
||||
Reference in New Issue
Block a user