From b59ef3efc6f8316a5776d7386ccb3dbe6357ae16 Mon Sep 17 00:00:00 2001 From: Diego Imbert <70353967+diegoimbert@users.noreply.github.com> Date: Thu, 15 Jan 2026 07:09:14 +0100 Subject: [PATCH] Fix suspend step duplicate forms (#7581) * nit totalEventsWaiting * remove temp console log * loading indicator in Resume button * refactor * Revert "refactor" This reverts commit eae6213cdd053dd5f858d38f3f477d484eb39052. * useThrottle * fix promises * Revert "fix promises" This reverts commit 90a56132458326097d88e57a851c1bbba75010f9. * svelte 5 migration * Fix duplicate resume forms * Check all flow_jobs --- .../lib/components/FlowPreviewResult.svelte | 10 ---- .../components/FlowStatusViewerInner.svelte | 58 +++++++++---------- .../FlowStatusWaitingForEvents.svelte | 54 ++++++++++------- 3 files changed, 58 insertions(+), 64 deletions(-) diff --git a/frontend/src/lib/components/FlowPreviewResult.svelte b/frontend/src/lib/components/FlowPreviewResult.svelte index 4796198e94..57cdbb8058 100644 --- a/frontend/src/lib/components/FlowPreviewResult.svelte +++ b/frontend/src/lib/components/FlowPreviewResult.svelte @@ -32,16 +32,6 @@ extra, result_streams }: Props = $props() - - // Sometimes the approval form is duplicated but I can't reproduce the issue - // This is a temporary debug log to try to catch it when it happens - // (See the #each below) - $effect(() => - console.log( - 'suspendStatusVal', - Object.entries(suspendStatus.val || {}).map(([k, v]) => [k, v.job.id]) - ) - ) diff --git a/frontend/src/lib/components/FlowStatusViewerInner.svelte b/frontend/src/lib/components/FlowStatusViewerInner.svelte index f78eed3117..9680c13ce5 100644 --- a/frontend/src/lib/components/FlowStatusViewerInner.svelte +++ b/frontend/src/lib/components/FlowStatusViewerInner.svelte @@ -49,6 +49,7 @@ import JobAssetsViewer from './assets/JobAssetsViewer.svelte' import McpToolCallDetails from './McpToolCallDetails.svelte' import { SelectionManager } from './graph/selectionUtils.svelte' + import { useThrottle } from 'runed' let { flowState: flowStateStore, @@ -503,8 +504,21 @@ } let jobMissingStartedAt: Record = {} - let lastSelectedLoopSwitch: number | undefined - let selectedLoopSwitchTimeout: number | undefined = undefined + + let setSelectedLoopSwitch = useThrottle(async (lastStarted: string, mod: FlowStatusModule) => { + let position = mod.flow_jobs?.indexOf(lastStarted) + if (!position) return + for (const flow_job of mod.flow_jobs ?? []) { + if (flow_job === lastStarted) { + break + } else if (flow_job !== lastStarted && suspendStatus.val[flow_job]) { + console.log('setSelectedLoopSwitch deleting suspend for', flow_job) + delete suspendStatus.val[flow_job] + } + } + console.log('setSelectedLoopSwitch', position, lastStarted, mod.id, suspendStatus) + setIteration(position, lastStarted, false, mod.id ?? '', true) + }, 2000) function updateInnerModules() { if (localModuleStates) { @@ -641,29 +655,7 @@ }) if (anySet) { updateDurationStatuses(key, nDurationStatuses) - selectedLoopSwitchTimeout && clearTimeout(selectedLoopSwitchTimeout) - function setSelectedLoopSwitch() { - if (lastStarted) { - let position = mod.flow_jobs?.indexOf(lastStarted) - if (position != undefined) { - lastSelectedLoopSwitch = new Date().getTime() - console.log('setSelectedLoopSwitch', position, lastStarted) - setIteration(position, lastStarted, false, mod.id ?? '', true) - } - } - } - - if ( - lastSelectedLoopSwitch && - new Date().getTime() - lastSelectedLoopSwitch < 3000 - ) { - selectedLoopSwitchTimeout = setTimeout(() => { - setSelectedLoopSwitch() - }, 2000) - } else { - console.log('setSelectedLoopSwitch') - setSelectedLoopSwitch() - } + if (lastStarted) setSelectedLoopSwitch(lastStarted, mod) } }) .catch((e) => { @@ -1293,6 +1285,10 @@ tabsHeight.graphHeight ) ) + + let totalEventsWaiting = $derived( + Object.values(suspendStatus?.val ?? {}).reduce((a, b) => a + (b?.nb ?? 0), 0) + ) @@ -1744,13 +1740,11 @@ {/if} {/each} - {#each Object.values(suspendStatus?.val ?? {}) as count} - {#if count.nb} - - Flow suspended, waiting for {count.nb} events - - {/if} - {/each} + {#if totalEventsWaiting} + + Flow suspended, waiting for {totalEventsWaiting} events + + {/if} { + job && untrack(() => getDefaultArgs()) + })
@@ -130,6 +138,7 @@
+
{#if job?.raw_flow?.modules?.[approvalStep]?.suspend?.resume_form?.schema} @@ -157,9 +167,9 @@
{/if} - The payload is optional, it is passed to the following step through the `resume` variable + + The payload is optional, it is passed to the following step through the `resume` variable + {:else} You cannot resume the flow yourself without receiving the resume secret since you are not an