diff --git a/src/components/rightSidePanel/settings/SetNodeState.vue b/src/components/rightSidePanel/settings/SetNodeState.vue index 7d64fefeff3..2c5d539af59 100644 --- a/src/components/rightSidePanel/settings/SetNodeState.vue +++ b/src/components/rightSidePanel/settings/SetNodeState.vue @@ -4,44 +4,56 @@ import { useI18n } from 'vue-i18n' import type { LGraphNode } from '@/lib/litegraph/src/LGraphNode' import { LGraphEventMode } from '@/lib/litegraph/src/litegraph' +import { layoutStore } from '@/renderer/core/layout/store/layoutStore' import FormSelectButton from '@/renderer/extensions/vueNodes/widgets/components/form/FormSelectButton.vue' import LayoutField from './LayoutField.vue' /** * Good design limits dependencies and simplifies the interface of the abstraction layer. - * Here, we only care about the mode method, + * Here, we only care about the node id, * and do not concern ourselves with other methods. */ -type PickedNode = Pick +type PickedNode = Pick const { nodes } = defineProps<{ nodes: PickedNode[] }>() const emit = defineEmits<{ (e: 'changed'): void }>() const { t } = useI18n() +const nodeIds = computed(() => nodes.map((node) => node.id.toString())) + +/** + * Retrieves layout references for all selected nodes from the store. + */ +const nodeRefs = computed(() => + nodeIds.value.map((nodeId) => layoutStore.getNodeLayoutRef(nodeId)) +) + +/** + * Manages the execution mode state for selected nodes. + * When getting: returns the common mode if all nodes share the same mode, null otherwise. + * When setting: applies the new mode to all selected nodes via the layout store. + */ const nodeState = computed({ get() { - let mode: LGraphNode['mode'] | null = null + if (nodeIds.value.length === 0) return null - if (nodes.length === 0) return null + const modes = nodeRefs.value + .map((nodeRef) => nodeRef.value?.mode) + .filter((mode): mode is number => mode !== undefined && mode !== null) - // For multiple nodes, if all nodes have the same mode, return that mode, otherwise return null - if (nodes.length > 1) { - mode = nodes[0].mode - if (!nodes.every((node) => node.mode === mode)) { - mode = null - } - } else { - mode = nodes[0].mode - } + if (modes.length === 0) return null - return mode + const firstMode = modes[0] + const allSame = modes.every((mode) => mode === firstMode) + + return allSame ? firstMode : null }, set(value: LGraphNode['mode']) { - nodes.forEach((node) => { - node.mode = value - }) + if (value === null || value === undefined) return + + layoutStore.setNodesMode(nodeIds.value, value) emit('changed') } }) diff --git a/src/composables/canvas/useSelectedLiteGraphItems.test.ts b/src/composables/canvas/useSelectedLiteGraphItems.test.ts index 23e1e8dd31e..7f164245a83 100644 --- a/src/composables/canvas/useSelectedLiteGraphItems.test.ts +++ b/src/composables/canvas/useSelectedLiteGraphItems.test.ts @@ -4,6 +4,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import { useSelectedLiteGraphItems } from '@/composables/canvas/useSelectedLiteGraphItems' import type { LGraphNode, Positionable } from '@/lib/litegraph/src/litegraph' import { LGraphEventMode, Reroute } from '@/lib/litegraph/src/litegraph' +import { layoutStore } from '@/renderer/core/layout/store/layoutStore' import { useCanvasStore } from '@/renderer/core/canvas/canvasStore' import { app } from '@/scripts/app' @@ -224,8 +225,19 @@ describe('useSelectedLiteGraphItems', () => { it('toggleSelectedNodesMode should toggle node modes correctly', () => { const { toggleSelectedNodesMode } = useSelectedLiteGraphItems() - const node1 = { id: 1, mode: LGraphEventMode.ALWAYS } as LGraphNode - const node2 = { id: 2, mode: LGraphEventMode.NEVER } as LGraphNode + const node1 = { id: '1', mode: LGraphEventMode.ALWAYS } as LGraphNode + const node2 = { id: '2', mode: LGraphEventMode.NEVER } as LGraphNode + + // Initialize nodes in layoutStore + layoutStore.initializeFromLiteGraph([ + { + id: '1', + pos: [0, 0], + size: [100, 100], + mode: LGraphEventMode.ALWAYS + }, + { id: '2', pos: [0, 0], size: [100, 100], mode: LGraphEventMode.NEVER } + ]) app.canvas.selected_nodes = { '0': node1, '1': node2 } @@ -234,13 +246,22 @@ describe('useSelectedLiteGraphItems', () => { // node1 should change from ALWAYS to NEVER // node2 should stay NEVER (since a selected node exists which is not NEVER) - expect(node1.mode).toBe(LGraphEventMode.NEVER) - expect(node2.mode).toBe(LGraphEventMode.NEVER) + expect(layoutStore.getNodeLayoutRef('1').value?.mode).toBe( + LGraphEventMode.NEVER + ) + expect(layoutStore.getNodeLayoutRef('2').value?.mode).toBe( + LGraphEventMode.NEVER + ) }) it('toggleSelectedNodesMode should set mode to ALWAYS when already in target mode', () => { const { toggleSelectedNodesMode } = useSelectedLiteGraphItems() - const node = { id: 1, mode: LGraphEventMode.BYPASS } as LGraphNode + const node = { id: '1', mode: LGraphEventMode.BYPASS } as LGraphNode + + // Initialize node in layoutStore + layoutStore.initializeFromLiteGraph([ + { id: '1', pos: [0, 0], size: [100, 100], mode: LGraphEventMode.BYPASS } + ]) app.canvas.selected_nodes = { '0': node } @@ -248,7 +269,9 @@ describe('useSelectedLiteGraphItems', () => { toggleSelectedNodesMode(LGraphEventMode.BYPASS) // Should change to ALWAYS - expect(node.mode).toBe(LGraphEventMode.ALWAYS) + expect(layoutStore.getNodeLayoutRef('1').value?.mode).toBe( + LGraphEventMode.ALWAYS + ) }) it('getSelectedNodes should include nodes from subgraphs', () => { @@ -277,17 +300,43 @@ describe('useSelectedLiteGraphItems', () => { it('toggleSelectedNodesMode should apply unified state to subgraph children', () => { const { toggleSelectedNodesMode } = useSelectedLiteGraphItems() - const subNode1 = { id: 11, mode: LGraphEventMode.ALWAYS } as LGraphNode - const subNode2 = { id: 12, mode: LGraphEventMode.NEVER } as LGraphNode + const subNode1 = { id: '11', mode: LGraphEventMode.ALWAYS } as LGraphNode + const subNode2 = { id: '12', mode: LGraphEventMode.NEVER } as LGraphNode const subgraphNode = { - id: 1, + id: '1', mode: LGraphEventMode.ALWAYS, isSubgraphNode: () => true, subgraph: { nodes: [subNode1, subNode2] } } as unknown as LGraphNode - const regularNode = { id: 2, mode: LGraphEventMode.BYPASS } as LGraphNode + const regularNode = { + id: '2', + mode: LGraphEventMode.BYPASS + } as LGraphNode + + // Initialize all nodes in layoutStore + layoutStore.initializeFromLiteGraph([ + { + id: '1', + pos: [0, 0], + size: [100, 100], + mode: LGraphEventMode.ALWAYS + }, + { + id: '2', + pos: [0, 0], + size: [100, 100], + mode: LGraphEventMode.BYPASS + }, + { + id: '11', + pos: [0, 0], + size: [100, 100], + mode: LGraphEventMode.ALWAYS + }, + { id: '12', pos: [0, 0], size: [100, 100], mode: LGraphEventMode.NEVER } + ]) app.canvas.selected_nodes = { '0': subgraphNode, '1': regularNode } @@ -296,22 +345,30 @@ describe('useSelectedLiteGraphItems', () => { // Selected nodes follow standard toggle logic: // subgraphNode: ALWAYS -> NEVER (since ALWAYS != NEVER) - expect(subgraphNode.mode).toBe(LGraphEventMode.NEVER) + expect(layoutStore.getNodeLayoutRef('1').value?.mode).toBe( + LGraphEventMode.NEVER + ) // regularNode: BYPASS -> NEVER (since BYPASS != NEVER) - expect(regularNode.mode).toBe(LGraphEventMode.NEVER) + expect(layoutStore.getNodeLayoutRef('2').value?.mode).toBe( + LGraphEventMode.NEVER + ) // Subgraph children get unified state (same as their parent): // Both children should now be NEVER, regardless of their previous states - expect(subNode1.mode).toBe(LGraphEventMode.NEVER) // was ALWAYS, now NEVER - expect(subNode2.mode).toBe(LGraphEventMode.NEVER) // was NEVER, stays NEVER + expect(layoutStore.getNodeLayoutRef('11').value?.mode).toBe( + LGraphEventMode.NEVER + ) // was ALWAYS, now NEVER + expect(layoutStore.getNodeLayoutRef('12').value?.mode).toBe( + LGraphEventMode.NEVER + ) // was NEVER, stays NEVER }) it('toggleSelectedNodesMode should toggle to ALWAYS when subgraph is already in target mode', () => { const { toggleSelectedNodesMode } = useSelectedLiteGraphItems() - const subNode1 = { id: 11, mode: LGraphEventMode.ALWAYS } as LGraphNode - const subNode2 = { id: 12, mode: LGraphEventMode.BYPASS } as LGraphNode + const subNode1 = { id: '11', mode: LGraphEventMode.ALWAYS } as LGraphNode + const subNode2 = { id: '12', mode: LGraphEventMode.BYPASS } as LGraphNode const subgraphNode = { - id: 1, + id: '1', mode: LGraphEventMode.NEVER, // Already in NEVER mode isSubgraphNode: () => true, subgraph: { @@ -319,17 +376,40 @@ describe('useSelectedLiteGraphItems', () => { } } as unknown as LGraphNode + // Initialize all nodes in layoutStore + layoutStore.initializeFromLiteGraph([ + { id: '1', pos: [0, 0], size: [100, 100], mode: LGraphEventMode.NEVER }, + { + id: '11', + pos: [0, 0], + size: [100, 100], + mode: LGraphEventMode.ALWAYS + }, + { + id: '12', + pos: [0, 0], + size: [100, 100], + mode: LGraphEventMode.BYPASS + } + ]) + app.canvas.selected_nodes = { '0': subgraphNode } // Toggle to NEVER mode (but subgraphNode is already NEVER) toggleSelectedNodesMode(LGraphEventMode.NEVER) // Selected subgraph should toggle to ALWAYS (since it was already NEVER) - expect(subgraphNode.mode).toBe(LGraphEventMode.ALWAYS) + expect(layoutStore.getNodeLayoutRef('1').value?.mode).toBe( + LGraphEventMode.ALWAYS + ) // All children should also get ALWAYS (unified with parent's new state) - expect(subNode1.mode).toBe(LGraphEventMode.ALWAYS) - expect(subNode2.mode).toBe(LGraphEventMode.ALWAYS) + expect(layoutStore.getNodeLayoutRef('11').value?.mode).toBe( + LGraphEventMode.ALWAYS + ) + expect(layoutStore.getNodeLayoutRef('12').value?.mode).toBe( + LGraphEventMode.ALWAYS + ) }) }) diff --git a/src/composables/canvas/useSelectedLiteGraphItems.ts b/src/composables/canvas/useSelectedLiteGraphItems.ts index a4a93b9fbc0..0e165f5209e 100644 --- a/src/composables/canvas/useSelectedLiteGraphItems.ts +++ b/src/composables/canvas/useSelectedLiteGraphItems.ts @@ -1,5 +1,6 @@ import type { LGraphNode, Positionable } from '@/lib/litegraph/src/litegraph' import { LGraphEventMode, Reroute } from '@/lib/litegraph/src/litegraph' +import { layoutStore } from '@/renderer/core/layout/store/layoutStore' import { useCanvasStore } from '@/renderer/core/canvas/canvasStore' import { app } from '@/scripts/app' import { @@ -119,16 +120,21 @@ export function useSelectedLiteGraphItems() { for (const i in selectedNodes) { selectedNodeArray.push(selectedNodes[i]) } - const allNodesMatch = !selectedNodeArray.some( - (selectedNode) => selectedNode.mode !== mode - ) + + // Check if all selected nodes are already in the target mode + const allNodesMatch = !selectedNodeArray.some((selectedNode) => { + const nodeRef = layoutStore.getNodeLayoutRef(selectedNode.id.toString()) + return nodeRef.value?.mode !== mode + }) const newModeForSelectedNode = allNodesMatch ? LGraphEventMode.ALWAYS : mode // Process each selected node independently to determine its target state and apply to children selectedNodeArray.forEach((selectedNode) => { // Apply standard toggle logic to the selected node itself - - selectedNode.mode = newModeForSelectedNode + layoutStore.setNodeMode( + selectedNode.id.toString(), + newModeForSelectedNode + ) // If this selected node is a subgraph, apply the same mode uniformly to all its children // This ensures predictable behavior: all children get the same state as their parent @@ -139,7 +145,7 @@ export function useSelectedLiteGraphItems() { if (node === selectedNode) return undefined // Apply the parent's new mode to all children uniformly - node.mode = newModeForSelectedNode + layoutStore.setNodeMode(node.id.toString(), newModeForSelectedNode) return undefined } }) diff --git a/src/composables/graph/useVueNodeLifecycle.ts b/src/composables/graph/useVueNodeLifecycle.ts index 648427a5130..51fdf33775b 100644 --- a/src/composables/graph/useVueNodeLifecycle.ts +++ b/src/composables/graph/useVueNodeLifecycle.ts @@ -8,6 +8,7 @@ import type { LGraphNode } from '@/lib/litegraph/src/litegraph' import { useCanvasStore } from '@/renderer/core/canvas/canvasStore' import { useLayoutMutations } from '@/renderer/core/layout/operations/layoutMutations' import { layoutStore } from '@/renderer/core/layout/store/layoutStore' +import { patchLGraphNodeMode } from '@/renderer/core/layout/sync/patchLGraphNodeMode' import { useLayoutSync } from '@/renderer/core/layout/sync/useLayoutSync' import { removeNodeTitleHeight } from '@/renderer/core/layout/utils/nodeSizeUtil' import { ensureCorrectLayoutScale } from '@/renderer/extensions/vueNodes/layout/ensureCorrectLayoutScale' @@ -36,7 +37,8 @@ function useVueNodeLifecycleIndividual() { size: [node.size[0], removeNodeTitleHeight(node.size[1])] as [ number, number - ] + ], + mode: node.mode })) layoutStore.initializeFromLiteGraph(nodes) @@ -59,6 +61,9 @@ function useVueNodeLifecycleIndividual() { ) } + // Patch LGraphNode.changeMode to sync with layoutStore + patchLGraphNodeMode() + // Initialize layout sync (one-way: Layout Store → LiteGraph) startSync(canvasStore.canvas) } diff --git a/src/extensions/core/groupOptions.ts b/src/extensions/core/groupOptions.ts index 7e3240bcf70..8a73374dd10 100644 --- a/src/extensions/core/groupOptions.ts +++ b/src/extensions/core/groupOptions.ts @@ -7,14 +7,14 @@ import { LGraphGroup, type LGraphNode } from '@/lib/litegraph/src/litegraph' +import { layoutStore } from '@/renderer/core/layout/store/layoutStore' import { useSettingStore } from '@/platform/settings/settingStore' import type { ComfyExtension } from '@/types/comfy' import { app } from '../../scripts/app' function setNodeMode(node: LGraphNode, mode: number) { - node.mode = mode - node.graph?.change() + layoutStore.setNodeMode(node.id.toString(), mode) } function addNodesToGroup(group: LGraphGroup, items: Iterable) { diff --git a/src/lib/litegraph/src/LGraphNode.ts b/src/lib/litegraph/src/LGraphNode.ts index 1ff503cdc94..3a568ee3bbb 100644 --- a/src/lib/litegraph/src/LGraphNode.ts +++ b/src/lib/litegraph/src/LGraphNode.ts @@ -1325,6 +1325,9 @@ export class LGraphNode case LGraphEventMode.ALWAYS: break + case LGraphEventMode.BYPASS: + break + // @ts-expect-error Not impl. case LiteGraph.ON_REQUEST: break diff --git a/src/renderer/core/layout/operations/layoutMutations.ts b/src/renderer/core/layout/operations/layoutMutations.ts index 78d580d3580..b2d0e51f06a 100644 --- a/src/renderer/core/layout/operations/layoutMutations.ts +++ b/src/renderer/core/layout/operations/layoutMutations.ts @@ -150,6 +150,7 @@ export function useLayoutMutations(): LayoutMutations { size: layout.size ?? { width: 200, height: 100 }, zIndex: layout.zIndex ?? 0, visible: layout.visible ?? true, + mode: layout.mode ?? 0, // Default to ALWAYS bounds: { x: layout.position?.x ?? 0, y: layout.position?.y ?? 0, diff --git a/src/renderer/core/layout/store/layoutStore.test.ts b/src/renderer/core/layout/store/layoutStore.test.ts index ff7ee1fa06b..4bfb044320b 100644 --- a/src/renderer/core/layout/store/layoutStore.test.ts +++ b/src/renderer/core/layout/store/layoutStore.test.ts @@ -17,6 +17,7 @@ describe('layoutStore CRDT operations', () => { size: { width: 200, height: 100 }, zIndex: 0, visible: true, + mode: 0, bounds: { x: 100, y: 100, width: 200, height: 100 } }) diff --git a/src/renderer/core/layout/store/layoutStore.ts b/src/renderer/core/layout/store/layoutStore.ts index 786be06256e..44924c25bf9 100644 --- a/src/renderer/core/layout/store/layoutStore.ts +++ b/src/renderer/core/layout/store/layoutStore.ts @@ -37,6 +37,7 @@ import type { RerouteId, RerouteLayout, ResizeNodeOperation, + SetNodeModeOperation, SetNodeZIndexOperation, SlotLayout } from '@/renderer/core/layout/types' @@ -295,6 +296,18 @@ class LayoutStoreImpl implements LayoutStore { actor: this.currentActor }) } + if (existingLayout.mode !== newLayout.mode) { + this.applyOperation({ + type: 'setNodeMode', + entity: 'node', + nodeId, + mode: newLayout.mode, + previousMode: existingLayout.mode, + timestamp: Date.now(), + source: this.currentSource, + actor: this.currentActor + }) + } } } trigger() @@ -870,6 +883,9 @@ class LayoutStoreImpl implements LayoutStore { case 'setNodeZIndex': this.handleSetNodeZIndex(operation as SetNodeZIndexOperation, change) break + case 'setNodeMode': + this.handleSetNodeMode(operation as SetNodeModeOperation, change) + break case 'createNode': this.handleCreateNode(operation as CreateNodeOperation, change) break @@ -969,7 +985,12 @@ class LayoutStoreImpl implements LayoutStore { * Initialize store with existing nodes */ initializeFromLiteGraph( - nodes: Array<{ id: string; pos: [number, number]; size: [number, number] }> + nodes: Array<{ + id: string + pos: [number, number] + size: [number, number] + mode?: number + }> ): void { this.ydoc.transact(() => { this.ynodes.clear() @@ -993,6 +1014,7 @@ class LayoutStoreImpl implements LayoutStore { size: { width: node.size[0], height: node.size[1] }, zIndex: index, visible: true, + mode: node.mode ?? 0, // Default to ALWAYS if not provided bounds: { x: node.pos[0], y: node.pos[1], @@ -1078,6 +1100,17 @@ class LayoutStoreImpl implements LayoutStore { change.nodeIds.push(operation.nodeId) } + private handleSetNodeMode( + operation: SetNodeModeOperation, + change: LayoutChange + ): void { + const ynode = this.ynodes.get(operation.nodeId) + if (!ynode) return + + ynode.set('mode', operation.mode) + change.nodeIds.push(operation.nodeId) + } + private handleCreateNode( operation: CreateNodeOperation, change: LayoutChange @@ -1428,6 +1461,43 @@ class LayoutStoreImpl implements LayoutStore { return Y.encodeStateAsUpdate(this.ydoc) } + /** + * Set the execution mode for a single node. + * Applies the node's changeMode method if available and notifies the graph. + */ + setNodeMode(nodeId: NodeId, mode: number): void { + const ynode = this.ynodes.get(nodeId) + if (!ynode) return + + const currentLayout = yNodeToLayout(ynode) + if (currentLayout.mode === mode) return // No change needed + + this.applyOperation({ + type: 'setNodeMode', + entity: 'node', + nodeId, + mode, + previousMode: currentLayout.mode, + timestamp: Date.now(), + source: this.currentSource, + actor: this.currentActor + }) + } + + /** + * Set the execution mode for multiple nodes. + * Applies the mode to all nodes atomically. + */ + setNodesMode(nodeIds: NodeId[], mode: number): void { + if (nodeIds.length === 0) return + + // Apply mode to each node + // Note: We could create a batch operation type if needed for better performance + nodeIds.forEach((nodeId) => { + this.setNodeMode(nodeId, mode) + }) + } + /** * Batch update node bounds using Yjs transaction for atomicity. */ diff --git a/src/renderer/core/layout/sync/patchLGraphNodeMode.ts b/src/renderer/core/layout/sync/patchLGraphNodeMode.ts new file mode 100644 index 00000000000..598ecd1d900 --- /dev/null +++ b/src/renderer/core/layout/sync/patchLGraphNodeMode.ts @@ -0,0 +1,33 @@ +/** + * Patches LGraphNode.changeMode to sync with layoutStore + * This ensures that mode changes from LiteGraph (e.g., keyboard shortcuts, context menus) + * are properly synchronized to the layout store. + */ +import { LGraphNode } from '@/lib/litegraph/src/LGraphNode' +import { layoutStore } from '@/renderer/core/layout/store/layoutStore' + +let isPatched = false + +/** + * Patches LGraphNode.prototype.changeMode to sync with layoutStore. + * Should be called once during application initialization. + */ +export function patchLGraphNodeMode(): void { + if (isPatched) return + + const originalChangeMode = LGraphNode.prototype.changeMode + + LGraphNode.prototype.changeMode = function (modeTo: number): boolean { + const previousMode = this.mode + const result = originalChangeMode.call(this, modeTo) + + // Sync to layoutStore if mode actually changed and the call succeeded + if (result && previousMode !== this.mode) { + layoutStore.setNodeMode(this.id.toString(), this.mode) + } + + return result + } + + isPatched = true +} diff --git a/src/renderer/core/layout/sync/useLayoutSync.ts b/src/renderer/core/layout/sync/useLayoutSync.ts index 221fe64eb90..d789924b157 100644 --- a/src/renderer/core/layout/sync/useLayoutSync.ts +++ b/src/renderer/core/layout/sync/useLayoutSync.ts @@ -53,6 +53,11 @@ export function useLayoutSync() { // Use setSize() to trigger onResize callback liteNode.setSize([layout.size.width, layout.size.height]) } + + // Sync mode to LiteGraph node + if (liteNode.mode !== layout.mode) { + liteNode.changeMode(layout.mode) + } } // Trigger single redraw for all changes diff --git a/src/renderer/core/layout/types.ts b/src/renderer/core/layout/types.ts index 4332059f5e3..0ad001d1055 100644 --- a/src/renderer/core/layout/types.ts +++ b/src/renderer/core/layout/types.ts @@ -48,6 +48,7 @@ export interface NodeLayout { size: Size zIndex: number visible: boolean + mode: number // LGraphEventMode: 0=ALWAYS, 2=NEVER, 4=BYPASS, etc. // Computed bounds for hit testing bounds: Bounds } @@ -120,6 +121,7 @@ type OperationType = | 'moveNode' | 'resizeNode' | 'setNodeZIndex' + | 'setNodeMode' | 'createNode' | 'deleteNode' | 'setNodeVisibility' @@ -157,6 +159,15 @@ export interface SetNodeZIndexOperation extends NodeOpBase { previousZIndex: number } +/** + * Set node mode operation + */ +export interface SetNodeModeOperation extends NodeOpBase { + type: 'setNodeMode' + mode: number + previousMode: number +} + /** * Create node operation */ @@ -243,6 +254,7 @@ export type LayoutOperation = | MoveNodeOperation | ResizeNodeOperation | SetNodeZIndexOperation + | SetNodeModeOperation | CreateNodeOperation | DeleteNodeOperation | SetNodeVisibilityOperation diff --git a/src/renderer/core/layout/utils/layoutMath.test.ts b/src/renderer/core/layout/utils/layoutMath.test.ts index 9c1fe1b46a3..ccec019ecca 100644 --- a/src/renderer/core/layout/utils/layoutMath.test.ts +++ b/src/renderer/core/layout/utils/layoutMath.test.ts @@ -62,6 +62,7 @@ describe('layoutMath utils', () => { size: { width, height }, zIndex: 0, visible: true, + mode: 0, bounds: { x, y, width, height } }) diff --git a/src/renderer/core/layout/utils/mappers.ts b/src/renderer/core/layout/utils/mappers.ts index 48b85dc53fe..0aeaa00cb03 100644 --- a/src/renderer/core/layout/utils/mappers.ts +++ b/src/renderer/core/layout/utils/mappers.ts @@ -10,6 +10,7 @@ export const NODE_LAYOUT_DEFAULTS: NodeLayout = { size: { width: 100, height: 50 }, zIndex: 0, visible: true, + mode: 0, // LGraphEventMode.ALWAYS bounds: { x: 0, y: 0, width: 100, height: 50 } } @@ -20,6 +21,7 @@ export function layoutToYNode(layout: NodeLayout): NodeLayoutMap { ynode.set('size', layout.size) ynode.set('zIndex', layout.zIndex) ynode.set('visible', layout.visible) + ynode.set('mode', layout.mode) ynode.set('bounds', layout.bounds) return ynode } @@ -40,6 +42,7 @@ export function yNodeToLayout(ynode: NodeLayoutMap): NodeLayout { size: getOr(ynode, 'size', NODE_LAYOUT_DEFAULTS.size), zIndex: getOr(ynode, 'zIndex', NODE_LAYOUT_DEFAULTS.zIndex), visible: getOr(ynode, 'visible', NODE_LAYOUT_DEFAULTS.visible), + mode: getOr(ynode, 'mode', NODE_LAYOUT_DEFAULTS.mode), bounds: getOr(ynode, 'bounds', NODE_LAYOUT_DEFAULTS.bounds) } } diff --git a/src/renderer/extensions/minimap/data/MinimapDataSource.test.ts b/src/renderer/extensions/minimap/data/MinimapDataSource.test.ts index 50f9ebba0ef..2296edf7c7d 100644 --- a/src/renderer/extensions/minimap/data/MinimapDataSource.test.ts +++ b/src/renderer/extensions/minimap/data/MinimapDataSource.test.ts @@ -34,6 +34,7 @@ describe('MinimapDataSource', () => { size: { width: 100, height: 50 }, zIndex: 0, visible: true, + mode: 0, bounds: { x: 0, y: 0, width: 100, height: 50 } } ] diff --git a/src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.test.ts b/src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.test.ts index c3410051a08..f4d2e6c7322 100644 --- a/src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.test.ts +++ b/src/renderer/extensions/vueNodes/composables/useNodePointerInteractions.test.ts @@ -80,6 +80,7 @@ const mockData = vi.hoisted(() => { size: { width: 100, height: 100 }, zIndex: 1, visible: true, + mode: 0, bounds: { x: 0, y: 0,