mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-20 06:20:11 +00:00
feat: implement automatic widget registration in setNodeId()
- setNodeId() now calls registerWidget() with all widget metadata - Updated BaseWidget tests with 3 new tests for automatic registration - Fixed IWidgetOptions type to use unknown instead of unknown[] Amp-Thread-ID: https://ampcode.com/threads/T-019c2631-966c-73a0-a399-7fe85bd6d495 Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -71,16 +71,15 @@ describe('BaseWidget store integration', () => {
|
||||
|
||||
describe('metadata properties after registration', () => {
|
||||
it('reads from store when registered', () => {
|
||||
const widget = createTestWidget(node, { name: 'storeWidget' })
|
||||
widget.setNodeId(1)
|
||||
|
||||
store.registerWidget(1, 'storeWidget', 'number', 42, {
|
||||
const widget = createTestWidget(node, {
|
||||
name: 'storeWidget',
|
||||
label: 'Store Label',
|
||||
hidden: true,
|
||||
disabled: true,
|
||||
advanced: true,
|
||||
promoted: true
|
||||
})
|
||||
widget.setNodeId(1)
|
||||
|
||||
expect(widget.label).toBe('Store Label')
|
||||
expect(widget.hidden).toBe(true)
|
||||
@@ -93,8 +92,6 @@ describe('BaseWidget store integration', () => {
|
||||
const widget = createTestWidget(node, { name: 'writeWidget' })
|
||||
widget.setNodeId(1)
|
||||
|
||||
store.registerWidget(1, 'writeWidget', 'number', 42)
|
||||
|
||||
widget.label = 'Updated Label'
|
||||
widget.hidden = true
|
||||
widget.disabled = true
|
||||
@@ -110,11 +107,9 @@ describe('BaseWidget store integration', () => {
|
||||
})
|
||||
|
||||
it('syncs value with store', () => {
|
||||
const widget = createTestWidget(node, { name: 'valueWidget' })
|
||||
const widget = createTestWidget(node, { name: 'valueWidget', value: 42 })
|
||||
widget.setNodeId(1)
|
||||
|
||||
store.registerWidget(1, 'valueWidget', 'number', 0)
|
||||
|
||||
widget.value = 99
|
||||
expect(store.get(1, 'valueWidget')).toBe(99)
|
||||
|
||||
@@ -123,14 +118,61 @@ describe('BaseWidget store integration', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('automatic registration via setNodeId', () => {
|
||||
it('registers widget with all metadata', () => {
|
||||
const widget = createTestWidget(node, {
|
||||
name: 'autoRegWidget',
|
||||
value: 100,
|
||||
label: 'Auto Label',
|
||||
hidden: true,
|
||||
disabled: true,
|
||||
advanced: true,
|
||||
promoted: true
|
||||
})
|
||||
widget.setNodeId(1)
|
||||
|
||||
const state = store.getWidget(1, 'autoRegWidget')
|
||||
expect(state).toBeDefined()
|
||||
expect(state?.nodeId).toBe(1)
|
||||
expect(state?.name).toBe('autoRegWidget')
|
||||
expect(state?.type).toBe('number')
|
||||
expect(state?.value).toBe(100)
|
||||
expect(state?.label).toBe('Auto Label')
|
||||
expect(state?.hidden).toBe(true)
|
||||
expect(state?.disabled).toBe(true)
|
||||
expect(state?.advanced).toBe(true)
|
||||
expect(state?.promoted).toBe(true)
|
||||
expect(state?.options).toEqual({ min: 0, max: 100 })
|
||||
})
|
||||
|
||||
it('registers widget with default metadata values', () => {
|
||||
const widget = createTestWidget(node, { name: 'defaultsWidget' })
|
||||
widget.setNodeId(1)
|
||||
|
||||
const state = store.getWidget(1, 'defaultsWidget')
|
||||
expect(state).toBeDefined()
|
||||
expect(state?.hidden).toBe(false)
|
||||
expect(state?.disabled).toBe(false)
|
||||
expect(state?.advanced).toBe(false)
|
||||
expect(state?.promoted).toBe(false)
|
||||
expect(state?.label).toBeUndefined()
|
||||
})
|
||||
|
||||
it('registers widget value in values map', () => {
|
||||
const widget = createTestWidget(node, { name: 'valuesWidget', value: 77 })
|
||||
widget.setNodeId(1)
|
||||
|
||||
expect(store.get(1, 'valuesWidget')).toBe(77)
|
||||
})
|
||||
})
|
||||
|
||||
describe('fallback behavior', () => {
|
||||
it('falls back to internal value when widget not in store', () => {
|
||||
it('uses internal value before registration', () => {
|
||||
const widget = createTestWidget(node, {
|
||||
name: 'fallbackWidget',
|
||||
label: 'Internal'
|
||||
})
|
||||
widget.setNodeId(1)
|
||||
|
||||
// Widget not yet registered - should use internal value
|
||||
expect(widget.label).toBe('Internal')
|
||||
})
|
||||
|
||||
@@ -138,8 +180,6 @@ describe('BaseWidget store integration', () => {
|
||||
const widget = createTestWidget(node)
|
||||
widget.setNodeId(1)
|
||||
|
||||
store.registerWidget(1, 'testWidget', 'number', 42)
|
||||
|
||||
widget.hidden = undefined
|
||||
widget.disabled = undefined
|
||||
|
||||
|
||||
@@ -11,7 +11,10 @@ import type {
|
||||
} from '@/lib/litegraph/src/litegraph'
|
||||
import { LiteGraph } from '@/lib/litegraph/src/litegraph'
|
||||
import type { CanvasPointerEvent } from '@/lib/litegraph/src/types/events'
|
||||
import type { IBaseWidget } from '@/lib/litegraph/src/types/widgets'
|
||||
import type {
|
||||
IBaseWidget,
|
||||
TWidgetType
|
||||
} from '@/lib/litegraph/src/types/widgets'
|
||||
import { useWidgetValueStore } from '@/stores/widgetValueStore'
|
||||
|
||||
export interface DrawWidgetOptions {
|
||||
@@ -198,15 +201,27 @@ export abstract class BaseWidget<
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates this widget with a node ID and seeds the store with the current value.
|
||||
* Once set, value reads/writes will be delegated to the WidgetValueStore.
|
||||
* Associates this widget with a node ID and registers it in the WidgetValueStore.
|
||||
* Once set, value reads/writes will be delegated to the store.
|
||||
*/
|
||||
setNodeId(nodeId: NodeId): void {
|
||||
this._nodeId = nodeId
|
||||
if (this._internalValue !== undefined) {
|
||||
const store = useWidgetValueStore()
|
||||
store.set(nodeId, this.name, this._internalValue)
|
||||
}
|
||||
const store = useWidgetValueStore()
|
||||
store.registerWidget(
|
||||
nodeId,
|
||||
this.name,
|
||||
this.type as TWidgetType,
|
||||
this._internalValue,
|
||||
{
|
||||
label: this._label,
|
||||
hidden: this._hidden,
|
||||
disabled: this._disabled,
|
||||
advanced: this._advanced,
|
||||
promoted: this._promoted,
|
||||
serialize: this.serialize,
|
||||
widgetOptions: this.options
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
constructor(widget: TWidget & { node: LGraphNode })
|
||||
|
||||
@@ -19,7 +19,7 @@ export interface WidgetState {
|
||||
disabled: boolean
|
||||
advanced: boolean
|
||||
promoted: boolean
|
||||
options: IWidgetOptions
|
||||
options: IWidgetOptions<unknown>
|
||||
serialize: boolean
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ export const useWidgetValueStore = defineStore('widgetValue', () => {
|
||||
WidgetState,
|
||||
'label' | 'hidden' | 'disabled' | 'advanced' | 'promoted' | 'serialize'
|
||||
>
|
||||
> & { widgetOptions?: IWidgetOptions } = {}
|
||||
> & { widgetOptions?: IWidgetOptions<unknown> } = {}
|
||||
): WidgetState {
|
||||
const key = makeKey(nodeId, name)
|
||||
const state: WidgetState = {
|
||||
|
||||
Reference in New Issue
Block a user