fix(subgraph): preserve renamed labels through migration + app mode

Two related label-propagation regressions:

R1 (app-mode rename): mappedSelections in AppModeWidgetList depends on
graphNodes (shallowRef), and renaming a promoted widget never bumped it.
Listen for node:slot-label:changed (already fired by renameWidget) and
triggerRef the existing graphNodes shallowRef.

R2 (sidepanel renamed labels): repairCreateSubgraphInput in the proxy-
widget migration created a new SubgraphInput without copying the
interior slot's label. After migration, the renamed label was lost
because PromotedWidgetView.label falls back to slot.name. Mirror the
LGraphNode.configure input.label propagation at the migration boundary.

Also drop the redundant `_subgraphSlot.label =` write in renameWidget
(the PromotedWidgetView.set label setter writes the slot directly).

Amp-Thread-ID: https://ampcode.com/threads/T-019e0e0d-1937-758e-8a9b-4f54716b0aa2
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
DrJKL
2026-05-09 14:06:56 -07:00
parent 231a8ce723
commit 3cfd4d0401
4 changed files with 6 additions and 22 deletions

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { useEventListener } from '@vueuse/core'
import { computed, provide, shallowRef } from 'vue'
import { computed, provide, shallowRef, triggerRef } from 'vue'
import { useAppModeWidgetResizing } from '@/components/builder/useAppModeWidgetResizing'
import { useI18n } from 'vue-i18n'
@@ -63,6 +63,9 @@ useEventListener(
'configured',
() => (graphNodes.value = app.rootGraph.nodes)
)
useEventListener(app.rootGraph.events, 'node:slot-label:changed', () =>
triggerRef(graphNodes)
)
const mappedSelections = computed((): WidgetEntry[] => {
void graphNodes.value

View File

@@ -121,6 +121,8 @@ function repairCreateSubgraphInput(
const slotType = String(slot.type ?? sourceWidget.type ?? '*')
const newSubgraphInput = subgraph.addInput(desiredName, slotType)
// Mirror LGraphNode.configure: input.label → widget.label propagation.
if (slot.label !== undefined) newSubgraphInput.label = slot.label
const link = newSubgraphInput.connect(slot, sourceNode)
if (!link) {
subgraph.removeInput(newSubgraphInput)

View File

@@ -128,21 +128,6 @@ describe('renameWidget', () => {
expect(promotedWidget.label).toBe('Renamed')
})
it('updates _subgraphSlot.label when input has a subgraph slot', () => {
const widget = makeWidget({ name: 'seed' })
const subgraphSlot = { label: undefined as string | undefined }
const input = fromAny<INodeInputSlot, unknown>({
name: 'seed',
widget: { name: 'seed' },
_subgraphSlot: subgraphSlot
})
const node = makeNode({ inputs: [input] })
renameWidget(widget, node, 'New Label')
expect(subgraphSlot.label).toBe('New Label')
})
it('does not resolve promoted widget source for non-subgraph node without parents', () => {
const promotedWidget = makeWidget({
name: 'seed',

View File

@@ -1,7 +1,6 @@
import { isPromotedWidgetView } from '@/core/graph/subgraph/promotedWidgetTypes'
import { resolvePromotedWidgetSource } from '@/core/graph/subgraph/resolvePromotedWidgetSource'
import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode'
import type { ISubgraphInput } from '@/lib/litegraph/src/interfaces'
import type { SubgraphNode } from '@/lib/litegraph/src/subgraph/SubgraphNode'
import { NodeSlotType } from '@/lib/litegraph/src/types/globalEnums'
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
@@ -78,11 +77,6 @@ export function renameWidget(
widget.label = newLabel || undefined
if (input) {
input.label = newLabel || undefined
const subgraphSlot = (input as Partial<ISubgraphInput>)._subgraphSlot
if (subgraphSlot) {
subgraphSlot.label = newLabel || undefined
}
}
// Fires for all node types; listeners guard against non-subgraph nodes.