From cc141effa3b1019f70f4b7230fe7ebc7017632a0 Mon Sep 17 00:00:00 2001 From: Diego Imbert <70353967+diegoimbert@users.noreply.github.com> Date: Wed, 20 May 2026 11:54:09 +0200 Subject: [PATCH] fix(frontend): flow progress bar for early-stop completion and error handler (WIN-1961) (#9254) Two FlowProgressBar bugs: 1. stop_after_if (without 'label as skipped') ends the flow with step < modules.length, leaving the bar at <100% with a spinner. 2. failure_module execution drives step past modules.length, so the bar overflows past 100% and never reflects the error. The fix clamps progress to the failed module when the error handler runs, and forces 100% Done when the flow completed successfully but stopped early. Co-authored-by: Claude Opus 4.7 (1M context) --- .../components/flows/FlowProgressBar.svelte | 33 +++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/frontend/src/lib/components/flows/FlowProgressBar.svelte b/frontend/src/lib/components/flows/FlowProgressBar.svelte index c7d7198856..d31c1cae97 100644 --- a/frontend/src/lib/components/flows/FlowProgressBar.svelte +++ b/frontend/src/lib/components/flows/FlowProgressBar.svelte @@ -58,6 +58,22 @@ let newCurrentStepId: string | undefined = undefined let newIsWaitingForEvents = false + // Error handler (failure_module) was triggered: backend sets step >= modules.length + // and runs the failure_module. Clamp progress to the failed module so the bar shows + // the error indicator at the correct position instead of overflowing past 100%. + if ( + maxDone >= modules.length && + job?.flow_status?.failure_module?.type !== 'WaitingForPriorSteps' + ) { + const failedIdx = modules.findIndex((m) => m?.type === 'Failure') + if (failedIdx >= 0) { + newError = failedIdx + maxDone = failedIdx + 1 + } else { + maxDone = modules.length + } + } + if (modules.length > maxDone) { const nextModule = modules[maxDone] if (nextModule.type === 'InProgress') { @@ -110,12 +126,25 @@ subLength = subStepLength ? Math.max(subStepLength, 1) : undefined subIndex = subStepIndex length = Math.max(modules.length, 1) - index = maxDone + const newIsSkipped = 'is_skipped' in job && Boolean(job.is_skipped) + // Early-stop completion: stop_after_if (without 'label as skipped') ends the flow + // with step < modules.length. Without this, the bar stays at < 100% with 'Running'. + if ( + 'success' in job && + job.success === true && + !newIsSkipped && + newError === undefined && + maxDone < modules.length + ) { + index = modules.length + } else { + index = maxDone + } nextInProgress = newNextInProgress currentStepId = newCurrentStepId isWaitingForEvents = newIsWaitingForEvents isCanceled = job?.canceled || false - isSkipped = 'is_skipped' in job && Boolean(job.is_skipped) + isSkipped = newIsSkipped } export function reset() {