fix: prevent non-widget inputs on nested subgraphs from appearing as button widgets#9542
fix: prevent non-widget inputs on nested subgraphs from appearing as button widgets#9542
Conversation
…button widgets resolveSubgraphInputTarget unconditionally returned a promotion target for every input linked to a nested SubgraphNode, including non-widget inputs (e.g. AUDIO, IMAGE). This caused bogus PromotedWidgetView entries that failed to resolve (falling back to type 'button'), while the inputs also rendered as normal slot circles — appearing twice. Add getTargetWidget() guard in the isSubgraphNode() branch, matching the existing check for non-subgraph nodes. Amp-Thread-ID: https://ampcode.com/threads/T-019cca65-f6b1-71f4-b870-62056b704736 Co-authored-by: Amp <amp@ampcode.com>
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughA null-check guard was added to the subgraph node path in Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
🎨 Storybook: ✅ Built — View Storybook |
🎭 Playwright: ✅ 554 passed, 0 failed · 3 flaky📊 Browser Reports
|
📦 Bundle: 4.57 MB gzip 🔴 +15 BDetailsSummary
Category Glance App Entry Points — 28.9 kB (baseline 28.9 kB) • ⚪ 0 BMain entry bundles and manifests
Status: 1 added / 1 removed Graph Workspace — 954 kB (baseline 954 kB) • ⚪ 0 BGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed Views & Navigation — 72.4 kB (baseline 72.4 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 9 added / 9 removed Panels & Settings — 436 kB (baseline 436 kB) • ⚪ 0 BConfiguration panels, inspectors, and settings screens
Status: 10 added / 10 removed User & Accounts — 16.1 kB (baseline 16.1 kB) • ⚪ 0 BAuthentication, profile, and account management bundles
Status: 5 added / 5 removed Editors & Dialogs — 77.6 kB (baseline 77.6 kB) • ⚪ 0 BModals, dialogs, drawers, and in-app editors
Status: 2 added / 2 removed UI Components — 56.5 kB (baseline 56.5 kB) • ⚪ 0 BReusable component library chunks
Status: 5 added / 5 removed Data & Services — 2.77 MB (baseline 2.77 MB) • 🔴 +54 BStores, services, APIs, and repositories
Status: 14 added / 14 removed Utilities & Hooks — 56.8 kB (baseline 56.8 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 11 added / 11 removed Vendor & Third-Party — 8.87 MB (baseline 8.87 MB) • ⚪ 0 BExternal libraries and shared vendor chunks
Other — 8.04 MB (baseline 8.04 MB) • ⚪ 0 BBundles that do not match a named category
Status: 50 added / 50 removed |
Non-widget inputs on nested SubgraphNodes (e.g. AUDIO, IMAGE) must return undefined instead of a bogus promotion target. Amp-Thread-ID: https://ampcode.com/threads/T-019cca7b-9ba8-779c-ba40-9f2b45bed5e2 Co-authored-by: Amp <amp@ampcode.com>
⚡ Performance Report
Raw data{
"timestamp": "2026-03-07T22:57:06.290Z",
"gitSha": "e9720b0a056dba3ff754d615f8fdf5addc509589",
"branch": "drjkl/why-are-they-buttons",
"measurements": [
{
"name": "canvas-idle",
"durationMs": 2098.7799999999766,
"styleRecalcs": 127,
"styleRecalcDurationMs": 29.069,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 595.418,
"heapDeltaBytes": -4104356
},
{
"name": "canvas-idle",
"durationMs": 2016.5250000000015,
"styleRecalcs": 123,
"styleRecalcDurationMs": 28.958,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 507.91600000000005,
"heapDeltaBytes": -4311540
},
{
"name": "canvas-idle",
"durationMs": 2038.663999999983,
"styleRecalcs": 124,
"styleRecalcDurationMs": 28.484,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 512.919,
"heapDeltaBytes": -3579628
},
{
"name": "canvas-mouse-sweep",
"durationMs": 2059.1079999999806,
"styleRecalcs": 184,
"styleRecalcDurationMs": 57.70399999999999,
"layouts": 12,
"layoutDurationMs": 3.299,
"taskDurationMs": 1108.819,
"heapDeltaBytes": -2891976
},
{
"name": "canvas-mouse-sweep",
"durationMs": 2104.0079999999934,
"styleRecalcs": 189,
"styleRecalcDurationMs": 65.178,
"layouts": 13,
"layoutDurationMs": 3.9219999999999993,
"taskDurationMs": 1144.2540000000001,
"heapDeltaBytes": -2338156
},
{
"name": "canvas-mouse-sweep",
"durationMs": 1900.7309999999507,
"styleRecalcs": 174,
"styleRecalcDurationMs": 54.63999999999999,
"layouts": 12,
"layoutDurationMs": 3.5500000000000003,
"taskDurationMs": 886.257,
"heapDeltaBytes": -3136600
},
{
"name": "dom-widget-clipping",
"durationMs": 578.3869999999922,
"styleRecalcs": 42,
"styleRecalcDurationMs": 14.213000000000001,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 379.94199999999995,
"heapDeltaBytes": 6354300
},
{
"name": "dom-widget-clipping",
"durationMs": 631.2689999999748,
"styleRecalcs": 47,
"styleRecalcDurationMs": 18.246000000000002,
"layouts": 1,
"layoutDurationMs": 0.2900000000000001,
"taskDurationMs": 415.08399999999995,
"heapDeltaBytes": 8423624
},
{
"name": "dom-widget-clipping",
"durationMs": 588.3269999999925,
"styleRecalcs": 45,
"styleRecalcDurationMs": 18.636,
"layouts": 1,
"layoutDurationMs": 0.2819999999999999,
"taskDurationMs": 382.54900000000004,
"heapDeltaBytes": 7304584
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 642.7160000000072,
"styleRecalcs": 76,
"styleRecalcDurationMs": 16.669999999999998,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 439.56200000000007,
"heapDeltaBytes": 14639620
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 642.1230000000264,
"styleRecalcs": 75,
"styleRecalcDurationMs": 17.737999999999996,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 451.181,
"heapDeltaBytes": -8989208
},
{
"name": "subgraph-dom-widget-clipping",
"durationMs": 630.7940000000372,
"styleRecalcs": 75,
"styleRecalcDurationMs": 17.154,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 434.60200000000003,
"heapDeltaBytes": 15079820
},
{
"name": "subgraph-idle",
"durationMs": 2007.9510000000198,
"styleRecalcs": 123,
"styleRecalcDurationMs": 32.481,
"layouts": 1,
"layoutDurationMs": 0.289,
"taskDurationMs": 514.39,
"heapDeltaBytes": -2761872
},
{
"name": "subgraph-idle",
"durationMs": 2029.2420000000106,
"styleRecalcs": 123,
"styleRecalcDurationMs": 28.119999999999997,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 473.096,
"heapDeltaBytes": -3460448
},
{
"name": "subgraph-idle",
"durationMs": 1999.1939999999886,
"styleRecalcs": 121,
"styleRecalcDurationMs": 27.374999999999996,
"layouts": 0,
"layoutDurationMs": 0,
"taskDurationMs": 454.91700000000003,
"heapDeltaBytes": -3488136
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1745.8630000000142,
"styleRecalcs": 159,
"styleRecalcDurationMs": 56.046,
"layouts": 17,
"layoutDurationMs": 4.845,
"taskDurationMs": 841.958,
"heapDeltaBytes": -5131644
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1905.5329999999913,
"styleRecalcs": 166,
"styleRecalcDurationMs": 56.916000000000004,
"layouts": 16,
"layoutDurationMs": 4.314,
"taskDurationMs": 969.9879999999999,
"heapDeltaBytes": -5198400
},
{
"name": "subgraph-mouse-sweep",
"durationMs": 1704.9710000000005,
"styleRecalcs": 155,
"styleRecalcDurationMs": 47.945,
"layouts": 16,
"layoutDurationMs": 4.6690000000000005,
"taskDurationMs": 781.655,
"heapDeltaBytes": -5876308
}
]
} |
…button widgets (#9542) ## Summary Fix non-widget inputs on nested subgraphs appearing twice — once as slots and once as unresolved button widgets. ## Changes - **What**: Add `getTargetWidget()` guard in the `isSubgraphNode()` branch of `resolveSubgraphInputTarget`, matching the existing check for non-subgraph nodes. Non-widget inputs (e.g. AUDIO, IMAGE) now return `undefined` instead of a bogus promotion entry. ## Review Focus `resolveSubgraphInputTarget` had an asymmetry: the non-subgraph branch checked `getTargetWidget()` before returning, but the `isSubgraphNode()` branch returned unconditionally for every input. For nested subgraphs where non-widget slots are linked through to inner SubgraphNode inputs, this created `PromotedWidgetView` entries that failed `resolveDeepest()` (falling back to `type: 'button'`), while the inputs also rendered as normal slot circles since `input.widget` was never set by `_resolveInputWidget` (which correctly skipped them). ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9542-fix-prevent-non-widget-inputs-on-nested-subgraphs-from-appearing-as-button-widgets-31c6d73d3650816387c3f97f0385e762) by [Unito](https://www.unito.io) --------- Co-authored-by: Amp <amp@ampcode.com>
…button widgets (#9542) ## Summary Fix non-widget inputs on nested subgraphs appearing twice — once as slots and once as unresolved button widgets. ## Changes - **What**: Add `getTargetWidget()` guard in the `isSubgraphNode()` branch of `resolveSubgraphInputTarget`, matching the existing check for non-subgraph nodes. Non-widget inputs (e.g. AUDIO, IMAGE) now return `undefined` instead of a bogus promotion entry. ## Review Focus `resolveSubgraphInputTarget` had an asymmetry: the non-subgraph branch checked `getTargetWidget()` before returning, but the `isSubgraphNode()` branch returned unconditionally for every input. For nested subgraphs where non-widget slots are linked through to inner SubgraphNode inputs, this created `PromotedWidgetView` entries that failed `resolveDeepest()` (falling back to `type: 'button'`), while the inputs also rendered as normal slot circles since `input.widget` was never set by `_resolveInputWidget` (which correctly skipped them). ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9542-fix-prevent-non-widget-inputs-on-nested-subgraphs-from-appearing-as-button-widgets-31c6d73d3650816387c3f97f0385e762) by [Unito](https://www.unito.io) --------- Co-authored-by: Amp <amp@ampcode.com>
|
…button widgets (#9542) ## Summary Fix non-widget inputs on nested subgraphs appearing twice — once as slots and once as unresolved button widgets. ## Changes - **What**: Add `getTargetWidget()` guard in the `isSubgraphNode()` branch of `resolveSubgraphInputTarget`, matching the existing check for non-subgraph nodes. Non-widget inputs (e.g. AUDIO, IMAGE) now return `undefined` instead of a bogus promotion entry. ## Review Focus `resolveSubgraphInputTarget` had an asymmetry: the non-subgraph branch checked `getTargetWidget()` before returning, but the `isSubgraphNode()` branch returned unconditionally for every input. For nested subgraphs where non-widget slots are linked through to inner SubgraphNode inputs, this created `PromotedWidgetView` entries that failed `resolveDeepest()` (falling back to `type: 'button'`), while the inputs also rendered as normal slot circles since `input.widget` was never set by `_resolveInputWidget` (which correctly skipped them). ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9542-fix-prevent-non-widget-inputs-on-nested-subgraphs-from-appearing-as-button-widgets-31c6d73d3650816387c3f97f0385e762) by [Unito](https://www.unito.io) --------- Co-authored-by: Amp <amp@ampcode.com>
|
…button widgets (#9542) ## Summary Fix non-widget inputs on nested subgraphs appearing twice — once as slots and once as unresolved button widgets. ## Changes - **What**: Add `getTargetWidget()` guard in the `isSubgraphNode()` branch of `resolveSubgraphInputTarget`, matching the existing check for non-subgraph nodes. Non-widget inputs (e.g. AUDIO, IMAGE) now return `undefined` instead of a bogus promotion entry. ## Review Focus `resolveSubgraphInputTarget` had an asymmetry: the non-subgraph branch checked `getTargetWidget()` before returning, but the `isSubgraphNode()` branch returned unconditionally for every input. For nested subgraphs where non-widget slots are linked through to inner SubgraphNode inputs, this created `PromotedWidgetView` entries that failed `resolveDeepest()` (falling back to `type: 'button'`), while the inputs also rendered as normal slot circles since `input.widget` was never set by `_resolveInputWidget` (which correctly skipped them). ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9542-fix-prevent-non-widget-inputs-on-nested-subgraphs-from-appearing-as-button-widgets-31c6d73d3650816387c3f97f0385e762) by [Unito](https://www.unito.io) --------- Co-authored-by: Amp <amp@ampcode.com>
…hs from appearing as button widgets (#9542) (#9563) Backport of #9542 to core/1.41. Cherry-pick of merge commit 8a5bcde applied cleanly. **Original PR:** #9542 **Pipeline ticket:** 15e1f241-efaa-4fe5-88ca-4ccc7bfb3345 ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9563-backport-core-1-41-fix-prevent-non-widget-inputs-on-nested-subgraphs-from-appearing-as-31d6d73d36508154927fd4b7b55ea87f) by [Unito](https://www.unito.io) Co-authored-by: Alexander Brown <drjkl@comfy.org> Co-authored-by: Amp <amp@ampcode.com>
|
|
|
…button widgets (#9542) Fix non-widget inputs on nested subgraphs appearing twice — once as slots and once as unresolved button widgets. - **What**: Add `getTargetWidget()` guard in the `isSubgraphNode()` branch of `resolveSubgraphInputTarget`, matching the existing check for non-subgraph nodes. Non-widget inputs (e.g. AUDIO, IMAGE) now return `undefined` instead of a bogus promotion entry. `resolveSubgraphInputTarget` had an asymmetry: the non-subgraph branch checked `getTargetWidget()` before returning, but the `isSubgraphNode()` branch returned unconditionally for every input. For nested subgraphs where non-widget slots are linked through to inner SubgraphNode inputs, this created `PromotedWidgetView` entries that failed `resolveDeepest()` (falling back to `type: 'button'`), while the inputs also rendered as normal slot circles since `input.widget` was never set by `_resolveInputWidget` (which correctly skipped them). ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-9542-fix-prevent-non-widget-inputs-on-nested-subgraphs-from-appearing-as-button-widgets-31c6d73d3650816387c3f97f0385e762) by [Unito](https://www.unito.io) --------- Co-authored-by: Amp <amp@ampcode.com>
…hs from appearing as button widgets (#9542) (#9581) Backport of #9542 to core/1.40. Conflict: resolveSubgraphInputTarget.ts was modify/delete — kept as new file (the fix). **Original PR:** #9542 **Pipeline ticket:** 15e1f241-efaa-4fe5-88ca-4ccc7bfb3345 Co-authored-by: Alexander Brown <drjkl@comfy.org> Co-authored-by: Amp <amp@ampcode.com>
…esolution (#9282) (#9616) Backport of #9282 to core/1.40. MUST — user-facing subgraph widget resolution bug. 12 conflict files resolved: - 8 modify/delete: new files introduced by the PR (kept as new) - 1 add/add: resolveSubgraphInputTarget.ts (merged with existing from #9542 backport) - 3 content: accepted incoming changes **Original PR:** #9282 **Pipeline ticket:** 15e1f241-efaa-4fe5-88ca-4ccc7bfb3345 Co-authored-by: Alexander Brown <drjkl@comfy.org> Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: GitHub Action <action@github.com>
Summary
Fix non-widget inputs on nested subgraphs appearing twice — once as slots and once as unresolved button widgets.
Changes
getTargetWidget()guard in theisSubgraphNode()branch ofresolveSubgraphInputTarget, matching the existing check for non-subgraph nodes. Non-widget inputs (e.g. AUDIO, IMAGE) now returnundefinedinstead of a bogus promotion entry.Review Focus
resolveSubgraphInputTargethad an asymmetry: the non-subgraph branch checkedgetTargetWidget()before returning, but theisSubgraphNode()branch returned unconditionally for every input. For nested subgraphs where non-widget slots are linked through to inner SubgraphNode inputs, this createdPromotedWidgetViewentries that failedresolveDeepest()(falling back totype: 'button'), while the inputs also rendered as normal slot circles sinceinput.widgetwas never set by_resolveInputWidget(which correctly skipped them).┆Issue is synchronized with this Notion page by Unito