Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 8 additions & 16 deletions src/stores/executionStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@ import { isCloud } from '@/platform/distribution/types'
import { useTelemetry } from '@/platform/telemetry'
import type { ComfyWorkflow } from '@/platform/workflow/management/stores/workflowStore'
import { useWorkflowStore } from '@/platform/workflow/management/stores/workflowStore'
import type {
ComfyNode,
ComfyWorkflowJSON,
NodeId
} from '@/platform/workflow/validation/schemas/workflowSchema'
import type { NodeId } from '@/platform/workflow/validation/schemas/workflowSchema'
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
import type {
ExecutedWsMessage,
Expand Down Expand Up @@ -194,20 +190,16 @@ export const useExecutionStore = defineStore('execution', () => {
)

// For backward compatibility - returns the primary executing node
const executingNode = computed<ComfyNode | null>(() => {
const executingNode = computed(() => {
if (!executingNodeId.value) return null

const workflow: ComfyWorkflow | undefined = activePrompt.value?.workflow
if (!workflow) return null

const canvasState: ComfyWorkflowJSON | null =
workflow.changeTracker?.activeState ?? null
if (!canvasState) return null

return (
canvasState.nodes.find((n) => String(n.id) === executingNodeId.value) ??
null
// Use getNodeByExecutionId to find nodes even in subgraphs
// executingNodeId may be a simple ID like "123" or a hierarchical ID like "123:456"
const node = getNodeByExecutionId(
app.rootGraph,
String(executingNodeId.value)
)
return node ?? null
})

// This is the progress of the currently executing node (for backward compatibility)
Expand Down
106 changes: 106 additions & 0 deletions tests-ui/tests/store/executionStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
import { app } from '@/scripts/app'
import { useExecutionStore } from '@/stores/executionStore'

import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
import {
createTestSubgraph,
createTestSubgraphNode
} from '../litegraph/subgraph/fixtures/subgraphHelpers'

// Create mock functions that will be shared
const mockNodeExecutionIdToNodeLocatorId = vi.fn()
const mockNodeIdToNodeLocatorId = vi.fn()
Expand Down Expand Up @@ -297,3 +303,103 @@ describe('useExecutionStore - Node Error Lookups', () => {
})
})
})

describe('useExecutionStore - executingNode with subgraphs', () => {
let store: ReturnType<typeof useExecutionStore>

beforeEach(() => {
vi.clearAllMocks()
setActivePinia(createPinia())
store = useExecutionStore()
})

it('should find executing node in root graph', () => {
const mockNode = {
id: '123',
title: 'Test Node',
type: 'TestNode'
} as LGraphNode

vi.mocked(app.rootGraph.getNodeById).mockReturnValue(mockNode)

// Simulate node execution starting
store.nodeProgressStates = {
'123': {
state: 'running',
value: 0,
max: 100,
display_node_id: '123',
prompt_id: 'test-prompt',
node_id: '123'
}
}

expect(store.executingNode).toBe(mockNode)
})

it('should find executing node in subgraph using execution ID', () => {
const mockNodeInSubgraph = {
id: '789',
title: 'Nested Node',
type: 'NestedNode'
} as LGraphNode

// Create a real subgraph with the test helper
const testSubgraph = createTestSubgraph({
id: 'sub-uuid'
})
// Add the mock node to the subgraph
testSubgraph.add(mockNodeInSubgraph)

// Create a subgraph node using the helper
const mockSubgraphNode = createTestSubgraphNode(testSubgraph, {
id: '456'
})

// Mock the subgraph's getNodeById to return our mock node
vi.spyOn(testSubgraph, 'getNodeById').mockImplementation(
(id: string | number | null | undefined) =>
id === '789' ? mockNodeInSubgraph : null
)

vi.mocked(app.rootGraph.getNodeById).mockReturnValue(mockSubgraphNode)

// Simulate node execution in subgraph with hierarchical execution ID "456:789"
store.nodeProgressStates = {
'456:789': {
state: 'running',
value: 0,
max: 100,
display_node_id: '456:789',
prompt_id: 'test-prompt',
node_id: '456:789'
}
}

// The executingNode should resolve to the nested node
expect(store.executingNode).toBe(mockNodeInSubgraph)
})

it('should return null when no node is executing', () => {
store.nodeProgressStates = {}

expect(store.executingNode).toBeNull()
})

it('should return null when executing node cannot be found', () => {
vi.mocked(app.rootGraph.getNodeById).mockReturnValue(null)

store.nodeProgressStates = {
'999': {
state: 'running',
value: 0,
max: 100,
display_node_id: '999',
prompt_id: 'test-prompt',
node_id: '999'
}
}

expect(store.executingNode).toBeNull()
})
})