[aidan] ui/ux: fix connecting status accuracy

This commit is contained in:
abccodes
2026-06-14 03:49:17 -07:00
parent 46134bc367
commit daece58c3d
@@ -143,16 +143,24 @@ function runAuthCodeFlow(ctx: ConnectCtx) {
popup = window.open(data.auth_url, 'oauth_connect', 'width=600,height=700');
}
let stopped = false;
let resetTimer: ReturnType<typeof setTimeout> | null = null;
// Status polling: primary for external-browser flow, secondary for popup flow (postMessage is faster).
const statusPoller = setInterval(async () => {
if (stopped) return;
try {
const sr = await fetch(`${API_BASE}/agents/subscriptions/status`);
const sd = await sr.json();
const connections = sd.providers?.connections || [];
if (connections.some((p: any) => p.provider === providerId && (p.isActive || p.testStatus === 'active'))) {
stopped = true;
if (resetTimer) clearTimeout(resetTimer);
clearInterval(statusPoller);
setPollTimer(null);
if (!useExternal) window.removeEventListener('message', msgHandler);
window.removeEventListener('blur', onBlur);
window.removeEventListener('focus', onFocus);
setConnecting(null);
fetchStatus();
refreshPickerModels();
@@ -164,10 +172,14 @@ function runAuthCodeFlow(ctx: ConnectCtx) {
// Shared exchange helper invoked by whichever relay path delivers the code first.
let exchanged = false;
const runExchange = async (code: string, state?: string) => {
if (exchanged) return;
if (exchanged || stopped) return;
exchanged = true;
stopped = true;
if (resetTimer) clearTimeout(resetTimer);
window.removeEventListener('message', msgHandler);
if (ipcUnsub) ipcUnsub();
window.removeEventListener('blur', onBlur);
window.removeEventListener('focus', onFocus);
clearInterval(statusPoller);
setPollTimer(null);
if (popup && !popup.closed) popup.close();
@@ -208,13 +220,55 @@ function runAuthCodeFlow(ctx: ConnectCtx) {
});
}
// If the user comes back to openswarm without finishing OAuth (closed the browser, cancelled),
// 3s of sustained focus + no active connection means abandoned; clear Connecting so they can retry.
// A blur during the wait cancels, so brief tab-backs to check progress don't false-positive.
const onBlur = () => {
if (resetTimer) { clearTimeout(resetTimer); resetTimer = null; }
};
const onFocus = () => {
if (stopped) return;
if (resetTimer) clearTimeout(resetTimer);
resetTimer = setTimeout(async () => {
resetTimer = null;
if (stopped) return;
try {
const sr = await fetch(`${API_BASE}/agents/subscriptions/status`);
const sd = await sr.json();
const conns = sd.providers?.connections || [];
if (conns.some((p: any) => p.provider === providerId && (p.isActive || p.testStatus === 'active'))) return;
} catch {}
if (stopped) return;
stopped = true;
clearInterval(statusPoller);
setPollTimer(null);
if (!useExternal) window.removeEventListener('message', msgHandler);
if (ipcUnsub) ipcUnsub();
window.removeEventListener('blur', onBlur);
window.removeEventListener('focus', onFocus);
setConnecting(null);
}, 3000);
};
// Delay attach; popup mode's window.open blurs/refocuses the parent and would false-trigger.
setTimeout(() => {
if (!stopped) {
window.addEventListener('blur', onBlur);
window.addEventListener('focus', onFocus);
}
}, 2000);
// 3min popup / 5min external-browser; bounds the Connecting indicator, safety-net poller is the real exit.
const timeoutMs = useExternal ? 300_000 : 180_000;
setTimeout(() => {
if (stopped) return;
stopped = true;
if (resetTimer) clearTimeout(resetTimer);
clearInterval(statusPoller);
setPollTimer(null);
if (!useExternal) window.removeEventListener('message', msgHandler);
if (ipcUnsub) ipcUnsub();
window.removeEventListener('blur', onBlur);
window.removeEventListener('focus', onFocus);
setConnecting(null);
}, timeoutMs);
}