diff --git a/src/components/rightSidePanel/parameters/WidgetActions.vue b/src/components/rightSidePanel/parameters/WidgetActions.vue index b9b5fa04a..467c24d6e 100644 --- a/src/components/rightSidePanel/parameters/WidgetActions.vue +++ b/src/components/rightSidePanel/parameters/WidgetActions.vue @@ -51,6 +51,8 @@ const isEffectivelyAdvanced = computed(() => advancedOverridesStore.getAdvancedState(node, widget) ) +const backendDefaultAdvanced = computed(() => !!widget.options?.advanced) + const showAdvancedToggle = computed( () => !hasParents.value && @@ -112,11 +114,13 @@ function handleToggleFavorite() { } function handleToggleAdvanced() { - advancedOverridesStore.setAdvanced( - node, - widget.name, - !isEffectivelyAdvanced.value - ) + const newEffective = !isEffectivelyAdvanced.value + if (newEffective === backendDefaultAdvanced.value) { + advancedOverridesStore.clearOverride(node, widget.name) + } else { + advancedOverridesStore.setAdvanced(node, widget.name, newEffective) + } + node.expandToFitContent() } diff --git a/src/stores/workspace/advancedWidgetOverridesStore.test.ts b/src/stores/workspace/advancedWidgetOverridesStore.test.ts index ff3ebc997..f1e9bb672 100644 --- a/src/stores/workspace/advancedWidgetOverridesStore.test.ts +++ b/src/stores/workspace/advancedWidgetOverridesStore.test.ts @@ -1,11 +1,14 @@ import { createPinia, setActivePinia } from 'pinia' +import { nextTick } from 'vue' import { beforeEach, describe, expect, it, vi } from 'vitest' +import type { LGraphNode } from '@/lib/litegraph/src/litegraph' +import type { IWidgetOptions } from '@/lib/litegraph/src/types/widgets' import { useAdvancedWidgetOverridesStore } from '@/stores/workspace/advancedWidgetOverridesStore' const mockGraph = { extra: {} as Record, - nodes: [] as Array<{ id: number; widgets: Array<{ name: string }> }> + nodes: [] as LGraphNode[] } vi.mock('@/scripts/app', () => ({ @@ -31,9 +34,9 @@ vi.mock('@/renderer/core/canvas/canvasStore', () => ({ function makeNode( id: number, - widgets: Array<{ name: string; options?: Record }> + widgets: Array<{ name: string; options?: IWidgetOptions }> ) { - return { id, widgets } as any + return { id, widgets } as Partial as LGraphNode } describe('useAdvancedWidgetOverridesStore', () => { @@ -47,10 +50,10 @@ describe('useAdvancedWidgetOverridesStore', () => { const store = useAdvancedWidgetOverridesStore() const node = makeNode(1, [{ name: 'steps', options: { advanced: true } }]) - expect(store.getAdvancedState(node, node.widgets[0])).toBe(true) + expect(store.getAdvancedState(node, node.widgets![0])).toBe(true) const node2 = makeNode(2, [{ name: 'cfg' }]) - expect(store.getAdvancedState(node2, node2.widgets[0])).toBe(false) + expect(store.getAdvancedState(node2, node2.widgets![0])).toBe(false) }) it('override to advanced takes precedence over backend', () => { @@ -59,7 +62,7 @@ describe('useAdvancedWidgetOverridesStore', () => { store.setAdvanced(node, 'cfg', true) - expect(store.getAdvancedState(node, node.widgets[0])).toBe(true) + expect(store.getAdvancedState(node, node.widgets![0])).toBe(true) expect(store.isOverridden(node, 'cfg')).toBe(true) }) @@ -69,7 +72,7 @@ describe('useAdvancedWidgetOverridesStore', () => { store.setAdvanced(node, 'steps', false) - expect(store.getAdvancedState(node, node.widgets[0])).toBe(false) + expect(store.getAdvancedState(node, node.widgets![0])).toBe(false) expect(store.isOverridden(node, 'steps')).toBe(true) }) @@ -78,10 +81,10 @@ describe('useAdvancedWidgetOverridesStore', () => { const node = makeNode(1, [{ name: 'steps', options: { advanced: true } }]) store.setAdvanced(node, 'steps', false) - expect(store.getAdvancedState(node, node.widgets[0])).toBe(false) + expect(store.getAdvancedState(node, node.widgets![0])).toBe(false) store.clearOverride(node, 'steps') - expect(store.getAdvancedState(node, node.widgets[0])).toBe(true) + expect(store.getAdvancedState(node, node.widgets![0])).toBe(true) expect(store.isOverridden(node, 'steps')).toBe(false) }) @@ -101,7 +104,13 @@ describe('useAdvancedWidgetOverridesStore', () => { store.setAdvanced(node, 'cfg', true) - const stored = mockGraph.extra.advancedWidgetOverrides as any + const stored = mockGraph.extra.advancedWidgetOverrides as { + overrides: Array<{ + nodeLocatorId: string + widgetName: string + advanced: boolean + }> + } expect(stored.overrides).toHaveLength(1) expect(stored.overrides[0]).toEqual({ nodeLocatorId: 'node-1', @@ -110,7 +119,7 @@ describe('useAdvancedWidgetOverridesStore', () => { }) }) - it('loads overrides from workflow.extra', () => { + it('loads overrides from workflow.extra', async () => { mockGraph.extra = { advancedWidgetOverrides: { overrides: [ @@ -121,13 +130,13 @@ describe('useAdvancedWidgetOverridesStore', () => { } const store = useAdvancedWidgetOverridesStore() - store.loadFromWorkflow() + await nextTick() const node1 = makeNode(1, [{ name: 'cfg' }]) - expect(store.getAdvancedState(node1, node1.widgets[0])).toBe(true) + expect(store.getAdvancedState(node1, node1.widgets![0])).toBe(true) const node2 = makeNode(2, [{ name: 'steps', options: { advanced: true } }]) - expect(store.getAdvancedState(node2, node2.widgets[0])).toBe(false) + expect(store.getAdvancedState(node2, node2.widgets![0])).toBe(false) }) it('clearAllOverrides removes everything', () => { @@ -135,10 +144,15 @@ describe('useAdvancedWidgetOverridesStore', () => { const node = makeNode(1, [{ name: 'cfg' }]) store.setAdvanced(node, 'cfg', true) - expect(store.overrides.size).toBe(1) + expect(store.isOverridden(node, 'cfg')).toBe(true) store.clearAllOverrides() - expect(store.overrides.size).toBe(0) + expect(store.isOverridden(node, 'cfg')).toBe(false) + + const stored = mockGraph.extra.advancedWidgetOverrides as { + overrides: unknown[] + } + expect(stored.overrides).toHaveLength(0) }) it('pruneInvalidOverrides removes stale entries', () => { @@ -147,14 +161,28 @@ describe('useAdvancedWidgetOverridesStore', () => { store.setAdvanced(node, 'cfg', true) store.setAdvanced(node, 'steps', true) - expect(store.overrides.size).toBe(2) + expect(store.isOverridden(node, 'cfg')).toBe(true) + expect(store.isOverridden(node, 'steps')).toBe(true) // Simulate node having only 'cfg' widget now - mockGraph.nodes = [{ id: 1, widgets: [{ name: 'cfg' }] }] as any + mockGraph.nodes = [makeNode(1, [{ name: 'cfg' }])] store.pruneInvalidOverrides() - expect(store.overrides.size).toBe(1) expect(store.isOverridden(node, 'cfg')).toBe(true) expect(store.isOverridden(node, 'steps')).toBe(false) + + const stored = mockGraph.extra.advancedWidgetOverrides as { + overrides: Array<{ + nodeLocatorId: string + widgetName: string + advanced: boolean + }> + } + expect(stored.overrides).toHaveLength(1) + expect(stored.overrides[0]).toEqual({ + nodeLocatorId: 'node-1', + widgetName: 'cfg', + advanced: true + }) }) }) diff --git a/src/stores/workspace/advancedWidgetOverridesStore.ts b/src/stores/workspace/advancedWidgetOverridesStore.ts index 2afe4050a..e598fa7cd 100644 --- a/src/stores/workspace/advancedWidgetOverridesStore.ts +++ b/src/stores/workspace/advancedWidgetOverridesStore.ts @@ -1,5 +1,5 @@ import { defineStore } from 'pinia' -import { computed, ref, watch } from 'vue' +import { ref, watch } from 'vue' import type { LGraphNode } from '@/lib/litegraph/src/litegraph' import type { IWidgetOptions } from '@/lib/litegraph/src/types/widgets' @@ -210,7 +210,7 @@ export const useAdvancedWidgetOverridesStore = defineStore( } watch( - () => workflowStore.activeWorkflow?.path, + () => workflowStore.activeWorkflow, () => { loadFromWorkflow() }, @@ -218,17 +218,13 @@ export const useAdvancedWidgetOverridesStore = defineStore( ) return { - overrides: computed(() => overrides.value), - getAdvancedState, setAdvanced, clearOverride, isOverridden, hasAnyAdvanced, clearAllOverrides, - pruneInvalidOverrides, - loadFromWorkflow, - saveToWorkflow + pruneInvalidOverrides } } )