mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 06:20:11 +00:00
fix: support non-standard output keys in app mode preview
Replace hardcoded allowlist of 5 output keys (images, audio, video, gifs, 3d) with dynamic iteration over all output entries, validating each item with isResultItemLike. Nodes like ImageCompare that output non-standard keys (a_images, b_images) now preview correctly.
This commit is contained in:
@@ -82,4 +82,41 @@ describe(flattenNodeOutput, () => {
|
||||
const result = flattenNodeOutput(['1', output])
|
||||
expect(result).toEqual([])
|
||||
})
|
||||
|
||||
it('flattens non-standard output keys with ResultItem-like values', () => {
|
||||
const output = makeOutput({
|
||||
a_images: [{ filename: 'before.png', subfolder: '', type: 'output' }],
|
||||
b_images: [{ filename: 'after.png', subfolder: '', type: 'output' }]
|
||||
} as unknown as Partial<NodeExecutionOutput>)
|
||||
|
||||
const result = flattenNodeOutput(['10', output])
|
||||
|
||||
expect(result).toHaveLength(2)
|
||||
expect(result.map((r) => r.filename)).toContain('before.png')
|
||||
expect(result.map((r) => r.filename)).toContain('after.png')
|
||||
})
|
||||
|
||||
it('excludes animated key', () => {
|
||||
const output = makeOutput({
|
||||
images: [{ filename: 'img.png', subfolder: '', type: 'output' }],
|
||||
animated: [true]
|
||||
})
|
||||
|
||||
const result = flattenNodeOutput(['1', output])
|
||||
|
||||
expect(result).toHaveLength(1)
|
||||
expect(result[0].mediaType).toBe('images')
|
||||
})
|
||||
|
||||
it('excludes non-ResultItem array items', () => {
|
||||
const output = {
|
||||
images: [{ filename: 'img.png', subfolder: '', type: 'output' }],
|
||||
custom_data: [{ randomKey: 123 }]
|
||||
} as unknown as NodeExecutionOutput
|
||||
|
||||
const result = flattenNodeOutput(['1', output])
|
||||
|
||||
expect(result).toHaveLength(1)
|
||||
expect(result[0].mediaType).toBe('images')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,20 +1,57 @@
|
||||
import type { NodeExecutionOutput, ResultItem } from '@/schemas/apiSchema'
|
||||
import { resultItemType } from '@/schemas/apiSchema'
|
||||
import { ResultItemImpl } from '@/stores/queueStore'
|
||||
|
||||
const EXCLUDED_KEYS = new Set(['animated'])
|
||||
|
||||
function isResultItemLike(item: unknown): item is ResultItem {
|
||||
if (!item || typeof item !== 'object' || Array.isArray(item)) {
|
||||
return false
|
||||
}
|
||||
|
||||
const candidate = item as Record<string, unknown>
|
||||
|
||||
if (
|
||||
candidate.filename !== undefined &&
|
||||
typeof candidate.filename !== 'string'
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (
|
||||
candidate.subfolder !== undefined &&
|
||||
typeof candidate.subfolder !== 'string'
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (
|
||||
candidate.type !== undefined &&
|
||||
!resultItemType.safeParse(candidate.type).success
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (
|
||||
candidate.filename === undefined &&
|
||||
candidate.subfolder === undefined &&
|
||||
candidate.type === undefined
|
||||
) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
export function flattenNodeOutput([nodeId, nodeOutput]: [
|
||||
string | number,
|
||||
NodeExecutionOutput
|
||||
]): ResultItemImpl[] {
|
||||
const knownOutputs: Record<string, ResultItem[]> = {}
|
||||
if (nodeOutput.audio) knownOutputs.audio = nodeOutput.audio
|
||||
if (nodeOutput.images) knownOutputs.images = nodeOutput.images
|
||||
if (nodeOutput.video) knownOutputs.video = nodeOutput.video
|
||||
if (nodeOutput.gifs) knownOutputs.gifs = nodeOutput.gifs as ResultItem[]
|
||||
if (nodeOutput['3d']) knownOutputs['3d'] = nodeOutput['3d'] as ResultItem[]
|
||||
|
||||
return Object.entries(knownOutputs).flatMap(([mediaType, outputs]) =>
|
||||
outputs.map(
|
||||
(output) => new ResultItemImpl({ ...output, mediaType, nodeId })
|
||||
return Object.entries(nodeOutput)
|
||||
.filter(([key, value]) => !EXCLUDED_KEYS.has(key) && Array.isArray(value))
|
||||
.flatMap(([mediaType, items]) =>
|
||||
(items as unknown[])
|
||||
.filter(isResultItemLike)
|
||||
.map((item) => new ResultItemImpl({ ...item, mediaType, nodeId }))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user