mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-26 01:09:46 +00:00
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:
@@ -6,6 +6,7 @@ import { reactiveComputed } from '@vueuse/core'
|
|||||||
import { reactive, shallowReactive } from 'vue'
|
import { reactive, shallowReactive } from 'vue'
|
||||||
|
|
||||||
import { useChainCallback } from '@/composables/functional/useChainCallback'
|
import { useChainCallback } from '@/composables/functional/useChainCallback'
|
||||||
|
import { isProxyWidget } from '@/core/graph/subgraph/proxyWidget'
|
||||||
import type {
|
import type {
|
||||||
INodeInputSlot,
|
INodeInputSlot,
|
||||||
INodeOutputSlot
|
INodeOutputSlot
|
||||||
@@ -42,14 +43,15 @@ export interface SafeWidgetData {
|
|||||||
name: string
|
name: string
|
||||||
type: string
|
type: string
|
||||||
value: WidgetValue
|
value: WidgetValue
|
||||||
label?: string
|
borderStyle?: string
|
||||||
options?: IWidgetOptions<unknown>
|
|
||||||
callback?: ((value: unknown) => void) | undefined
|
callback?: ((value: unknown) => void) | undefined
|
||||||
|
controlWidget?: SafeControlWidget
|
||||||
|
isDOMWidget?: boolean
|
||||||
|
label?: string
|
||||||
|
nodeType?: string
|
||||||
|
options?: IWidgetOptions<unknown>
|
||||||
spec?: InputSpec
|
spec?: InputSpec
|
||||||
slotMetadata?: WidgetSlotMetadata
|
slotMetadata?: WidgetSlotMetadata
|
||||||
isDOMWidget?: boolean
|
|
||||||
controlWidget?: SafeControlWidget
|
|
||||||
borderStyle?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VueNodeData {
|
export interface VueNodeData {
|
||||||
@@ -96,6 +98,11 @@ function getControlWidget(widget: IBaseWidget): SafeControlWidget | undefined {
|
|||||||
update: (value) => (cagWidget.value = normalizeControlOption(value))
|
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(
|
export function safeWidgetMapper(
|
||||||
node: LGraphNode,
|
node: LGraphNode,
|
||||||
@@ -131,12 +138,13 @@ export function safeWidgetMapper(
|
|||||||
value: value,
|
value: value,
|
||||||
borderStyle,
|
borderStyle,
|
||||||
callback: widget.callback,
|
callback: widget.callback,
|
||||||
|
controlWidget: getControlWidget(widget),
|
||||||
isDOMWidget: isDOMWidget(widget),
|
isDOMWidget: isDOMWidget(widget),
|
||||||
label: widget.label,
|
label: widget.label,
|
||||||
|
nodeType: getNodeType(node, widget),
|
||||||
options: widget.options,
|
options: widget.options,
|
||||||
spec,
|
spec,
|
||||||
slotMetadata: slotInfo,
|
slotMetadata: slotInfo
|
||||||
controlWidget: getControlWidget(widget)
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -168,12 +168,13 @@ const processedWidgets = computed((): ProcessedWidget[] => {
|
|||||||
name: widget.name,
|
name: widget.name,
|
||||||
type: widget.type,
|
type: widget.type,
|
||||||
value: widget.value,
|
value: widget.value,
|
||||||
label: widget.label,
|
|
||||||
options: widgetOptions,
|
|
||||||
callback: widget.callback,
|
|
||||||
spec: widget.spec,
|
|
||||||
borderStyle: widget.borderStyle,
|
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) {
|
function updateHandler(value: WidgetValue) {
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<WidgetSelectDropdown
|
<WidgetSelectDropdown
|
||||||
v-if="isDropdownUIWidget"
|
v-if="isDropdownUIWidget"
|
||||||
v-bind="props"
|
|
||||||
v-model="modelValue"
|
v-model="modelValue"
|
||||||
|
:widget
|
||||||
|
:node-type="widget.nodeType ?? nodeType"
|
||||||
:asset-kind="assetKind"
|
:asset-kind="assetKind"
|
||||||
:allow-upload="allowUpload"
|
:allow-upload="allowUpload"
|
||||||
:upload-folder="uploadFolder"
|
:upload-folder="uploadFolder"
|
||||||
@@ -100,10 +101,9 @@ const isAssetMode = computed(() => {
|
|||||||
if (isCloud) {
|
if (isCloud) {
|
||||||
const settingStore = useSettingStore()
|
const settingStore = useSettingStore()
|
||||||
const isUsingAssetAPI = settingStore.get('Comfy.Assets.UseAssetAPI')
|
const isUsingAssetAPI = settingStore.get('Comfy.Assets.UseAssetAPI')
|
||||||
const isEligible = assetService.isAssetBrowserEligible(
|
const isEligible =
|
||||||
props.nodeType,
|
assetService.isAssetBrowserEligible(props.nodeType, props.widget.name) ||
|
||||||
props.widget.name
|
props.widget.type === 'asset'
|
||||||
)
|
|
||||||
|
|
||||||
return isUsingAssetAPI && isEligible
|
return isUsingAssetAPI && isEligible
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import _ from 'es-toolkit/compat'
|
|||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
|
|
||||||
|
import { isProxyWidget } from '@/core/graph/subgraph/proxyWidget'
|
||||||
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||||
import { transformNodeDefV1ToV2 } from '@/schemas/nodeDef/migration'
|
import { transformNodeDefV1ToV2 } from '@/schemas/nodeDef/migration'
|
||||||
import type {
|
import type {
|
||||||
@@ -358,10 +359,21 @@ export const useNodeDefStore = defineStore('nodeDef', () => {
|
|||||||
node: LGraphNode,
|
node: LGraphNode,
|
||||||
widgetName: string
|
widgetName: string
|
||||||
): InputSpecV2 | undefined {
|
): InputSpecV2 | undefined {
|
||||||
const nodeDef = fromLGraphNode(node)
|
if (!node.isSubgraphNode()) {
|
||||||
if (!nodeDef) return undefined
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -64,6 +64,9 @@ export interface SimplifiedWidget<
|
|||||||
/** Widget options including filtered PrimeVue props */
|
/** Widget options including filtered PrimeVue props */
|
||||||
options?: O
|
options?: O
|
||||||
|
|
||||||
|
/** Override for use with subgraph promoted asset widgets*/
|
||||||
|
nodeType?: string
|
||||||
|
|
||||||
/** Optional serialization method for custom value handling */
|
/** Optional serialization method for custom value handling */
|
||||||
serializeValue?: () => any
|
serializeValue?: () => any
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user