diff --git a/src/composables/canvas/useSelectedLiteGraphItems.test.ts b/src/composables/canvas/useSelectedLiteGraphItems.test.ts index 8e16448f4..a8d0acdd3 100644 --- a/src/composables/canvas/useSelectedLiteGraphItems.test.ts +++ b/src/composables/canvas/useSelectedLiteGraphItems.test.ts @@ -276,7 +276,7 @@ describe('useSelectedLiteGraphItems', () => { expect(selectedNodes).toContainEqual(subNode2) }) - it('toggleSelectedNodesMode should apply unified state to subgraph children', () => { + it('toggleSelectedNodesMode should not apply 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 @@ -294,9 +294,8 @@ describe('useSelectedLiteGraphItems', () => { // regularNode: BYPASS -> NEVER (since BYPASS != NEVER) expect(regularNode.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 + // Subgraph children do not change state + expect(subNode1.mode).toBe(LGraphEventMode.ALWAYS) // was ALWAYS, stays ALWAYS expect(subNode2.mode).toBe(LGraphEventMode.NEVER) // was NEVER, stays NEVER }) @@ -317,9 +316,9 @@ describe('useSelectedLiteGraphItems', () => { // Selected subgraph should toggle to ALWAYS (since it was already NEVER) expect(subgraphNode.mode).toBe(LGraphEventMode.ALWAYS) - // All children should also get ALWAYS (unified with parent's new state) + // All children should be unchanged expect(subNode1.mode).toBe(LGraphEventMode.ALWAYS) - expect(subNode2.mode).toBe(LGraphEventMode.ALWAYS) + expect(subNode2.mode).toBe(LGraphEventMode.BYPASS) }) }) diff --git a/src/composables/canvas/useSelectedLiteGraphItems.ts b/src/composables/canvas/useSelectedLiteGraphItems.ts index a4a93b9fb..c7777d7af 100644 --- a/src/composables/canvas/useSelectedLiteGraphItems.ts +++ b/src/composables/canvas/useSelectedLiteGraphItems.ts @@ -2,10 +2,7 @@ import type { LGraphNode, Positionable } from '@/lib/litegraph/src/litegraph' import { LGraphEventMode, Reroute } from '@/lib/litegraph/src/litegraph' import { useCanvasStore } from '@/renderer/core/canvas/canvasStore' import { app } from '@/scripts/app' -import { - collectFromNodes, - traverseNodesDepthFirst -} from '@/utils/graphTraversalUtil' +import { collectFromNodes } from '@/utils/graphTraversalUtil' /** * Composable for handling selected LiteGraph items filtering and operations. @@ -97,16 +94,10 @@ export function useSelectedLiteGraphItems() { } /** - * Toggle the execution mode of all selected nodes with unified subgraph behavior. + * Toggle the execution mode of all selected nodes * - * Top-level behavior (selected nodes): Standard toggle logic - * - If the selected node is already in the specified mode → set to ALWAYS - * - Otherwise → set to the specified mode - * - * Subgraph behavior (children of selected subgraph nodes): Unified state application - * - All children inherit the same mode that their parent subgraph node was set to - * - This creates predictable behavior: if you toggle a subgraph to "mute", - * ALL nodes inside become muted, regardless of their previous individual states + * - If any nodes are not already the specified node mode → all are set to specified mode + * - Otherwise → set all nodes to ALWAYS * * @param mode - The LGraphEventMode to toggle to (e.g., NEVER for mute, BYPASS for bypass) */ @@ -124,27 +115,8 @@ export function useSelectedLiteGraphItems() { ) 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 - + for (const selectedNode of selectedNodeArray) selectedNode.mode = 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 - if (selectedNode.isSubgraphNode?.() && selectedNode.subgraph) { - traverseNodesDepthFirst([selectedNode], { - visitor: (node) => { - // Skip the parent node since we already handled it above - if (node === selectedNode) return undefined - - // Apply the parent's new mode to all children uniformly - node.mode = newModeForSelectedNode - return undefined - } - }) - } - }) } return { diff --git a/src/utils/executionUtil.ts b/src/utils/executionUtil.ts index 3f7f982c4..ea3e4e539 100644 --- a/src/utils/executionUtil.ts +++ b/src/utils/executionUtil.ts @@ -63,11 +63,18 @@ export const graphToPrompt = async ( ? new ExecutableGroupNodeDTO(node, [], nodeDtoMap) : new ExecutableNodeDTO(node, [], nodeDtoMap) + nodeDtoMap.set(dto.id, dto) + + if ( + node.mode === LGraphEventMode.NEVER || + node.mode === LGraphEventMode.BYPASS + ) { + continue + } + for (const innerNode of dto.getInnerNodes()) { nodeDtoMap.set(innerNode.id, innerNode) } - - nodeDtoMap.set(dto.id, dto) } const output: ComfyApiWorkflow = {}