From ecb7ae6c39ddb67fb7ceace43b4a2b4028b494d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20De=20Freitas?= <6485562+adefreitas@users.noreply.github.com> Date: Thu, 16 Apr 2026 11:27:58 +0100 Subject: [PATCH 1/2] fix(ENG-12551): detect COOP to fix popup close behavior without it Without COOP, closing the OAuth popup should reset to the form. Previously, active polling prevented this. Now we detect COOP by checking if the popup appears closed immediately after opening (browsers sever the window reference under same-origin COOP). Only defer to polling when COOP is actually detected. Co-Authored-By: Claude Sonnet 4.6 --- .../hooks/useIntegrationPicker.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/modules/integration-picker/hooks/useIntegrationPicker.ts b/src/modules/integration-picker/hooks/useIntegrationPicker.ts index f4b49b1..2deb84b 100644 --- a/src/modules/integration-picker/hooks/useIntegrationPicker.ts +++ b/src/modules/integration-picker/hooks/useIntegrationPicker.ts @@ -77,6 +77,7 @@ export const useIntegrationPicker = ({ const storageListenerRef = useRef<((event: StorageEvent) => void) | null>(null); const connectionAttemptIdRef = useRef(null); const pollingIntervalRef = useRef(null); + const coopDetectedRef = useRef(false); const oauthResolvedRef = useRef(false); const [connectionState, setConnectionState] = useState<{ loading: boolean; @@ -590,6 +591,7 @@ export const useIntegrationPicker = ({ console.debug('[hub] OAuth popup closed', { resolved: oauthResolvedRef.current, pollingActive: !!pollingIntervalRef.current, + coopDetected: coopDetectedRef.current, }); } connectWindow.current = null; @@ -600,15 +602,20 @@ export const useIntegrationPicker = ({ if (oauthResolvedRef.current) return; window.removeEventListener('message', processMessageCallback, false); - if (pollingIntervalRef.current) return; + if (coopDetectedRef.current && pollingIntervalRef.current) return; + + teardownOAuth(); + if (connectionAttemptIdRef.current) { + void cancelConnectionAttempt(baseUrl, connectionAttemptIdRef.current); + } if (debugRef.current) { - console.debug('[hub] popup closed with no active poll, resetting state'); + console.debug('[hub] popup closed, resetting state'); } setConnectionState({ loading: false, success: false }); }; checkStateTimeoutRef.current = window.setTimeout(check, 1000); - }, [processMessageCallback]); + }, [processMessageCallback, teardownOAuth, baseUrl]); const handleConnect = useCallback(async () => { if (!selectedIntegration) { @@ -732,6 +739,11 @@ export const useIntegrationPicker = ({ return; } + coopDetectedRef.current = connectWindow.current.closed === true; + if (debugRef.current && coopDetectedRef.current) { + console.debug('[hub] COOP detected: popup appears closed immediately'); + } + if (typeof connectWindow.current.focus === 'function') { connectWindow.current.focus(); } From 21fecd64a4d259883330180ffcdd4fdc795ab5a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20De=20Freitas?= <6485562+adefreitas@users.noreply.github.com> Date: Thu, 16 Apr 2026 11:32:30 +0100 Subject: [PATCH 2/2] fix: capture attemptId before teardownOAuth clears the ref Co-Authored-By: Claude Sonnet 4.6 --- src/modules/integration-picker/hooks/useIntegrationPicker.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/integration-picker/hooks/useIntegrationPicker.ts b/src/modules/integration-picker/hooks/useIntegrationPicker.ts index 2deb84b..0796a0a 100644 --- a/src/modules/integration-picker/hooks/useIntegrationPicker.ts +++ b/src/modules/integration-picker/hooks/useIntegrationPicker.ts @@ -605,9 +605,10 @@ export const useIntegrationPicker = ({ if (coopDetectedRef.current && pollingIntervalRef.current) return; + const connectionAttemptId = connectionAttemptIdRef.current; teardownOAuth(); - if (connectionAttemptIdRef.current) { - void cancelConnectionAttempt(baseUrl, connectionAttemptIdRef.current); + if (connectionAttemptId) { + void cancelConnectionAttempt(baseUrl, connectionAttemptId); } if (debugRef.current) { console.debug('[hub] popup closed, resetting state');