From 145b061c7889541681db06fa2dbd38b1412401b0 Mon Sep 17 00:00:00 2001 From: Dariusz L Date: Sat, 6 Jun 2026 02:06:09 +0200 Subject: [PATCH] fix: improve workflow change detection and graph signature stale checks - Patch app.loadGraphData to dispatch custom event after loading, ensuring workflow handlers fire when switching active workflow - Add document-click handler to catch workflow changes initiated by clicks - Pass event options through removeEventListener for proper cleanup - Detect possible pending graph switch on document-click and reduce max refresh attempts from 8 to 3 to avoid stale graph timers --- web/resolver/model_resolver.js | 38 ++++++++++++++++++-- web/resolver/shell/workflow_state_methods.js | 9 ++++- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/web/resolver/model_resolver.js b/web/resolver/model_resolver.js index 73db7c2..8171abc 100644 --- a/web/resolver/model_resolver.js +++ b/web/resolver/model_resolver.js @@ -193,8 +193,8 @@ export class ModelResolver { setupActiveWorkflowChangeListeners() { if (window.__ModelResolverWorkflowChangeHandlers) { - for (const { target, event, handler } of window.__ModelResolverWorkflowChangeHandlers) { - target?.removeEventListener?.(event, handler); + for (const { target, event, handler, options } of window.__ModelResolverWorkflowChangeHandlers) { + target?.removeEventListener?.(event, handler, options); } } @@ -214,11 +214,41 @@ export class ModelResolver { window.__ModelResolverHistoryPatched = true; } + if (!window.__ModelResolverLoadGraphDataPatched && typeof app.loadGraphData === 'function') { + const originalLoadGraphData = app.loadGraphData; + app.loadGraphData = function(...args) { + const result = originalLoadGraphData.apply(this, args); + Promise.resolve(result).then(() => { + setTimeout(() => { + window.dispatchEvent(new Event('model-resolver-active-workflowchange')); + }, 0); + }, () => { + setTimeout(() => { + window.dispatchEvent(new Event('model-resolver-active-workflowchange')); + }, 0); + }); + return result; + }; + window.__ModelResolverLoadGraphDataPatched = true; + } + window.__ModelResolverWorkflowChangeOwner = this; const routeHandler = () => { window.__ModelResolverWorkflowChangeOwner?.handleActiveWorkflowRouteChange('route-change'); }; + const activeWorkflowHandler = () => { + window.__ModelResolverWorkflowChangeOwner?.handleActiveWorkflowRouteChange('active-workflow-change'); + }; + const documentClickHandler = (event) => { + const owner = window.__ModelResolverWorkflowChangeOwner; + if (!owner?.dialog?.isVisible()) return; + + const target = event.target instanceof Element ? event.target : null; + if (target?.closest('#model-resolver-modal, .model-resolver-backdrop')) return; + + owner.handleActiveWorkflowRouteChange('document-click'); + }; const focusHandler = () => { window.__ModelResolverWorkflowChangeOwner?.handleActiveWorkflowRouteChange('window-focus'); }; @@ -231,6 +261,8 @@ export class ModelResolver { window.addEventListener('hashchange', routeHandler); window.addEventListener('popstate', routeHandler); window.addEventListener('model-resolver-locationchange', routeHandler); + window.addEventListener('model-resolver-active-workflowchange', activeWorkflowHandler); + document.addEventListener('click', documentClickHandler, true); window.addEventListener('focus', focusHandler); document.addEventListener('visibilitychange', visibilityHandler); @@ -238,6 +270,8 @@ export class ModelResolver { { target: window, event: 'hashchange', handler: routeHandler }, { target: window, event: 'popstate', handler: routeHandler }, { target: window, event: 'model-resolver-locationchange', handler: routeHandler }, + { target: window, event: 'model-resolver-active-workflowchange', handler: activeWorkflowHandler }, + { target: document, event: 'click', handler: documentClickHandler, options: true }, { target: window, event: 'focus', handler: focusHandler }, { target: document, event: 'visibilitychange', handler: visibilityHandler } ]; diff --git a/web/resolver/shell/workflow_state_methods.js b/web/resolver/shell/workflow_state_methods.js index 72a4c2b..118770a 100644 --- a/web/resolver/shell/workflow_state_methods.js +++ b/web/resolver/shell/workflow_state_methods.js @@ -28,6 +28,7 @@ export const workflowStateMethods = { }, getWorkflowScopedQueueKey(route = this.activeWorkflowRouteKey, signature = this.activeWorkflowSignature) { + if (route && signature) return `${route}\n${signature}`; return route || signature || null; }, @@ -216,8 +217,14 @@ export const workflowStateMethods = { const routeChanged = currentRoute !== this.activeWorkflowRouteKey; const signatureChanged = signature && signature !== this.activeWorkflowSignature; const graphStillLooksOld = routeChanged && previousSignature && signature === previousSignature; + const possiblePendingGraphSwitch = ( + reason === 'document-click' && + previousSignature && + signature === previousSignature + ); + const maxAttempts = possiblePendingGraphSwitch ? 3 : 8; - if ((!signature || graphStillLooksOld) && attempt < 8) { + if ((!signature || graphStillLooksOld || possiblePendingGraphSwitch) && attempt < maxAttempts) { setTimeout(() => { this.refreshForActiveWorkflowChange({ reason,