mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-22 15:54:09 +00:00
Update the frontend to support async nodes. (#4382)
Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: Christian Byrne <cbyrne@comfy.org>
This commit is contained in:
@@ -17,6 +17,7 @@ import type {
|
||||
LogsRawResponse,
|
||||
LogsWsMessage,
|
||||
PendingTaskItem,
|
||||
ProgressStateWsMessage,
|
||||
ProgressTextWsMessage,
|
||||
ProgressWsMessage,
|
||||
PromptResponse,
|
||||
@@ -105,7 +106,17 @@ interface BackendApiCalls {
|
||||
logs: LogsWsMessage
|
||||
/** Binary preview/progress data */
|
||||
b_preview: Blob
|
||||
/** Binary preview with metadata (node_id, prompt_id) */
|
||||
b_preview_with_metadata: {
|
||||
blob: Blob
|
||||
nodeId: string
|
||||
parentNodeId: string
|
||||
displayNodeId: string
|
||||
realNodeId: string
|
||||
promptId: string
|
||||
}
|
||||
progress_text: ProgressTextWsMessage
|
||||
progress_state: ProgressStateWsMessage
|
||||
display_component: DisplayComponentWsMessage
|
||||
feature_flags: FeatureFlagsWsMessage
|
||||
}
|
||||
@@ -457,6 +468,33 @@ export class ComfyApi extends EventTarget {
|
||||
})
|
||||
this.dispatchCustomEvent('b_preview', imageBlob)
|
||||
break
|
||||
case 4:
|
||||
// PREVIEW_IMAGE_WITH_METADATA
|
||||
const decoder4 = new TextDecoder()
|
||||
const metadataLength = view.getUint32(4)
|
||||
const metadataBytes = event.data.slice(8, 8 + metadataLength)
|
||||
const metadata = JSON.parse(decoder4.decode(metadataBytes))
|
||||
const imageData4 = event.data.slice(8 + metadataLength)
|
||||
|
||||
let imageMime4 = metadata.image_type
|
||||
|
||||
const imageBlob4 = new Blob([imageData4], {
|
||||
type: imageMime4
|
||||
})
|
||||
|
||||
// Dispatch enhanced preview event with metadata
|
||||
this.dispatchCustomEvent('b_preview_with_metadata', {
|
||||
blob: imageBlob4,
|
||||
nodeId: metadata.node_id,
|
||||
displayNodeId: metadata.display_node_id,
|
||||
parentNodeId: metadata.parent_node_id,
|
||||
realNodeId: metadata.real_node_id,
|
||||
promptId: metadata.prompt_id
|
||||
})
|
||||
|
||||
// Also dispatch legacy b_preview for backward compatibility
|
||||
this.dispatchCustomEvent('b_preview', imageBlob4)
|
||||
break
|
||||
default:
|
||||
throw new Error(
|
||||
`Unknown binary websocket message of type ${eventType}`
|
||||
@@ -486,6 +524,7 @@ export class ComfyApi extends EventTarget {
|
||||
case 'execution_cached':
|
||||
case 'execution_success':
|
||||
case 'progress':
|
||||
case 'progress_state':
|
||||
case 'executed':
|
||||
case 'graphChanged':
|
||||
case 'promptQueued':
|
||||
|
||||
@@ -194,6 +194,8 @@ export class ComfyApp {
|
||||
|
||||
/**
|
||||
* @deprecated Use useExecutionStore().executingNodeId instead
|
||||
* TODO: Update to support multiple executing nodes. This getter returns only the first executing node.
|
||||
* Consider updating consumers to handle multiple nodes or use executingNodeIds array.
|
||||
*/
|
||||
get runningNodeId(): NodeId | null {
|
||||
return useExecutionStore().executingNodeId
|
||||
@@ -635,10 +637,6 @@ export class ComfyApp {
|
||||
|
||||
api.addEventListener('executing', () => {
|
||||
this.graph.setDirtyCanvas(true, false)
|
||||
// @ts-expect-error fixme ts strict error
|
||||
this.revokePreviews(this.runningNodeId)
|
||||
// @ts-expect-error fixme ts strict error
|
||||
delete this.nodePreviewImages[this.runningNodeId]
|
||||
})
|
||||
|
||||
api.addEventListener('executed', ({ detail }) => {
|
||||
@@ -689,15 +687,13 @@ export class ComfyApp {
|
||||
this.canvas.draw(true, true)
|
||||
})
|
||||
|
||||
api.addEventListener('b_preview', ({ detail }) => {
|
||||
const id = this.runningNodeId
|
||||
if (id == null) return
|
||||
|
||||
const blob = detail
|
||||
api.addEventListener('b_preview_with_metadata', ({ detail }) => {
|
||||
// Enhanced preview with explicit node context
|
||||
const { blob, displayNodeId } = detail
|
||||
this.revokePreviews(displayNodeId)
|
||||
const blobUrl = URL.createObjectURL(blob)
|
||||
// Ensure clean up if `executing` event is missed.
|
||||
this.revokePreviews(id)
|
||||
this.nodePreviewImages[id] = [blobUrl]
|
||||
// Preview cleanup is now handled in progress_state event to support multiple concurrent previews
|
||||
this.nodePreviewImages[displayNodeId] = [blobUrl]
|
||||
})
|
||||
|
||||
api.init()
|
||||
|
||||
@@ -44,12 +44,30 @@ export interface DOMWidget<T extends HTMLElement, V extends object | string>
|
||||
inputEl?: T
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional props that can be passed to component widgets.
|
||||
* These are in addition to the standard props that are always provided:
|
||||
* - modelValue: The widget's value (handled by v-model)
|
||||
* - widget: Reference to the widget instance
|
||||
* - onUpdate:modelValue: The update handler for v-model
|
||||
*/
|
||||
export type ComponentWidgetCustomProps = Record<string, unknown>
|
||||
|
||||
/**
|
||||
* Standard props that are handled separately by DomWidget.vue and should be
|
||||
* omitted when defining custom props for component widgets
|
||||
*/
|
||||
export type ComponentWidgetStandardProps =
|
||||
| 'modelValue'
|
||||
| 'widget'
|
||||
| 'onUpdate:modelValue'
|
||||
|
||||
/**
|
||||
* A DOM widget that wraps a Vue component as a litegraph widget.
|
||||
*/
|
||||
export interface ComponentWidget<
|
||||
V extends object | string,
|
||||
P = Record<string, unknown>
|
||||
P extends ComponentWidgetCustomProps = ComponentWidgetCustomProps
|
||||
> extends BaseDOMWidget<V> {
|
||||
readonly component: Component
|
||||
readonly inputSpec: InputSpec
|
||||
@@ -247,7 +265,7 @@ export class DOMWidgetImpl<T extends HTMLElement, V extends object | string>
|
||||
|
||||
export class ComponentWidgetImpl<
|
||||
V extends object | string,
|
||||
P = Record<string, unknown>
|
||||
P extends ComponentWidgetCustomProps = ComponentWidgetCustomProps
|
||||
>
|
||||
extends BaseDOMWidgetImpl<V>
|
||||
implements ComponentWidget<V, P>
|
||||
|
||||
Reference in New Issue
Block a user