Fix promoted assets not being assets in vue (#7576)

- Fixes asset widgets which have been promoted failing to display as
asset widgets and having red names in vue mode.
- Fixes promoted subgraph widgets failing to resolve inputSpec for use
in vue mode.

| Before | After |
| ------ | ----- |
| <img width="360" alt="before"
src="https://github.com/user-attachments/assets/6c2d2763-6ac3-4769-82c5-b1ab1cc5e945"/>
| <img width="360" alt="after"
src="https://github.com/user-attachments/assets/742e218b-ec42-411a-b5a2-021820031e2a"
/>|

I'm not excited that this creates further bloat of SimplifiedWidget.

Known issue
- Similar to #7550, subgraph widgets will have an incorrect callback and
will fail to update value on a fresh reload. This can be "fixed" (made
worse) by entering and exiting the subgraph. Since this creates a
'leaked' widget callback which will then be called.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7576-Fix-promoted-assets-not-being-assets-in-vue-2cc6d73d3650814b8734f69b225b0228)
by [Unito](https://www.unito.io)
This commit is contained in:
AustinMroz
2025-12-17 18:48:32 -08:00
committed by GitHub
parent fba580dc7d
commit 6396eb6fa3
5 changed files with 44 additions and 20 deletions

View File

@@ -6,6 +6,7 @@ import { reactiveComputed } from '@vueuse/core'
import { reactive, shallowReactive } from 'vue'
import { useChainCallback } from '@/composables/functional/useChainCallback'
import { isProxyWidget } from '@/core/graph/subgraph/proxyWidget'
import type {
INodeInputSlot,
INodeOutputSlot
@@ -42,14 +43,15 @@ export interface SafeWidgetData {
name: string
type: string
value: WidgetValue
label?: string
options?: IWidgetOptions<unknown>
borderStyle?: string
callback?: ((value: unknown) => void) | undefined
controlWidget?: SafeControlWidget
isDOMWidget?: boolean
label?: string
nodeType?: string
options?: IWidgetOptions<unknown>
spec?: InputSpec
slotMetadata?: WidgetSlotMetadata
isDOMWidget?: boolean
controlWidget?: SafeControlWidget
borderStyle?: string
}
export interface VueNodeData {
@@ -96,6 +98,11 @@ function getControlWidget(widget: IBaseWidget): SafeControlWidget | undefined {
update: (value) => (cagWidget.value = normalizeControlOption(value))
}
}
function getNodeType(node: LGraphNode, widget: IBaseWidget) {
if (!node.isSubgraphNode() || !isProxyWidget(widget)) return undefined
const subNode = node.subgraph.getNodeById(widget._overlay.nodeId)
return subNode?.type
}
export function safeWidgetMapper(
node: LGraphNode,
@@ -131,12 +138,13 @@ export function safeWidgetMapper(
value: value,
borderStyle,
callback: widget.callback,
controlWidget: getControlWidget(widget),
isDOMWidget: isDOMWidget(widget),
label: widget.label,
nodeType: getNodeType(node, widget),
options: widget.options,
spec,
slotMetadata: slotInfo,
controlWidget: getControlWidget(widget)
slotMetadata: slotInfo
}
} catch (error) {
return {

View File

@@ -168,12 +168,13 @@ const processedWidgets = computed((): ProcessedWidget[] => {
name: widget.name,
type: widget.type,
value: widget.value,
label: widget.label,
options: widgetOptions,
callback: widget.callback,
spec: widget.spec,
borderStyle: widget.borderStyle,
controlWidget: widget.controlWidget
callback: widget.callback,
controlWidget: widget.controlWidget,
label: widget.label,
nodeType: widget.nodeType,
options: widgetOptions,
spec: widget.spec
}
function updateHandler(value: WidgetValue) {

View File

@@ -1,8 +1,9 @@
<template>
<WidgetSelectDropdown
v-if="isDropdownUIWidget"
v-bind="props"
v-model="modelValue"
:widget
:node-type="widget.nodeType ?? nodeType"
:asset-kind="assetKind"
:allow-upload="allowUpload"
:upload-folder="uploadFolder"
@@ -100,10 +101,9 @@ const isAssetMode = computed(() => {
if (isCloud) {
const settingStore = useSettingStore()
const isUsingAssetAPI = settingStore.get('Comfy.Assets.UseAssetAPI')
const isEligible = assetService.isAssetBrowserEligible(
props.nodeType,
props.widget.name
)
const isEligible =
assetService.isAssetBrowserEligible(props.nodeType, props.widget.name) ||
props.widget.type === 'asset'
return isUsingAssetAPI && isEligible
}

View File

@@ -3,6 +3,7 @@ import _ from 'es-toolkit/compat'
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'
import { isProxyWidget } from '@/core/graph/subgraph/proxyWidget'
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
import { transformNodeDefV1ToV2 } from '@/schemas/nodeDef/migration'
import type {
@@ -358,10 +359,21 @@ export const useNodeDefStore = defineStore('nodeDef', () => {
node: LGraphNode,
widgetName: string
): InputSpecV2 | undefined {
const nodeDef = fromLGraphNode(node)
if (!nodeDef) return undefined
if (!node.isSubgraphNode()) {
const nodeDef = fromLGraphNode(node)
if (!nodeDef) return undefined
return nodeDef.inputs[widgetName]
return nodeDef.inputs[widgetName]
}
const widget = node.widgets?.find((w) => w.name === widgetName)
//TODO: resolve spec for linked
if (!widget || !isProxyWidget(widget)) return undefined
const { nodeId, widgetName: subWidgetName } = widget._overlay
const subNode = node.subgraph.getNodeById(nodeId)
if (!subNode) return undefined
return getInputSpecForWidget(subNode, subWidgetName)
}
/**

View File

@@ -64,6 +64,9 @@ export interface SimplifiedWidget<
/** Widget options including filtered PrimeVue props */
options?: O
/** Override for use with subgraph promoted asset widgets*/
nodeType?: string
/** Optional serialization method for custom value handling */
serializeValue?: () => any