Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -108,26 +108,24 @@ export function getLeftmostBlockId(workflowState: WorkflowState | null | undefin
/** Execution status for edges/nodes in the preview */
type ExecutionStatus = 'success' | 'error' | 'not-executed'

/** Calculates absolute position, handling nested subflows. */
function calculateAbsolutePosition(
/** Calculates nesting depth, handling nested subflows. */
function calculateNestingDepth(
block: BlockState,
blocks: Record<string, BlockState>
): { x: number; y: number } {
if (!block.data?.parentId) {
return block.position
}

const parentBlock = blocks[block.data.parentId]
blocks: Record<string, BlockState>,
visited: Set<string> = new Set()
): number {
const parentId = block.data?.parentId
if (!parentId) return 0
if (visited.has(parentId)) return 0

const parentBlock = blocks[parentId]
if (!parentBlock) {
logger.warn(`Parent block not found for child block`)
return block.position
logger.warn('Parent block not found for child block')
return 0
}

const parentAbsolutePosition = calculateAbsolutePosition(parentBlock, blocks)
return {
x: parentAbsolutePosition.x + block.position.x,
y: parentAbsolutePosition.y + block.position.y,
}
visited.add(parentId)
return 1 + calculateNestingDepth(parentBlock, blocks, visited)
}

interface PreviewWorkflowProps {
Expand Down Expand Up @@ -329,7 +327,8 @@ export function PreviewWorkflow({

if (childStatuses.length === 0) return undefined
if (childStatuses.some((s) => s === 'error')) return 'error'
return 'success'
if (childStatuses.every((s) => s === 'success')) return 'success'
return undefined
}
return derive
}, [subflowChildrenMap, blockExecutionMap, workflowState.blocks])
Expand Down Expand Up @@ -367,13 +366,20 @@ export function PreviewWorkflow({

const nodeArray: Node[] = []

Object.entries(workflowState.blocks || {}).forEach(([blockId, block]) => {
const sortedBlocks = Object.entries(workflowState.blocks || {}).sort(
([, left], [, right]) =>
calculateNestingDepth(left, workflowState.blocks) -
calculateNestingDepth(right, workflowState.blocks)
)

sortedBlocks.forEach(([blockId, block]) => {
if (!block || !block.type) {
logger.warn(`Skipping invalid block: ${blockId}`)
return
}

const absolutePosition = calculateAbsolutePosition(block, workflowState.blocks)
const parentId = block.data?.parentId
const nestingDepth = calculateNestingDepth(block, workflowState.blocks)

if (block.type === 'loop' || block.type === 'parallel') {
const isSelected = selectedBlockId === blockId
Expand All @@ -391,9 +397,14 @@ export function PreviewWorkflow({
nodeArray.push({
id: blockId,
type: 'subflowNode',
position: absolutePosition,
position: block.position,
parentId,
extent: block.data?.extent || undefined,
draggable: false,
zIndex: nestingDepth,
className: parentId ? 'nested-subflow-node' : undefined,
data: {
...block.data,
name: block.name,
width: dimensions.width,
height: dimensions.height,
Expand Down Expand Up @@ -430,9 +441,11 @@ export function PreviewWorkflow({
nodeArray.push({
id: blockId,
type: nodeType,
position: absolutePosition,
position: block.position,
parentId,
extent: block.data?.extent || undefined,
draggable: false,
zIndex: block.data?.parentId ? 10 : undefined,
zIndex: parentId ? 1000 : undefined,
data: {
type: block.type,
name: block.name,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ interface BlockExecutionData {
childWorkflowSnapshotId?: string
}

function isPauseOutput(output: unknown): boolean {
return (
output !== null &&
typeof output === 'object' &&
'_pauseMetadata' in output &&
(output as Record<string, unknown>)._pauseMetadata !== undefined
)
}

/** Represents a level in the workflow navigation stack */
interface WorkflowStackEntry {
workflowState: WorkflowState
Expand Down Expand Up @@ -91,7 +100,7 @@ export function buildBlockExecutions(spans: TraceSpan[]): Record<string, BlockEx
blockExecutionMap[span.blockId] = {
input: redactApiKeys(span.input || {}),
output: redactApiKeys(span.output || {}),
status: span.status || 'unknown',
status: isPauseOutput(span.output) ? 'pending' : span.status || 'unknown',
durationMs: span.duration || 0,
children: span.children,
childWorkflowSnapshotId: span.childWorkflowSnapshotId,
Expand Down
14 changes: 14 additions & 0 deletions apps/sim/executor/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,20 @@ export const EDGE = {
DEFAULT: 'default',
} as const

export const SUBFLOW_CONTROL_EDGE_HANDLES = new Set<string>([
EDGE.LOOP_CONTINUE,
EDGE.LOOP_CONTINUE_ALT,
EDGE.LOOP_EXIT,
EDGE.PARALLEL_CONTINUE,
EDGE.PARALLEL_EXIT,
])

export const CONTROL_BACK_EDGE_HANDLES = new Set<string>([
EDGE.LOOP_CONTINUE,
EDGE.LOOP_CONTINUE_ALT,
EDGE.PARALLEL_CONTINUE,
])

export const LOOP = {
TYPE: {
FOR: 'for' as LoopType,
Expand Down
Loading
Loading