feat(FN-1899): implement login timeout, cancellation, and 409 conflict handling

- Add login outcome types (timeout, success, failed) and state tracking via stepData
- Implement login timeout after MAX_POLL_CYCLES (150 polls × 2s = 5 minutes) with warning toast
- Add 409 Conflict detection for concurrent login attempts with warning toast
- Add cancellation capability for in-progress logins with cleanup and state reset
- Update ModelOnboardingModal tests to cover timeout and concurrent login scenarios
This commit is contained in:
Fusion
2026-04-16 00:37:01 -07:00
committed by gsxdsm
parent 4fb8be4273
commit a9d6c4159d
5 changed files with 159 additions and 12 deletions

View File

@@ -248,7 +248,7 @@ export function ModelOnboardingModal({
}
setAuthActionInProgress(null);
setLoginOutcomes((prev) => ({ ...prev, [providerId]: "timeout" }));
addToast("Login timed out. Please try again.", "info");
addToast("Login timed out. Please try again.", "warning");
return;
}
@@ -276,7 +276,7 @@ export function ModelOnboardingModal({
(err && typeof err === "object" && "status" in err && (err as { status: number }).status === 409);
if (isConcurrentLogin) {
addToast("Login already in progress. Please wait or cancel the current attempt.", "info");
addToast("Login already in progress. Please wait or cancel the current attempt.", "warning");
setLoginOutcomes((prev) => ({ ...prev, [providerId]: "failed" }));
} else {
addToast(err instanceof Error ? err.message : "Login failed", "error");

View File

@@ -1321,7 +1321,7 @@ describe("ModelOnboardingModal", () => {
await waitFor(() => {
expect(addToast).toHaveBeenCalledWith(
"Login already in progress. Please wait or cancel the current attempt.",
"info"
"warning"
);
});
});
@@ -1517,7 +1517,7 @@ describe("ModelOnboardingModal", () => {
});
// Should show timeout toast
expect(addToast).toHaveBeenCalledWith("Login timed out. Please try again.", "info");
expect(addToast).toHaveBeenCalledWith("Login timed out. Please try again.", "warning");
// Cancel button should not be shown after timeout
expect(screen.queryByText("Cancel")).toBeNull();