diff --git a/browser_tests/tests/nodeDisplay.spec.ts-snapshots/missing-nodes-converted-widget-chromium-linux.png b/browser_tests/tests/nodeDisplay.spec.ts-snapshots/missing-nodes-converted-widget-chromium-linux.png index 6dbe387ee2..0d1fbdae51 100644 Binary files a/browser_tests/tests/nodeDisplay.spec.ts-snapshots/missing-nodes-converted-widget-chromium-linux.png and b/browser_tests/tests/nodeDisplay.spec.ts-snapshots/missing-nodes-converted-widget-chromium-linux.png differ diff --git a/src/composables/functional/useChainCallback.ts b/src/composables/functional/useChainCallback.ts index 266e0a9520..3d631b9167 100644 --- a/src/composables/functional/useChainCallback.ts +++ b/src/composables/functional/useChainCallback.ts @@ -5,11 +5,14 @@ * @param callbacks - The callbacks to chain. * @returns A new callback that chains the original callback with the callbacks. */ -export const useChainCallback = void>( +export const useChainCallback = < + O, + T extends (this: O, ...args: any[]) => void +>( originalCallback: T | undefined, - ...callbacks: ((...args: Parameters) => void)[] + ...callbacks: ((this: O, ...args: Parameters) => void)[] ) => { - return function (this: unknown, ...args: Parameters) { + return function (this: O, ...args: Parameters) { originalCallback?.call(this, ...args) callbacks.forEach((callback) => callback.call(this, ...args)) } diff --git a/src/scripts/errorNodeWidgets.ts b/src/scripts/errorNodeWidgets.ts new file mode 100644 index 0000000000..2e4d2457f4 --- /dev/null +++ b/src/scripts/errorNodeWidgets.ts @@ -0,0 +1,60 @@ +import { IWidget, LGraphNode } from '@comfyorg/litegraph' + +import { useChainCallback } from '@/composables/functional/useChainCallback' +import { useBooleanWidget } from '@/composables/widgets/useBooleanWidget' +import { useFloatWidget } from '@/composables/widgets/useFloatWidget' +import { useStringWidget } from '@/composables/widgets/useStringWidget' + +const StringWidget = useStringWidget() +const FloatWidget = useFloatWidget() +const BooleanWidget = useBooleanWidget() + +function addWidgetFromValue(node: LGraphNode, value: unknown) { + let widget: IWidget + + if (typeof value === 'string') { + widget = StringWidget(node, { + type: 'STRING', + name: 'UNKNOWN', + multiline: value.length > 20 + }) + } else if (typeof value === 'number') { + widget = FloatWidget(node, { + type: 'FLOAT', + name: 'UNKNOWN' + }) + } else if (typeof value === 'boolean') { + widget = BooleanWidget(node, { + type: 'BOOLEAN', + name: 'UNKNOWN' + }) + } else { + console.warn(`Unknown value type: ${typeof value}`) + return + } + + widget.value = value +} + +/** + * Try add widgets to node with missing definition. + */ +LGraphNode.prototype.onConfigure = useChainCallback( + LGraphNode.prototype.onConfigure, + function (this: LGraphNode, info) { + if (!this.has_errors || !info.widgets_values) return + + /** + * Note: Some custom nodes overrides the `widgets_values` property to an + * object that has `length` property and index access. It is not safe to call + * any array methods on it. + * See example in https://github.com/Kosinkadink/ComfyUI-VideoHelperSuite/blob/8629188458dc6cb832f871ece3bd273507e8a766/web/js/VHS.core.js#L59-L84 + */ + for (let i = 0; i < info.widgets_values.length; i++) { + const widgetValue = info.widgets_values[i] + addWidgetFromValue(this, widgetValue) + } + + this.serialize_widgets = true + } +) diff --git a/src/scripts/widgets.ts b/src/scripts/widgets.ts index a9a56a8a70..50831164d4 100644 --- a/src/scripts/widgets.ts +++ b/src/scripts/widgets.ts @@ -20,6 +20,7 @@ import { useSettingStore } from '@/stores/settingStore' import type { ComfyApp } from './app' import './domWidget' +import './errorNodeWidgets' export type ComfyWidgetConstructorV2 = ( node: LGraphNode,