mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 06:20:11 +00:00
refactor: move isWidgetPromoted to promotionStore for shared use
Move the dual-key promotion check (with/without disambiguatingSourceNodeId) from promotionUtils.ts into promotionStore as isWidgetPromoted(). This avoids circular dependency issues when BaseWidget and domWidget need the same nested subgraph fallback logic. All three consumers now use the shared store method.
This commit is contained in:
@@ -27,30 +27,6 @@ export function getWidgetName(w: IBaseWidget): string {
|
||||
return isPromotedWidgetView(w) ? w.sourceWidgetName : w.name
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a widget is promoted by any subgraph node in the given graph.
|
||||
* Handles nested subgraph promotions where the stored key may omit the
|
||||
* disambiguatingSourceNodeId — checks both key shapes (with and without).
|
||||
*/
|
||||
export function isWidgetPromoted(
|
||||
graphId: string,
|
||||
sourceNodeId: string,
|
||||
sourceWidgetName: string,
|
||||
disambiguatingSourceNodeId?: string
|
||||
): boolean {
|
||||
const store = usePromotionStore()
|
||||
if (
|
||||
disambiguatingSourceNodeId &&
|
||||
store.isPromotedByAny(graphId, {
|
||||
sourceNodeId,
|
||||
sourceWidgetName,
|
||||
disambiguatingSourceNodeId
|
||||
})
|
||||
)
|
||||
return true
|
||||
return store.isPromotedByAny(graphId, { sourceNodeId, sourceWidgetName })
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given promotion entry corresponds to a linked promotion
|
||||
* on the subgraph node. Linked promotions are driven by subgraph input
|
||||
|
||||
@@ -211,10 +211,11 @@ export abstract class BaseWidget<TWidget extends IBaseWidget = IBaseWidget>
|
||||
if (
|
||||
graphId &&
|
||||
!suppressPromotedOutline &&
|
||||
usePromotionStore().isPromotedByAny(graphId, {
|
||||
sourceNodeId: String(this.node.id),
|
||||
sourceWidgetName: this.name
|
||||
})
|
||||
usePromotionStore().isWidgetPromoted(
|
||||
graphId,
|
||||
String(this.node.id),
|
||||
this.name
|
||||
)
|
||||
)
|
||||
return LiteGraph.WIDGET_PROMOTED_OUTLINE_COLOR
|
||||
return this.advanced
|
||||
|
||||
@@ -116,7 +116,7 @@ import {
|
||||
stripGraphPrefix,
|
||||
useWidgetValueStore
|
||||
} from '@/stores/widgetValueStore'
|
||||
import { isWidgetPromoted } from '@/core/graph/subgraph/promotionUtils'
|
||||
import { usePromotionStore } from '@/stores/promotionStore'
|
||||
import { useMissingModelStore } from '@/platform/missingModel/missingModelStore'
|
||||
import { useExecutionErrorStore } from '@/stores/executionErrorStore'
|
||||
import type {
|
||||
@@ -144,6 +144,7 @@ const { shouldHandleNodePointerEvents, forwardEventToCanvas } =
|
||||
const { isSelectInputsMode } = useAppMode()
|
||||
const canvasStore = useCanvasStore()
|
||||
const { bringNodeToFront } = useNodeZIndex()
|
||||
const promotionStore = usePromotionStore()
|
||||
const executionErrorStore = useExecutionErrorStore()
|
||||
const missingModelStore = useMissingModelStore()
|
||||
|
||||
@@ -392,7 +393,7 @@ const processedWidgets = computed((): ProcessedWidget[] => {
|
||||
const sourceWidgetName = widget.storeName ?? widget.name
|
||||
const isPromoted =
|
||||
graphId &&
|
||||
isWidgetPromoted(
|
||||
promotionStore.isWidgetPromoted(
|
||||
graphId,
|
||||
hostNodeId,
|
||||
sourceWidgetName,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { beforeEach, describe, expect, test, vi } from 'vitest'
|
||||
import { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import { ComponentWidgetImpl, DOMWidgetImpl } from '@/scripts/domWidget'
|
||||
|
||||
const isPromotedByAnyMock = vi.hoisted(() => vi.fn())
|
||||
const isWidgetPromotedMock = vi.hoisted(() => vi.fn())
|
||||
|
||||
// Mock dependencies
|
||||
vi.mock('@/stores/domWidgetStore', () => ({
|
||||
@@ -14,7 +14,7 @@ vi.mock('@/stores/domWidgetStore', () => ({
|
||||
|
||||
vi.mock('@/stores/promotionStore', () => ({
|
||||
usePromotionStore: () => ({
|
||||
isPromotedByAny: isPromotedByAnyMock
|
||||
isWidgetPromoted: isWidgetPromotedMock
|
||||
})
|
||||
}))
|
||||
|
||||
@@ -120,7 +120,7 @@ describe('DOMWidget draw promotion behavior', () => {
|
||||
})
|
||||
|
||||
test('draws promoted outline for visible promoted widgets', () => {
|
||||
isPromotedByAnyMock.mockReturnValue(true)
|
||||
isWidgetPromotedMock.mockReturnValue(true)
|
||||
|
||||
const node = new LGraphNode('test-node')
|
||||
const rootGraph = { id: 'root-graph-id' }
|
||||
@@ -138,16 +138,17 @@ describe('DOMWidget draw promotion behavior', () => {
|
||||
|
||||
widget.draw(ctx as CanvasRenderingContext2D, node, 200, 30, 40)
|
||||
|
||||
expect(isPromotedByAnyMock).toHaveBeenCalledWith('root-graph-id', {
|
||||
sourceNodeId: '-1',
|
||||
sourceWidgetName: 'seed'
|
||||
})
|
||||
expect(isWidgetPromotedMock).toHaveBeenCalledWith(
|
||||
'root-graph-id',
|
||||
'-1',
|
||||
'seed'
|
||||
)
|
||||
expect(ctx.strokeRect).toHaveBeenCalledOnce()
|
||||
expect(onDraw).toHaveBeenCalledWith(widget)
|
||||
})
|
||||
|
||||
test('does not draw promoted outline when widget is not promoted', () => {
|
||||
isPromotedByAnyMock.mockReturnValue(false)
|
||||
isWidgetPromotedMock.mockReturnValue(false)
|
||||
|
||||
const node = new LGraphNode('test-node')
|
||||
const rootGraph = { id: 'root-graph-id' }
|
||||
@@ -187,7 +188,7 @@ describe('DOMWidget draw promotion behavior', () => {
|
||||
|
||||
widget.draw(ctx as CanvasRenderingContext2D, node, 200, 30, 40)
|
||||
|
||||
expect(isPromotedByAnyMock).not.toHaveBeenCalled()
|
||||
expect(isWidgetPromotedMock).not.toHaveBeenCalled()
|
||||
expect(ctx.strokeRect).not.toHaveBeenCalled()
|
||||
expect(onDraw).toHaveBeenCalledWith(widget)
|
||||
})
|
||||
|
||||
@@ -125,8 +125,6 @@ abstract class BaseDOMWidgetImpl<V extends object | string>
|
||||
declare readonly name: string
|
||||
declare readonly options: DOMWidgetOptions<V>
|
||||
declare callback?: (value: V) => void
|
||||
readonly promotionStore = usePromotionStore()
|
||||
|
||||
readonly id: string
|
||||
|
||||
constructor(obj: {
|
||||
@@ -190,10 +188,11 @@ abstract class BaseDOMWidgetImpl<V extends object | string>
|
||||
const graphId = this.node.graph?.rootGraph.id
|
||||
const isPromoted =
|
||||
graphId &&
|
||||
this.promotionStore.isPromotedByAny(graphId, {
|
||||
sourceNodeId: String(this.node.id),
|
||||
sourceWidgetName: this.name
|
||||
})
|
||||
usePromotionStore().isWidgetPromoted(
|
||||
graphId,
|
||||
String(this.node.id),
|
||||
this.name
|
||||
)
|
||||
if (!isPromoted) {
|
||||
this.options.onDraw?.(this)
|
||||
return
|
||||
|
||||
@@ -190,11 +190,35 @@ export const usePromotionStore = defineStore('promotion', () => {
|
||||
graphRefCounts.value.delete(graphId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a widget is promoted by any subgraph node in the given
|
||||
* graph. Handles nested subgraph promotions where the stored key may omit
|
||||
* the disambiguatingSourceNodeId — checks both key shapes (#10612).
|
||||
*/
|
||||
function isWidgetPromoted(
|
||||
graphId: UUID,
|
||||
sourceNodeId: string,
|
||||
sourceWidgetName: string,
|
||||
disambiguatingSourceNodeId?: string
|
||||
): boolean {
|
||||
if (
|
||||
disambiguatingSourceNodeId &&
|
||||
isPromotedByAny(graphId, {
|
||||
sourceNodeId,
|
||||
sourceWidgetName,
|
||||
disambiguatingSourceNodeId
|
||||
})
|
||||
)
|
||||
return true
|
||||
return isPromotedByAny(graphId, { sourceNodeId, sourceWidgetName })
|
||||
}
|
||||
|
||||
return {
|
||||
getPromotionsRef,
|
||||
getPromotions,
|
||||
isPromoted,
|
||||
isPromotedByAny,
|
||||
isWidgetPromoted,
|
||||
setPromotions,
|
||||
promote,
|
||||
demote,
|
||||
|
||||
Reference in New Issue
Block a user