diff --git a/packages/frontend/editor-ui/src/components/RunDataAi/utils.test.ts b/packages/frontend/editor-ui/src/components/RunDataAi/utils.test.ts index 649c317f5b..565a90f62e 100644 --- a/packages/frontend/editor-ui/src/components/RunDataAi/utils.test.ts +++ b/packages/frontend/editor-ui/src/components/RunDataAi/utils.test.ts @@ -389,6 +389,42 @@ describe(getTreeNodeData, () => { expect(rootNodeTree[0].children[0].runIndex).toBe(0); }); + it('should include nodes with source array without previous node', () => { + const workflow = createTestWorkflowObject({ + nodes: [createTestNode({ name: 'RootNode' }), createTestNode({ name: 'SubNode' })], + connections: { + SubNode: { + ai_tool: [[{ node: 'RootNode', type: NodeConnectionTypes.AiTool, index: 0 }]], + }, + }, + }); + + // Create test AI data with a node that has empty source array + const subNodeData = { + node: 'SubNode', + runIndex: 0, + data: { + data: [{ json: { result: 'from RootNode' } }], + inOut: 'output' as const, + type: NodeConnectionTypes.AiTool, + source: [null], // Array with null + metadata: { + executionTime: 100, + startTime: Date.parse('2025-02-26T00:00:01.000Z'), + subExecution: undefined, + }, + }, + }; + + // Create test AI data array + const aiData = [subNodeData]; + + const rootNodeTree = getTreeNodeData('RootNode', workflow, aiData); + + expect(rootNodeTree[0].children.length).toBe(1); + expect(rootNodeTree[0].children[0].node).toBe('SubNode'); + }); + it('should filter deeper nested nodes based on source', () => { const workflow = createTestWorkflowObject({ nodes: [ @@ -806,6 +842,28 @@ describe(getTreeNodeDataV2, () => { expect(rootNodeTree[0].children[0].runIndex).toBe(0); }); + it('should include nodes with source array without previous node (v2)', () => { + const workflow = createTestWorkflowObject({ + nodes: [createTestNode({ name: 'RootNode' }), createTestNode({ name: 'SubNode' })], + connections: { + SubNode: { + ai_tool: [[{ node: 'RootNode', type: NodeConnectionTypes.AiTool, index: 0 }]], + }, + }, + }); + + // Create test run data with source information + const runData = { + RootNode: [createTestTaskData({ executionIndex: 0 })], + SubNode: [createTestTaskData({ executionIndex: 1, source: [null] })], + }; + + const rootNodeTree = getTreeNodeDataV2('RootNode', runData.RootNode[0], workflow, runData); + + expect(rootNodeTree[0].children.length).toBe(1); + expect(rootNodeTree[0].children[0].node.name).toBe('SubNode'); + }); + it('should filter deeper nested nodes based on source (v2)', () => { const workflow = createTestWorkflowObject({ nodes: [ diff --git a/packages/frontend/editor-ui/src/components/RunDataAi/utils.ts b/packages/frontend/editor-ui/src/components/RunDataAi/utils.ts index b8ac4d4acd..90dcae9102 100644 --- a/packages/frontend/editor-ui/src/components/RunDataAi/utils.ts +++ b/packages/frontend/editor-ui/src/components/RunDataAi/utils.ts @@ -86,7 +86,7 @@ function getTreeNodeDataRec( const filteredAiData = currentDepth === 0 ? aiData?.filter(({ data }) => { - if (!data?.source || data.source.length === 0) { + if (!data?.source || data.source.every((source) => source === null)) { return true; } @@ -339,7 +339,7 @@ function getTreeNodeDataRecV2( // This prevents showing duplicate executions when a sub-node is connected to multiple parents // Only filter nodes that have source information with valid previousNode references const isMatched = - currentDepth === 0 && t.source?.length > 0 + currentDepth === 0 && t.source.some((source) => source !== null) ? t.source.some( (source) => source?.previousNode === node.name &&