Portal Community

RunProgress Shape

export interface RunProgress {
    totalNodes     : number;  // Count of nodes in the workflow graph
    completedNodes : number;  // Nodes with status: success | failed | skipped
    failedNodes    : number;  // Nodes with status: failed
    progressPct    : number;  // completedNodes / totalNodes * 100 (0–100)
}

// Initial value (before run starts):
{ totalNodes: 0, completedNodes: 0, failedNodes: 0, progressPct: 0 }

updateRunProgress Action

updateRunProgress: (progress: RunProgress) => void

// Called on each NodeStatusChanged event when status is terminal
function recalculateProgress() {
    const { nodeStatuses } = useDesignerModeStore.getState();
    const { nodes } = useWorkflowStore.getState();

    const completed = Object.values(nodeStatuses).filter(
        s => ['success', 'failed', 'skipped'].includes(s.status)
    ).length;

    const failed = Object.values(nodeStatuses).filter(
        s => s.status === 'failed'
    ).length;

    useDesignerModeStore.getState().updateRunProgress({
        totalNodes    : nodes.length,
        completedNodes: completed,
        failedNodes   : failed,
        progressPct   : nodes.length > 0 ? (completed / nodes.length) * 100 : 0
    });
}

Progress Bar Component

// CanvasToolbar.tsx — progress bar in execution mode
function ExecutionProgressBar() {
    const { runProgress, currentMode } = useDesignerModeStore(
        state => ({ runProgress: state.runProgress, currentMode: state.currentMode }),
        shallow
    );

    if (currentMode !== 'execution') return null;

    return (
        <div className="progress-bar">
            <div
                className="progress-fill"
                style={{ width: `${runProgress.progressPct}%` }}
            />
            <span>{runProgress.completedNodes} / {runProgress.totalNodes} nodes</span>
            {runProgress.failedNodes > 0 &&
                <span className="failed-badge">{runProgress.failedNodes} failed</span>}
        </div>
    );
}

Suspended Nodes and Progress

Nodes in suspended status (HIL waiting) are NOT counted as completed. The progress bar shows partial completion while a HIL node waits for human input. When the actor responds and the node completes, the count updates.