mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 06:20:11 +00:00
fix: preserve user widget order through _syncPromotions
Replace linked-first ordering in _buildPromotionPersistenceState with
an order-preserving merge that keeps existing store entries in their
current position while pruning stale entries and appending new ones.
This fixes a regression from 74a48ab2 where removing the
shouldPersistLinkedOnly guard caused _syncPromotions to always
overwrite user-reordered widget order with linked-first ordering.
Fixes Notion: Bug: Subgraph widget reorder causes UI and panel mismatch
This commit is contained in:
@@ -840,8 +840,52 @@ describe('SubgraphNode.widgets getter', () => {
|
||||
subgraphNode.id
|
||||
)
|
||||
expect(promotions).toStrictEqual([
|
||||
{ sourceNodeId: String(linkedNodeA.id), sourceWidgetName: 'string_a' },
|
||||
{ sourceNodeId: String(independentNode.id), sourceWidgetName: 'string_a' }
|
||||
{
|
||||
sourceNodeId: String(independentNode.id),
|
||||
sourceWidgetName: 'string_a'
|
||||
},
|
||||
{ sourceNodeId: String(linkedNodeA.id), sourceWidgetName: 'string_a' }
|
||||
])
|
||||
})
|
||||
|
||||
test('syncPromotions preserves user-reordered store order', () => {
|
||||
const subgraph = createTestSubgraph({
|
||||
inputs: [{ name: 'widget_a', type: '*' }]
|
||||
})
|
||||
const subgraphNode = createTestSubgraphNode(subgraph, { id: 97 })
|
||||
subgraphNode.graph?.add(subgraphNode)
|
||||
|
||||
const linkedNode = new LGraphNode('LinkedNode')
|
||||
const linkedInput = linkedNode.addInput('widget_a', '*')
|
||||
linkedNode.addWidget('text', 'widget_a', 'val_a', () => {})
|
||||
linkedInput.widget = { name: 'widget_a' }
|
||||
subgraph.add(linkedNode)
|
||||
subgraph.inputNode.slots[0].connect(linkedInput, linkedNode)
|
||||
|
||||
const independentNode = new LGraphNode('IndependentNode')
|
||||
independentNode.addWidget('text', 'indep_widget', 'val_b', () => {})
|
||||
subgraph.add(independentNode)
|
||||
|
||||
// Simulate user reorder: independent first, then linked
|
||||
setPromotions(subgraphNode, [
|
||||
[String(independentNode.id), 'indep_widget'],
|
||||
[String(linkedNode.id), 'widget_a']
|
||||
])
|
||||
|
||||
callSyncPromotions(subgraphNode)
|
||||
|
||||
const promotions = usePromotionStore().getPromotions(
|
||||
subgraphNode.rootGraph.id,
|
||||
subgraphNode.id
|
||||
)
|
||||
|
||||
// Order must be preserved: independent first, linked second
|
||||
expect(promotions).toStrictEqual([
|
||||
{
|
||||
sourceNodeId: String(independentNode.id),
|
||||
sourceWidgetName: 'indep_widget'
|
||||
},
|
||||
{ sourceNodeId: String(linkedNode.id), sourceWidgetName: 'widget_a' }
|
||||
])
|
||||
})
|
||||
|
||||
|
||||
@@ -385,13 +385,38 @@ export class SubgraphNode extends LGraphNode implements BaseLGraph {
|
||||
fallbackStoredEntries
|
||||
)
|
||||
|
||||
const desiredEntries = shouldPersistLinkedOnly
|
||||
? linkedPromotionEntries
|
||||
: [...linkedPromotionEntries, ...fallbackStoredEntries]
|
||||
|
||||
return {
|
||||
mergedEntries: shouldPersistLinkedOnly
|
||||
? linkedPromotionEntries
|
||||
: [...linkedPromotionEntries, ...fallbackStoredEntries]
|
||||
mergedEntries: this._orderPreservingMerge(entries, desiredEntries)
|
||||
}
|
||||
}
|
||||
|
||||
private _orderPreservingMerge(
|
||||
currentEntries: PromotedWidgetSource[],
|
||||
desiredEntries: PromotedWidgetSource[]
|
||||
): PromotedWidgetSource[] {
|
||||
const makeKey = (e: PromotedWidgetSource) =>
|
||||
this._makePromotionEntryKey(
|
||||
e.sourceNodeId,
|
||||
e.sourceWidgetName,
|
||||
e.disambiguatingSourceNodeId
|
||||
)
|
||||
|
||||
const desiredByKey = new Map(desiredEntries.map((e) => [makeKey(e), e]))
|
||||
const currentKeys = new Set(currentEntries.map(makeKey))
|
||||
|
||||
const preserved = currentEntries
|
||||
.filter((e) => desiredByKey.has(makeKey(e)))
|
||||
.map((e) => desiredByKey.get(makeKey(e))!)
|
||||
|
||||
const added = desiredEntries.filter((e) => !currentKeys.has(makeKey(e)))
|
||||
|
||||
return [...preserved, ...added]
|
||||
}
|
||||
|
||||
private _collectLinkedAndFallbackEntries(
|
||||
entries: PromotedWidgetSource[],
|
||||
linkedEntries: LinkedPromotionEntry[]
|
||||
|
||||
Reference in New Issue
Block a user