mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 14:30:41 +00:00
## Summary Rename `imagePreviewStore.ts` → `nodeOutputStore.ts` to match the store it houses (`useNodeOutputStore`, Pinia ID `nodeOutput`). ## Changes - **What**: Rename file + test file, update all 21 import paths, mock paths, and describe labels - **Breaking**: None — exported symbol (`useNodeOutputStore`) and Pinia store ID (`nodeOutput`) are unchanged ## Custom Node Ecosystem Audit Searched the ComfyUI custom node ecosystem for `imagePreviewStore` and `useNodeOutputStore`: - **Not part of the public API** — neither filename nor export appear in `comfyui_frontend_package` or `vite.types.config.mts` - **1 external repo found:** `wallen0322/ComfyUI-AE-Animation` — contains a full fork of the frontend source tree; it copies the file internally and does not import from the published package. **No breakage.** - **No custom nodes import this store via the extension API.** This is a safe internal-only rename. ## Review Focus Pure mechanical rename — no logic changes. Verify no stale `imagePreviewStore` references remain. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9416-refactor-rename-imagePreviewStore-to-nodeOutputStore-31a6d73d3650816086c5e62959861ddb) by [Unito](https://www.unito.io) Co-authored-by: Alexander Brown <drjkl@comfy.org>
128 lines
4.3 KiB
TypeScript
128 lines
4.3 KiB
TypeScript
import { useNodeImage, useNodeVideo } from '@/composables/node/useNodeImage'
|
|
import { useNodeImageUpload } from '@/composables/node/useNodeImageUpload'
|
|
import { t } from '@/i18n'
|
|
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
|
import type { IComboWidget } from '@/lib/litegraph/src/types/widgets'
|
|
import type { ResultItemType } from '@/schemas/apiSchema'
|
|
import type { InputSpec } from '@/schemas/nodeDefSchema'
|
|
import type { ComfyWidgetConstructor } from '@/scripts/widgets'
|
|
import { useNodeOutputStore } from '@/stores/nodeOutputStore'
|
|
import { isImageUploadInput } from '@/types/nodeDefAugmentation'
|
|
import { createAnnotatedPath } from '@/utils/createAnnotatedPath'
|
|
import { addToComboValues } from '@/utils/litegraphUtil'
|
|
|
|
const ACCEPTED_IMAGE_TYPES = 'image/png,image/jpeg,image/webp'
|
|
const ACCEPTED_VIDEO_TYPES = 'video/webm,video/mp4'
|
|
|
|
const isImageFile = (file: File) => file.type.startsWith('image/')
|
|
const isVideoFile = (file: File) => file.type.startsWith('video/')
|
|
|
|
const findFileComboWidget = (
|
|
node: LGraphNode,
|
|
inputName: string
|
|
): IComboWidget | undefined =>
|
|
node.widgets?.find((w): w is IComboWidget => w.name === inputName)
|
|
|
|
export const useImageUploadWidget = () => {
|
|
const widgetConstructor: ComfyWidgetConstructor = (
|
|
node: LGraphNode,
|
|
inputName: string,
|
|
inputData: InputSpec
|
|
) => {
|
|
if (!isImageUploadInput(inputData)) {
|
|
throw new Error(
|
|
'Image upload widget requires imageInputName augmentation'
|
|
)
|
|
}
|
|
|
|
const inputOptions = inputData[1]
|
|
const { imageInputName, allow_batch, image_folder = 'input' } = inputOptions
|
|
const folder: ResultItemType | undefined = image_folder
|
|
const nodeOutputStore = useNodeOutputStore()
|
|
|
|
const isAnimated = !!inputOptions.animated_image_upload
|
|
const isVideo = !!inputOptions.video_upload
|
|
const accept = isVideo ? ACCEPTED_VIDEO_TYPES : ACCEPTED_IMAGE_TYPES
|
|
const { showPreview } = isVideo ? useNodeVideo(node) : useNodeImage(node)
|
|
|
|
const fileFilter = isVideo ? isVideoFile : isImageFile
|
|
const fileComboWidget = findFileComboWidget(node, imageInputName)
|
|
if (!fileComboWidget) {
|
|
throw new Error(`Widget "${imageInputName}" not found on node`)
|
|
}
|
|
const formatPath = (value: string) =>
|
|
createAnnotatedPath(value, { rootFolder: image_folder })
|
|
|
|
// Setup file upload handling
|
|
let rollback: (() => void) | undefined
|
|
const { openFileSelection } = useNodeImageUpload(node, {
|
|
allow_batch,
|
|
fileFilter,
|
|
accept,
|
|
folder,
|
|
onUploadStart: (files) => {
|
|
if (files.length > 0) {
|
|
const prev = fileComboWidget.value
|
|
fileComboWidget.value = files[0].name
|
|
rollback = () => {
|
|
fileComboWidget.value = prev
|
|
}
|
|
}
|
|
},
|
|
onUploadError: () => {
|
|
rollback?.()
|
|
rollback = undefined
|
|
},
|
|
onUploadComplete: (output) => {
|
|
rollback = undefined
|
|
const annotated = output.map(formatPath)
|
|
annotated.forEach((path) => {
|
|
addToComboValues(fileComboWidget, path)
|
|
})
|
|
|
|
const newValue = allow_batch ? annotated : annotated[0]
|
|
|
|
// @ts-expect-error litegraph combo value type does not support arrays yet
|
|
fileComboWidget.value = newValue
|
|
fileComboWidget.callback?.(newValue)
|
|
}
|
|
})
|
|
|
|
// Create the button widget for selecting the files
|
|
const uploadWidget = node.addWidget(
|
|
'button',
|
|
inputName,
|
|
'image',
|
|
() => openFileSelection(),
|
|
{
|
|
serialize: false,
|
|
canvasOnly: true
|
|
}
|
|
)
|
|
uploadWidget.label = t('g.choose_file_to_upload')
|
|
|
|
// Add our own callback to the combo widget to render an image when it changes
|
|
fileComboWidget.callback = function () {
|
|
node.imgs = undefined
|
|
nodeOutputStore.setNodeOutputs(node, String(fileComboWidget.value), {
|
|
isAnimated
|
|
})
|
|
node.graph?.setDirtyCanvas(true)
|
|
}
|
|
|
|
// On load if we have a value then render the image
|
|
// The value isn't set immediately so we need to wait a moment
|
|
// No change callbacks seem to be fired on initial setting of the value
|
|
requestAnimationFrame(() => {
|
|
nodeOutputStore.setNodeOutputs(node, String(fileComboWidget.value), {
|
|
isAnimated
|
|
})
|
|
showPreview({ block: false })
|
|
})
|
|
|
|
return { widget: uploadWidget }
|
|
}
|
|
|
|
return widgetConstructor
|
|
}
|