From e271ed86b63e4227ac7a07c8693fd391c988a209 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Sun, 10 Aug 2025 16:27:39 -0700 Subject: [PATCH] improvement(console): added iteration info to console entry for parallel/loop (#930) --- .../console-entry/console-entry.tsx | 8 ++ apps/sim/executor/index.ts | 136 ++++++++++++++++-- apps/sim/executor/resolver/resolver.ts | 9 ++ apps/sim/stores/panel/console/types.ts | 4 + 4 files changed, 144 insertions(+), 13 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/console/components/console-entry/console-entry.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/console/components/console-entry/console-entry.tsx index d9ef4fa7dc..ab93278422 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/console/components/console-entry/console-entry.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/console/components/console-entry/console-entry.tsx @@ -417,6 +417,14 @@ export function ConsoleEntry({ entry, consoleWidth }: ConsoleEntryProps) { {entry.startedAt ? format(new Date(entry.startedAt), 'HH:mm:ss') : 'N/A'} + {/* Iteration tag - only show if iteration context exists */} + {entry.iterationCurrent !== undefined && entry.iterationTotal !== undefined && ( +
+ + {entry.iterationCurrent}/{entry.iterationTotal} + +
+ )} {/* Input/Output tags - only show if input data exists */} {hasInputData && ( <> diff --git a/apps/sim/executor/index.ts b/apps/sim/executor/index.ts index 09410595fb..f5ee9d63f3 100644 --- a/apps/sim/executor/index.ts +++ b/apps/sim/executor/index.ts @@ -1508,6 +1508,43 @@ export class Executor { // Skip console logging for infrastructure blocks like loops and parallels // For streaming blocks, we'll add the console entry after stream processing if (block.metadata?.id !== BlockType.LOOP && block.metadata?.id !== BlockType.PARALLEL) { + // Determine iteration context for this block + let iterationCurrent: number | undefined + let iterationTotal: number | undefined + let iterationType: 'loop' | 'parallel' | undefined + const blockName = block.metadata?.name || 'Unnamed Block' + + if (parallelInfo) { + // This is a parallel iteration + const parallelState = context.parallelExecutions?.get(parallelInfo.parallelId) + iterationCurrent = parallelInfo.iterationIndex + 1 + iterationTotal = parallelState?.parallelCount + iterationType = 'parallel' + } else { + // Check if this block is inside a loop + const containingLoopId = this.resolver.loopsByBlockId?.get(block.id) + if (containingLoopId) { + const currentIteration = context.loopIterations.get(containingLoopId) + const loop = context.workflow?.loops?.[containingLoopId] + if (currentIteration !== undefined && loop) { + iterationCurrent = currentIteration + if (loop.loopType === 'forEach') { + // For forEach loops, get the total from the items + const forEachItems = context.loopItems.get(`${containingLoopId}_items`) + if (forEachItems) { + iterationTotal = Array.isArray(forEachItems) + ? forEachItems.length + : Object.keys(forEachItems).length + } + } else { + // For regular loops, use the iterations count + iterationTotal = loop.iterations || 5 + } + iterationType = 'loop' + } + } + } + addConsole({ input: blockLog.input, output: blockLog.output, @@ -1518,12 +1555,11 @@ export class Executor { workflowId: context.workflowId, blockId: parallelInfo ? blockId : block.id, executionId: this.contextExtensions.executionId, - blockName: parallelInfo - ? `${block.metadata?.name || 'Unnamed Block'} (iteration ${ - parallelInfo.iterationIndex + 1 - })` - : block.metadata?.name || 'Unnamed Block', + blockName, blockType: block.metadata?.id || 'unknown', + iterationCurrent, + iterationTotal, + iterationType, }) } @@ -1578,6 +1614,43 @@ export class Executor { // Skip console logging for infrastructure blocks like loops and parallels if (block.metadata?.id !== BlockType.LOOP && block.metadata?.id !== BlockType.PARALLEL) { + // Determine iteration context for this block + let iterationCurrent: number | undefined + let iterationTotal: number | undefined + let iterationType: 'loop' | 'parallel' | undefined + const blockName = block.metadata?.name || 'Unnamed Block' + + if (parallelInfo) { + // This is a parallel iteration + const parallelState = context.parallelExecutions?.get(parallelInfo.parallelId) + iterationCurrent = parallelInfo.iterationIndex + 1 + iterationTotal = parallelState?.parallelCount + iterationType = 'parallel' + } else { + // Check if this block is inside a loop + const containingLoopId = this.resolver.getContainingLoopId(block.id) + if (containingLoopId) { + const currentIteration = context.loopIterations.get(containingLoopId) + const loop = context.workflow?.loops?.[containingLoopId] + if (currentIteration !== undefined && loop) { + iterationCurrent = currentIteration + if (loop.loopType === 'forEach') { + // For forEach loops, get the total from the items + const forEachItems = context.loopItems.get(`${containingLoopId}_items`) + if (forEachItems) { + iterationTotal = Array.isArray(forEachItems) + ? forEachItems.length + : Object.keys(forEachItems).length + } + } else { + // For regular loops, use the iterations count + iterationTotal = loop.iterations || 5 + } + iterationType = 'loop' + } + } + } + addConsole({ input: blockLog.input, output: blockLog.output, @@ -1588,12 +1661,11 @@ export class Executor { workflowId: context.workflowId, blockId: parallelInfo ? blockId : block.id, executionId: this.contextExtensions.executionId, - blockName: parallelInfo - ? `${block.metadata?.name || 'Unnamed Block'} (iteration ${ - parallelInfo.iterationIndex + 1 - })` - : block.metadata?.name || 'Unnamed Block', + blockName, blockType: block.metadata?.id || 'unknown', + iterationCurrent, + iterationTotal, + iterationType, }) } @@ -1649,6 +1721,43 @@ export class Executor { // Skip console logging for infrastructure blocks like loops and parallels if (block.metadata?.id !== BlockType.LOOP && block.metadata?.id !== BlockType.PARALLEL) { + // Determine iteration context for this block + let iterationCurrent: number | undefined + let iterationTotal: number | undefined + let iterationType: 'loop' | 'parallel' | undefined + const blockName = block.metadata?.name || 'Unnamed Block' + + if (parallelInfo) { + // This is a parallel iteration + const parallelState = context.parallelExecutions?.get(parallelInfo.parallelId) + iterationCurrent = parallelInfo.iterationIndex + 1 + iterationTotal = parallelState?.parallelCount + iterationType = 'parallel' + } else { + // Check if this block is inside a loop + const containingLoopId = this.resolver.getContainingLoopId(block.id) + if (containingLoopId) { + const currentIteration = context.loopIterations.get(containingLoopId) + const loop = context.workflow?.loops?.[containingLoopId] + if (currentIteration !== undefined && loop) { + iterationCurrent = currentIteration + if (loop.loopType === 'forEach') { + // For forEach loops, get the total from the items + const forEachItems = context.loopItems.get(`${containingLoopId}_items`) + if (forEachItems) { + iterationTotal = Array.isArray(forEachItems) + ? forEachItems.length + : Object.keys(forEachItems).length + } + } else { + // For regular loops, use the iterations count + iterationTotal = loop.iterations || 5 + } + iterationType = 'loop' + } + } + } + addConsole({ input: blockLog.input, output: {}, @@ -1662,10 +1771,11 @@ export class Executor { workflowId: context.workflowId, blockId: parallelInfo ? blockId : block.id, executionId: this.contextExtensions.executionId, - blockName: parallelInfo - ? `${block.metadata?.name || 'Unnamed Block'} (iteration ${parallelInfo.iterationIndex + 1})` - : block.metadata?.name || 'Unnamed Block', + blockName, blockType: block.metadata?.id || 'unknown', + iterationCurrent, + iterationTotal, + iterationType, }) } diff --git a/apps/sim/executor/resolver/resolver.ts b/apps/sim/executor/resolver/resolver.ts index 6c82957b3d..7d7ced33c1 100644 --- a/apps/sim/executor/resolver/resolver.ts +++ b/apps/sim/executor/resolver/resolver.ts @@ -1845,4 +1845,13 @@ export class InputResolver { return value } + + /** + * Get the containing loop ID for a block + * @param blockId - The ID of the block + * @returns The containing loop ID or undefined if not in a loop + */ + getContainingLoopId(blockId: string): string | undefined { + return this.loopsByBlockId.get(blockId) + } } diff --git a/apps/sim/stores/panel/console/types.ts b/apps/sim/stores/panel/console/types.ts index 4d1c0f693e..9059af82a2 100644 --- a/apps/sim/stores/panel/console/types.ts +++ b/apps/sim/stores/panel/console/types.ts @@ -16,6 +16,10 @@ export interface ConsoleEntry { input?: any error?: string warning?: string + // Iteration context for loops and parallels + iterationCurrent?: number + iterationTotal?: number + iterationType?: 'loop' | 'parallel' } export interface ConsoleUpdate {