mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-14 01:20:03 +00:00
Always use interior nodeId for app mode (#9669)
App mode stores the state of selected widgets as a tuple of `[NodeId, WidgetName]`. With recent subgraph changes, for a given node, `widget.name` will no longer uniquely resolve to a single widget. - From both Vue and Litegraph, selecting an input for display in App mode will now resolve the NodeId of the node which owns the widget instead of the selected node. - When displaying selections in litegraph, if the NodeId does not exist in the current graph, instead of resolving the actual node the rootGraph is searched for any subgraphNode which contains a view matching the `[NodeId, WidgetName]` pair. - When displaying widgets in App mode, the widget is always set as being a view of the real widget (This means that they will not display a purple promotion border. Known Issue: - These same subgraph changes made it so that a widget can be linked without being disabled. This PR makes it so widgets which have been linked instead display normally under the assumption that they are incorrectly marked as disabled. As disabled widgets can not be selected as inputs, this should handle normal usage fine, but a better solution is being investigated ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9669-Always-use-interior-nodeId-for-app-mode-31e6d73d365081f8a918d0e43cb659ee) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -8,6 +8,7 @@ import DraggableList from '@/components/common/DraggableList.vue'
|
||||
import IoItem from '@/components/builder/IoItem.vue'
|
||||
import PropertiesAccordionItem from '@/components/rightSidePanel/layout/PropertiesAccordionItem.vue'
|
||||
import WidgetItem from '@/components/rightSidePanel/parameters/WidgetItem.vue'
|
||||
import { isPromotedWidgetView } from '@/core/graph/subgraph/promotedWidgetTypes'
|
||||
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
|
||||
import type { LGraphNode, NodeId } from '@/lib/litegraph/src/LGraphNode'
|
||||
import type { LGraphCanvas } from '@/lib/litegraph/src/LGraphCanvas'
|
||||
@@ -27,7 +28,6 @@ import { DOMWidgetImpl } from '@/scripts/domWidget'
|
||||
import { promptRenameWidget } from '@/utils/widgetUtil'
|
||||
import { useAppMode } from '@/composables/useAppMode'
|
||||
import { nodeTypeValidForApp, useAppModeStore } from '@/stores/appModeStore'
|
||||
import { resolveNode } from '@/utils/litegraphUtil'
|
||||
import { cn } from '@/utils/tailwindUtil'
|
||||
import { HideLayoutFieldKey } from '@/types/widgetTypes'
|
||||
|
||||
@@ -52,18 +52,15 @@ workflowStore.activeWorkflow?.changeTracker?.reset()
|
||||
const arrangeInputs = computed(() =>
|
||||
appModeStore.selectedInputs
|
||||
.map(([nodeId, widgetName]) => {
|
||||
const node = resolveNode(nodeId)
|
||||
if (!node) return null
|
||||
const widget = node.widgets?.find((w) => w.name === widgetName)
|
||||
return { nodeId, widgetName, node, widget }
|
||||
const [node, widget] = resolveNodeWidget(nodeId, widgetName)
|
||||
return node ? { nodeId, widgetName, node, widget } : null
|
||||
})
|
||||
.filter((item): item is NonNullable<typeof item> => item !== null)
|
||||
)
|
||||
|
||||
const inputsWithState = computed(() =>
|
||||
appModeStore.selectedInputs.map(([nodeId, widgetName]) => {
|
||||
const node = resolveNode(nodeId)
|
||||
const widget = node?.widgets?.find((w) => w.name === widgetName)
|
||||
const [node, widget] = resolveNodeWidget(nodeId, widgetName)
|
||||
if (!node || !widget) {
|
||||
return {
|
||||
nodeId,
|
||||
@@ -105,10 +102,34 @@ function getHovered(
|
||||
|
||||
if (widget || node.constructor.nodeData?.output_node) return [node, widget]
|
||||
}
|
||||
function resolveNodeWidget(
|
||||
nodeId: NodeId,
|
||||
widgetName?: string
|
||||
): [LGraphNode, IBaseWidget] | [LGraphNode] | [] {
|
||||
const node = app.graph.getNodeById(nodeId)
|
||||
if (!widgetName) return node ? [node] : []
|
||||
if (node) {
|
||||
const widget = node.widgets?.find((w) => w.name === widgetName)
|
||||
return widget ? [node, widget] : []
|
||||
}
|
||||
|
||||
for (const node of app.graph.nodes) {
|
||||
if (!node.isSubgraphNode()) continue
|
||||
const widget = node.widgets?.find(
|
||||
(w) =>
|
||||
isPromotedWidgetView(w) &&
|
||||
w.sourceWidgetName === widgetName &&
|
||||
w.sourceNodeId === nodeId
|
||||
)
|
||||
if (widget) return [node, widget]
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
function getBounding(nodeId: NodeId, widgetName?: string) {
|
||||
if (settingStore.get('Comfy.VueNodes.Enabled')) return undefined
|
||||
const node = app.rootGraph.getNodeById(nodeId)
|
||||
const [node, widget] = resolveNodeWidget(nodeId, widgetName)
|
||||
if (!node) return
|
||||
|
||||
const titleOffset =
|
||||
@@ -121,7 +142,6 @@ function getBounding(nodeId: NodeId, widgetName?: string) {
|
||||
left: `${node.pos[0]}px`,
|
||||
top: `${node.pos[1] - titleOffset}px`
|
||||
}
|
||||
const widget = node.widgets?.find((w) => w.name === widgetName)
|
||||
if (!widget) return
|
||||
|
||||
const margin = widget instanceof DOMWidgetImpl ? widget.margin : undefined
|
||||
@@ -162,10 +182,14 @@ function handleClick(e: MouseEvent) {
|
||||
}
|
||||
if (!isSelectInputsMode.value || widget.options.canvasOnly) return
|
||||
|
||||
const storeId = isPromotedWidgetView(widget) ? widget.sourceNodeId : node.id
|
||||
const storeName = isPromotedWidgetView(widget)
|
||||
? widget.sourceWidgetName
|
||||
: widget.name
|
||||
const index = appModeStore.selectedInputs.findIndex(
|
||||
([nodeId, widgetName]) => node.id == nodeId && widget.name === widgetName
|
||||
([nodeId, widgetName]) => storeId == nodeId && storeName === widgetName
|
||||
)
|
||||
if (index === -1) appModeStore.selectedInputs.push([node.id, widget.name])
|
||||
if (index === -1) appModeStore.selectedInputs.push([storeId, storeName])
|
||||
else appModeStore.selectedInputs.splice(index, 1)
|
||||
}
|
||||
|
||||
|
||||
@@ -107,8 +107,10 @@ function getDropIndicator(node: LGraphNode) {
|
||||
function nodeToNodeData(node: LGraphNode) {
|
||||
const dropIndicator = getDropIndicator(node)
|
||||
const nodeData = extractVueNodeData(node)
|
||||
remove(nodeData.widgets ?? [], (w) => w.slotMetadata?.linked ?? false)
|
||||
for (const widget of nodeData.widgets ?? []) widget.slotMetadata = undefined
|
||||
for (const widget of nodeData.widgets ?? []) {
|
||||
widget.slotMetadata = undefined
|
||||
widget.nodeId = String(node.id)
|
||||
}
|
||||
|
||||
return {
|
||||
...nodeData,
|
||||
|
||||
Reference in New Issue
Block a user