From e9db30bfd388745f4bd891dae21259ca1d57f574 Mon Sep 17 00:00:00 2001 From: DrJKL Date: Wed, 13 May 2026 15:58:02 -0700 Subject: [PATCH] fix(subgraphEditor): exclude promoted widgets from candidate list The candidate filter compared `toKey()` outputs across the active section (PromotedWidgetView, key includes `:sourceNodeId` suffix) and the interior section (raw widget, no suffix). The shapes never matched, so every link-promoted widget kept showing in the Hidden section as `icon-eye/eye-off`. Compare on the interior `(node.id, widget.name)` identity instead. Update the Properties panel test to demote a link-promoted widget via the source-node context menu (since linked promotions render `icon-link` and disable the editor toggle by design). Amp-Thread-ID: https://ampcode.com/threads/T-019e2260-c2ba-70b4-9962-1638be4bf645 Co-authored-by: Amp --- .../tests/subgraph/subgraphPromotion.spec.ts | 11 ++++++----- .../rightSidePanel/subgraph/SubgraphEditor.vue | 11 +++++++++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/browser_tests/tests/subgraph/subgraphPromotion.spec.ts b/browser_tests/tests/subgraph/subgraphPromotion.spec.ts index f4f271f17a..1e9c8ba21f 100644 --- a/browser_tests/tests/subgraph/subgraphPromotion.spec.ts +++ b/browser_tests/tests/subgraph/subgraphPromotion.spec.ts @@ -667,11 +667,12 @@ test('Properties panel operations @vue-nodes', async ({ comfyPage }) => { ) }) - await editor.togglePromotion(subgraphNode, { - nodeName: 'KSampler', - widgetName: 'steps', - toState: false - }) + // Link-promoted widgets render `icon-link` (disabled toggle) in the editor; + // demotion happens via the source-node context menu inside the subgraph. + await comfyPage.vueNodes.enterSubgraph('2') + const ksampler = await comfyPage.vueNodes.getFixtureByTitle('KSampler') + await comfyPage.subgraph.unpromoteWidget(ksampler.root, 'steps') + await comfyPage.subgraph.exitViaBreadcrumb() await expect(steps, 'Un-promote widget').toBeHidden() }) diff --git a/src/components/rightSidePanel/subgraph/SubgraphEditor.vue b/src/components/rightSidePanel/subgraph/SubgraphEditor.vue index f7f0211e40..197ccbba7d 100644 --- a/src/components/rightSidePanel/subgraph/SubgraphEditor.vue +++ b/src/components/rightSidePanel/subgraph/SubgraphEditor.vue @@ -127,9 +127,16 @@ const interiorWidgets = computed(() => { const candidateWidgets = computed(() => { const node = activeNode.value if (!node) return [] + // An interior widget is "already promoted" iff some active row's source + // identity matches it. PromotedWidgetView carries `sourceNodeId`; preview + // exposures are stored as the interior `[node, widget]` tuple directly. + const promotedSourceKeys = new Set( + activeWidgets.value.map( + ([n, w]) => `${getSourceNodeId(w) ?? String(n.id)}:${getWidgetName(w)}` + ) + ) return interiorWidgets.value.filter( - (item: WidgetItem) => - !activeWidgets.value.some((active) => toKey(active) === toKey(item)) + ([n, w]) => !promotedSourceKeys.has(`${n.id}:${w.name}`) ) }) const filteredCandidates = computed(() => {