diff --git a/src/renderer/extensions/vueNodes/components/LGraphNodePreview.test.ts b/src/renderer/extensions/vueNodes/components/LGraphNodePreview.test.ts index b75560e871..ce9b449fa1 100644 --- a/src/renderer/extensions/vueNodes/components/LGraphNodePreview.test.ts +++ b/src/renderer/extensions/vueNodes/components/LGraphNodePreview.test.ts @@ -3,9 +3,8 @@ import { render, screen } from '@testing-library/vue' import { computed } from 'vue' import { describe, expect, it, vi } from 'vitest' +import type { ProcessedWidget } from '@/renderer/extensions/vueNodes/composables/useProcessedWidgets' import type { ComfyNodeDef as ComfyNodeDefV2 } from '@/schemas/nodeDef/nodeDefSchemaV2' -import { useWidgetValueStore } from '@/stores/widgetValueStore' -import type { WidgetId } from '@/types/widgetId' import LGraphNodePreview from '@/renderer/extensions/vueNodes/components/LGraphNodePreview.vue' import { fromPartial } from '@total-typescript/shoehorn' @@ -13,12 +12,15 @@ vi.mock('@/stores/widgetStore', () => ({ useWidgetStore: () => ({ inputIsWidget: () => true }) })) -const NodeWidgetsProbe = { - props: ['widgetIds'], - setup(props: { widgetIds?: readonly WidgetId[] }) { - const widgetValueStore = useWidgetValueStore() +const WidgetGridProbe = { + props: ['processedWidgets'], + setup(props: { processedWidgets?: ProcessedWidget[] }) { const widgets = computed(() => - (props.widgetIds ?? []).map((id) => widgetValueStore.getWidget(id)) + (props.processedWidgets ?? []).map((widget) => ({ + name: widget.name, + value: widget.simplified.value, + options: { values: widget.simplified.options?.values } + })) ) return { widgets } }, @@ -52,7 +54,7 @@ function renderedWidgets( stubs: { NodeHeader: true, NodeSlots: true, - NodeWidgets: NodeWidgetsProbe + WidgetGrid: WidgetGridProbe } } }) diff --git a/src/renderer/extensions/vueNodes/components/LGraphNodePreview.vue b/src/renderer/extensions/vueNodes/components/LGraphNodePreview.vue index 2722938298..2b37dd5d4e 100644 --- a/src/renderer/extensions/vueNodes/components/LGraphNodePreview.vue +++ b/src/renderer/extensions/vueNodes/components/LGraphNodePreview.vue @@ -19,10 +19,12 @@ > - @@ -30,7 +32,7 @@ diff --git a/src/renderer/extensions/vueNodes/components/NodeWidgets.vue b/src/renderer/extensions/vueNodes/components/NodeWidgets.vue index 617a156f54..bcfa63ecfc 100644 --- a/src/renderer/extensions/vueNodes/components/NodeWidgets.vue +++ b/src/renderer/extensions/vueNodes/components/NodeWidgets.vue @@ -2,82 +2,23 @@
{{ st('nodeErrors.widgets', 'Node Widgets Error') }}
-
- -
+ /> diff --git a/src/renderer/extensions/vueNodes/composables/usePreviewWidgets.ts b/src/renderer/extensions/vueNodes/composables/usePreviewWidgets.ts new file mode 100644 index 0000000000..597d74a503 --- /dev/null +++ b/src/renderer/extensions/vueNodes/composables/usePreviewWidgets.ts @@ -0,0 +1,92 @@ +import type { TooltipOptions } from 'primevue' +import { computed } from 'vue' +import type { Component } from 'vue' + +import type { IWidgetOptions } from '@/lib/litegraph/src/types/widgets' +import { useSettingStore } from '@/platform/settings/settingStore' +import type { ProcessedWidget } from '@/renderer/extensions/vueNodes/composables/useProcessedWidgets' +import { isWidgetVisible } from '@/renderer/extensions/vueNodes/composables/useProcessedWidgets' +import WidgetLegacy from '@/renderer/extensions/vueNodes/widgets/components/WidgetLegacy.vue' +import { + getComponent, + shouldExpand +} from '@/renderer/extensions/vueNodes/widgets/registry/widgetRegistry' +import type { ComfyNodeDef as ComfyNodeDefV2 } from '@/schemas/nodeDef/nodeDefSchemaV2' +import { useWidgetStore } from '@/stores/widgetStore' +import type { WidgetValue } from '@/types/simplifiedWidget' + +const EMPTY_TOOLTIP: TooltipOptions = {} +const noop = () => {} + +/** + * Builds render-ready widgets for a static node preview straight from its + * schema, without registering anything in the widget stores. Previews have no + * live graph, so nothing here needs (or should touch) store-backed state. + */ +export function usePreviewWidgets( + nodeDefGetter: () => ComfyNodeDefV2, + widgetValuesGetter: () => Record | undefined +) { + const widgetStore = useWidgetStore() + const settingStore = useSettingStore() + const showAdvanced = computed(() => + Boolean(settingStore.get('Comfy.Node.AlwaysShowAdvancedWidgets')) + ) + + const processedWidgets = computed(() => { + const nodeDef = nodeDefGetter() + const widgetValues = widgetValuesGetter() + return Object.entries(nodeDef.inputs || {}) + .filter(([, input]) => widgetStore.inputIsWidget(input)) + .map(([name, input]): ProcessedWidget => { + const comboValues = + input.type === 'COMBO' && Array.isArray(input.options) + ? input.options + : undefined + const leadValue = widgetValues?.[name] + const value = (leadValue ?? + (input.default !== undefined + ? input.default + : (comboValues?.[0] ?? ''))) as WidgetValue + const options = { + hidden: input.hidden, + advanced: input.advanced, + values: + leadValue && comboValues + ? [ + leadValue, + ...comboValues.filter((option) => option !== leadValue) + ] + : comboValues + } satisfies IWidgetOptions + const type = input.widgetType || input.type + const vueComponent: Component = getComponent(type) ?? WidgetLegacy + return { + advanced: Boolean(input.advanced), + handleContextMenu: noop, + hasLayoutSize: false, + hasError: false, + hidden: Boolean(input.hidden), + name, + renderKey: `preview:${nodeDef.name}:${name}`, + simplified: { name, type, value, options, spec: input }, + tooltipConfig: EMPTY_TOOLTIP, + type, + updateHandler: noop, + value, + visible: isWidgetVisible(options, showAdvanced.value), + vueComponent, + slotMetadata: undefined + } + }) + }) + + const gridTemplateRows = computed(() => + processedWidgets.value + .filter((widget) => widget.visible) + .map((widget) => (shouldExpand(widget.type) ? 'auto' : 'min-content')) + .join(' ') + ) + + return { processedWidgets, gridTemplateRows } +} diff --git a/src/renderer/extensions/vueNodes/composables/useProcessedWidgets.ts b/src/renderer/extensions/vueNodes/composables/useProcessedWidgets.ts index 514fb2a437..29c74a079d 100644 --- a/src/renderer/extensions/vueNodes/composables/useProcessedWidgets.ts +++ b/src/renderer/extensions/vueNodes/composables/useProcessedWidgets.ts @@ -60,7 +60,7 @@ function isTooltipValueType(val: unknown): val is TooltipValueType { return TOOLTIP_VALUE_TYPES.includes(val as TooltipValueType) } -interface WidgetSlotMetadata { +export interface WidgetSlotMetadata { index: number linked: boolean originNodeId?: NodeId @@ -78,7 +78,7 @@ interface WidgetErrorTarget { widgetName: string } -interface ProcessedWidget { +export interface ProcessedWidget { advanced: boolean handleContextMenu: (e: PointerEvent) => void hasLayoutSize: boolean