Compare commits

...

3 Commits

Author SHA1 Message Date
Austin Mroz
4f60b46b22 Remove price arg
I have now had three different nits on code that does nothing and
physically can not run because the node is not an output node and has no
outputs. The price arg is removed. Changing it combo is both wrong, and
introduces an unused variable.
2026-06-24 10:30:39 -07:00
Austin Mroz
a0a281056f Add test 2026-06-22 21:39:28 -07:00
Austin Mroz
a8f6fcac51 Ensure dynamic combo children cleanup state 2026-06-22 20:48:21 -07:00
3 changed files with 43 additions and 1 deletions

View File

@@ -73,4 +73,16 @@ test.describe('Vue Widget Reactivity', { tag: '@vue-nodes' }, () => {
await expect(widget, 'Widget has restored value').toHaveText('scale width')
})
test('Dynamic children have separate state', async ({ comfyPage }) => {
const nodeName = 'Node With Dynamic Combo'
await comfyPage.searchBoxV2.addNode(nodeName, {
position: { x: 200, y: 150 }
})
const child = comfyPage.vueNodes.getWidgetByName(nodeName, 'suboption')
await expect(child, 'initial state').toHaveText('1x')
await comfyPage.vueNodes.selectComboOption(nodeName, 'combo', 'option2')
await expect(child, 'child of same name has new state').toHaveText('2x')
})
})

View File

@@ -77,6 +77,7 @@ function dynamicComboWidget(
widgetName?: string
) {
const { addNodeInput } = useLitegraphService()
const { deleteWidget } = useWidgetValueStore()
const parseResult = zDynamicComboInputSpec.safeParse(untypedInputData)
if (!parseResult.success) throw new Error('invalid DynamicCombo spec')
const inputData = parseResult.data
@@ -99,7 +100,10 @@ function dynamicComboWidget(
const newSpec = value ? options[value] : undefined
const removedInputs = remove(node.inputs, isInGroup)
for (const widget of remove(node.widgets, isInGroup)) widget.onRemove?.()
for (const widget of remove(node.widgets, isInGroup)) {
widget.onRemove?.()
if (widget.widgetId) deleteWidget(widget.widgetId)
}
if (!newSpec) return

View File

@@ -343,6 +343,30 @@ class NodeWithPriceBadge(IO.ComfyNode):
async def execute(cls, price):
return IO.NodeOutput()
class NodeWithDynamicCombo(IO.ComfyNode):
@classmethod
def define_schema(cls):
return IO.Schema(
node_id="DevToolsNodeWithDynamicCombo",
display_name="Node With Dynamic Combo",
description="A node with a Dynamic combo",
inputs=[IO.DynamicCombo.Input("combo", options=[
IO.DynamicCombo.Option("option1", [IO.Combo.Input("suboption", options=["1x"])]),
IO.DynamicCombo.Option("option2", [IO.Combo.Input("suboption", options=["2x"])]),
IO.DynamicCombo.Option("option3", [IO.Image.Input("image")]),
IO.DynamicCombo.Option("option4", [
IO.DynamicCombo.Input("subcombo", options=[
IO.DynamicCombo.Option("opt1", [IO.Float.Input("float_x"), IO.Float.Input("float_y")]),
IO.DynamicCombo.Option("opt2", [IO.Mask.Input("mask1", optional=True)]),
])
])]
)],
)
@classmethod
async def execute(cls):
return IO.NodeOutput()
NODE_CLASS_MAPPINGS = {
"DevToolsLongComboDropdown": LongComboDropdown,
@@ -361,6 +385,7 @@ NODE_CLASS_MAPPINGS = {
"DevToolsNodeWithV2ComboInput": NodeWithV2ComboInput,
"DevToolsNodeWithLegacyWidget": NodeWithLegacyWidget,
"DevToolsNodeWithPriceBadge": NodeWithPriceBadge,
"DevToolsNodeWithDynamicCombo": NodeWithDynamicCombo,
}
NODE_DISPLAY_NAME_MAPPINGS = {
@@ -380,6 +405,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"DevToolsNodeWithV2ComboInput": "Node With V2 Combo Input",
"DevToolsNodeWithLegacyWidget": "Node With Legacy Widget",
"DevToolsNodeWithPriceBadge": "Node With Price Badge",
"DevToolsNodeWithDynamicCombo": "Node With Dynamic Combo",
}
__all__ = [