Skip to content

Commit e271ed8

Browse files
authored
improvement(console): added iteration info to console entry for parallel/loop (#930)
1 parent 785b86a commit e271ed8

File tree

4 files changed

+144
-13
lines changed

4 files changed

+144
-13
lines changed

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/console/components/console-entry/console-entry.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,14 @@ export function ConsoleEntry({ entry, consoleWidth }: ConsoleEntryProps) {
417417
{entry.startedAt ? format(new Date(entry.startedAt), 'HH:mm:ss') : 'N/A'}
418418
</span>
419419
</div>
420+
{/* Iteration tag - only show if iteration context exists */}
421+
{entry.iterationCurrent !== undefined && entry.iterationTotal !== undefined && (
422+
<div className='flex h-5 items-center rounded-lg bg-secondary px-2'>
423+
<span className='font-normal text-muted-foreground text-xs leading-normal'>
424+
{entry.iterationCurrent}/{entry.iterationTotal}
425+
</span>
426+
</div>
427+
)}
420428
{/* Input/Output tags - only show if input data exists */}
421429
{hasInputData && (
422430
<>

apps/sim/executor/index.ts

Lines changed: 123 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1508,6 +1508,43 @@ export class Executor {
15081508
// Skip console logging for infrastructure blocks like loops and parallels
15091509
// For streaming blocks, we'll add the console entry after stream processing
15101510
if (block.metadata?.id !== BlockType.LOOP && block.metadata?.id !== BlockType.PARALLEL) {
1511+
// Determine iteration context for this block
1512+
let iterationCurrent: number | undefined
1513+
let iterationTotal: number | undefined
1514+
let iterationType: 'loop' | 'parallel' | undefined
1515+
const blockName = block.metadata?.name || 'Unnamed Block'
1516+
1517+
if (parallelInfo) {
1518+
// This is a parallel iteration
1519+
const parallelState = context.parallelExecutions?.get(parallelInfo.parallelId)
1520+
iterationCurrent = parallelInfo.iterationIndex + 1
1521+
iterationTotal = parallelState?.parallelCount
1522+
iterationType = 'parallel'
1523+
} else {
1524+
// Check if this block is inside a loop
1525+
const containingLoopId = this.resolver.loopsByBlockId?.get(block.id)
1526+
if (containingLoopId) {
1527+
const currentIteration = context.loopIterations.get(containingLoopId)
1528+
const loop = context.workflow?.loops?.[containingLoopId]
1529+
if (currentIteration !== undefined && loop) {
1530+
iterationCurrent = currentIteration
1531+
if (loop.loopType === 'forEach') {
1532+
// For forEach loops, get the total from the items
1533+
const forEachItems = context.loopItems.get(`${containingLoopId}_items`)
1534+
if (forEachItems) {
1535+
iterationTotal = Array.isArray(forEachItems)
1536+
? forEachItems.length
1537+
: Object.keys(forEachItems).length
1538+
}
1539+
} else {
1540+
// For regular loops, use the iterations count
1541+
iterationTotal = loop.iterations || 5
1542+
}
1543+
iterationType = 'loop'
1544+
}
1545+
}
1546+
}
1547+
15111548
addConsole({
15121549
input: blockLog.input,
15131550
output: blockLog.output,
@@ -1518,12 +1555,11 @@ export class Executor {
15181555
workflowId: context.workflowId,
15191556
blockId: parallelInfo ? blockId : block.id,
15201557
executionId: this.contextExtensions.executionId,
1521-
blockName: parallelInfo
1522-
? `${block.metadata?.name || 'Unnamed Block'} (iteration ${
1523-
parallelInfo.iterationIndex + 1
1524-
})`
1525-
: block.metadata?.name || 'Unnamed Block',
1558+
blockName,
15261559
blockType: block.metadata?.id || 'unknown',
1560+
iterationCurrent,
1561+
iterationTotal,
1562+
iterationType,
15271563
})
15281564
}
15291565

@@ -1578,6 +1614,43 @@ export class Executor {
15781614

15791615
// Skip console logging for infrastructure blocks like loops and parallels
15801616
if (block.metadata?.id !== BlockType.LOOP && block.metadata?.id !== BlockType.PARALLEL) {
1617+
// Determine iteration context for this block
1618+
let iterationCurrent: number | undefined
1619+
let iterationTotal: number | undefined
1620+
let iterationType: 'loop' | 'parallel' | undefined
1621+
const blockName = block.metadata?.name || 'Unnamed Block'
1622+
1623+
if (parallelInfo) {
1624+
// This is a parallel iteration
1625+
const parallelState = context.parallelExecutions?.get(parallelInfo.parallelId)
1626+
iterationCurrent = parallelInfo.iterationIndex + 1
1627+
iterationTotal = parallelState?.parallelCount
1628+
iterationType = 'parallel'
1629+
} else {
1630+
// Check if this block is inside a loop
1631+
const containingLoopId = this.resolver.getContainingLoopId(block.id)
1632+
if (containingLoopId) {
1633+
const currentIteration = context.loopIterations.get(containingLoopId)
1634+
const loop = context.workflow?.loops?.[containingLoopId]
1635+
if (currentIteration !== undefined && loop) {
1636+
iterationCurrent = currentIteration
1637+
if (loop.loopType === 'forEach') {
1638+
// For forEach loops, get the total from the items
1639+
const forEachItems = context.loopItems.get(`${containingLoopId}_items`)
1640+
if (forEachItems) {
1641+
iterationTotal = Array.isArray(forEachItems)
1642+
? forEachItems.length
1643+
: Object.keys(forEachItems).length
1644+
}
1645+
} else {
1646+
// For regular loops, use the iterations count
1647+
iterationTotal = loop.iterations || 5
1648+
}
1649+
iterationType = 'loop'
1650+
}
1651+
}
1652+
}
1653+
15811654
addConsole({
15821655
input: blockLog.input,
15831656
output: blockLog.output,
@@ -1588,12 +1661,11 @@ export class Executor {
15881661
workflowId: context.workflowId,
15891662
blockId: parallelInfo ? blockId : block.id,
15901663
executionId: this.contextExtensions.executionId,
1591-
blockName: parallelInfo
1592-
? `${block.metadata?.name || 'Unnamed Block'} (iteration ${
1593-
parallelInfo.iterationIndex + 1
1594-
})`
1595-
: block.metadata?.name || 'Unnamed Block',
1664+
blockName,
15961665
blockType: block.metadata?.id || 'unknown',
1666+
iterationCurrent,
1667+
iterationTotal,
1668+
iterationType,
15971669
})
15981670
}
15991671

@@ -1649,6 +1721,43 @@ export class Executor {
16491721

16501722
// Skip console logging for infrastructure blocks like loops and parallels
16511723
if (block.metadata?.id !== BlockType.LOOP && block.metadata?.id !== BlockType.PARALLEL) {
1724+
// Determine iteration context for this block
1725+
let iterationCurrent: number | undefined
1726+
let iterationTotal: number | undefined
1727+
let iterationType: 'loop' | 'parallel' | undefined
1728+
const blockName = block.metadata?.name || 'Unnamed Block'
1729+
1730+
if (parallelInfo) {
1731+
// This is a parallel iteration
1732+
const parallelState = context.parallelExecutions?.get(parallelInfo.parallelId)
1733+
iterationCurrent = parallelInfo.iterationIndex + 1
1734+
iterationTotal = parallelState?.parallelCount
1735+
iterationType = 'parallel'
1736+
} else {
1737+
// Check if this block is inside a loop
1738+
const containingLoopId = this.resolver.getContainingLoopId(block.id)
1739+
if (containingLoopId) {
1740+
const currentIteration = context.loopIterations.get(containingLoopId)
1741+
const loop = context.workflow?.loops?.[containingLoopId]
1742+
if (currentIteration !== undefined && loop) {
1743+
iterationCurrent = currentIteration
1744+
if (loop.loopType === 'forEach') {
1745+
// For forEach loops, get the total from the items
1746+
const forEachItems = context.loopItems.get(`${containingLoopId}_items`)
1747+
if (forEachItems) {
1748+
iterationTotal = Array.isArray(forEachItems)
1749+
? forEachItems.length
1750+
: Object.keys(forEachItems).length
1751+
}
1752+
} else {
1753+
// For regular loops, use the iterations count
1754+
iterationTotal = loop.iterations || 5
1755+
}
1756+
iterationType = 'loop'
1757+
}
1758+
}
1759+
}
1760+
16521761
addConsole({
16531762
input: blockLog.input,
16541763
output: {},
@@ -1662,10 +1771,11 @@ export class Executor {
16621771
workflowId: context.workflowId,
16631772
blockId: parallelInfo ? blockId : block.id,
16641773
executionId: this.contextExtensions.executionId,
1665-
blockName: parallelInfo
1666-
? `${block.metadata?.name || 'Unnamed Block'} (iteration ${parallelInfo.iterationIndex + 1})`
1667-
: block.metadata?.name || 'Unnamed Block',
1774+
blockName,
16681775
blockType: block.metadata?.id || 'unknown',
1776+
iterationCurrent,
1777+
iterationTotal,
1778+
iterationType,
16691779
})
16701780
}
16711781

apps/sim/executor/resolver/resolver.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1845,4 +1845,13 @@ export class InputResolver {
18451845

18461846
return value
18471847
}
1848+
1849+
/**
1850+
* Get the containing loop ID for a block
1851+
* @param blockId - The ID of the block
1852+
* @returns The containing loop ID or undefined if not in a loop
1853+
*/
1854+
getContainingLoopId(blockId: string): string | undefined {
1855+
return this.loopsByBlockId.get(blockId)
1856+
}
18481857
}

apps/sim/stores/panel/console/types.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ export interface ConsoleEntry {
1616
input?: any
1717
error?: string
1818
warning?: string
19+
// Iteration context for loops and parallels
20+
iterationCurrent?: number
21+
iterationTotal?: number
22+
iterationType?: 'loop' | 'parallel'
1923
}
2024

2125
export interface ConsoleUpdate {

0 commit comments

Comments
 (0)