Make the add-connection modal self-contained so abandoned OAuth can't wedge it - #1126
Merged
Conversation
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-marketing | 1a17293 | Commit Preview URL Branch Preview URL |
Jun 25 2026, 06:54 AM |
Contributor
Cloudflare previewTorn down — the PR is closed. |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
executor-cloud | 1a17293 | Jun 25 2026, 06:54 AM |
@executor-js/cli
@executor-js/config
@executor-js/execution
@executor-js/sdk
@executor-js/codemode-core
@executor-js/runtime-quickjs
@executor-js/plugin-file-secrets
@executor-js/plugin-graphql
@executor-js/plugin-keychain
@executor-js/plugin-mcp
@executor-js/plugin-onepassword
@executor-js/plugin-openapi
executor
commit: |
RhysSullivan
force-pushed
the
claude/nice-banzai-534ae2
branch
from
June 25, 2026 06:35
1b38390 to
10f2383
Compare
… wedge it The add-account modal stays mounted across open/close (its parent passes an `open` prop rather than conditionally mounting it), so transient state survived a close. In particular the OAuth popup flow's busy state lives in `useOAuthPopupFlow`, not the modal's own useState, and a hand-written `reset()` cleared the modal's local booleans but never touched it. So if a user began OAuth and then abandoned the provider popup (closed it without granting consent, which we intentionally do not poll for because provider COOP headers make `popup.closed` unreliable), the footer stayed wedged on "Connecting…" with Close disabled. Reopening the modal showed the same stuck state with no way to retry. The fix is structural rather than another setter in `reset()`: the modal is now self-contained. The whole body lives in `AddAccountModalView`, and the thin `AddAccountModal` wrapper mounts it only while open (`open ? <View/> : null`). Closing flips `open` to false, which genuinely unmounts the view, so React destroys the form fields and the OAuth popup flow's busy state and runs the hook's unmount cleanup that cancels the dangling server OAuth session. `reset()` is deleted: a closed modal owns no state to reset. Reconnect and deep-link handoffs still prefill, because the view mounts with its `initialState` already set and applies it on mount. The view owns the dynamic-width DialogContent (its width tracks the body's current sub-view), so there is no body-independent shell to keep mounted while the body remounts; unmounting the whole Dialog forgoes the Radix close animation. That is the deliberate tradeoff for correct teardown. Adds a cloud e2e scenario driving the real abandon-then-reopen path: it starts OAuth against a local authorization server, closes the popup mid-flow, closes the modal with Escape, reopens, and asserts the modal offers a fresh attempt instead of a stuck "Connecting…". Also adds a self-contained-modals skill codifying the underlying rule (form and in-flight state live inside the modal; closing unmounts it) so this lifecycle-leak class gets flagged in review.
RhysSullivan
force-pushed
the
claude/nice-banzai-534ae2
branch
from
June 25, 2026 06:52
10f2383 to
1a17293
Compare
RhysSullivan
marked this pull request as ready for review
June 25, 2026 07:07
Greptile SummaryThis PR makes the add-connection modal tear down its own transient state on close. The main changes are:
Confidence Score: 5/5This looks safe to merge.
Important Files Changed
Reviews (1): Last reviewed commit: "Make the add-connection modal self-conta..." | Re-trigger Greptile |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A user reported the add-connection modal getting stuck on "Connecting…": they began an OAuth connection, abandoned the provider popup (closed it without granting consent), then closed the modal. Reopening showed the footer still wedged on "Connecting…" with the Close button disabled, and no way to retry.
Root cause
The add-account modal was kept mounted across open/close (its parent renders it with an
openprop rather than conditionally mounting it), so transient state survived a close. The OAuth popup flow'sbusystate lives in theuseOAuthPopupFlowhook, not in the modal's ownuseState, and the modal's hand-writtenreset()zeroed its local booleans but never touched the hook.Because we intentionally do not poll
popup.closed(provider COOP headers make it unreliable), abandoning the popup leaves the hook'sbusytrue. With the modal always mounted, that state survived the close, so:and the reopened footer stayed on "Connecting…".
Fix
Rather than adding another setter to
reset(), the modal is now self-contained and genuinely unmounts on close. The whole body lives inAddAccountModalView, and the thinAddAccountModalwrapper mounts it only while open:reset()is deleted. Closing flipsopento false, React unmounts the view, and that destroys the form fields and the OAuth popup flow'sbusystate for free, and runs the hook's unmount cleanup that cancels the dangling server-side OAuth session. A closed modal owns no state to reset.initialStatealready set and applies it on mount.DialogContent(its width tracks the body's current sub-view), so there is no body-independent shell to keep mounted while the body remounts. Unmounting the whole Dialog forgoes the Radix close animation, the deliberate cost of correct teardown here.Evidence
New cloud e2e scenario
e2e/cloud/connection-modal-oauth-abandon.test.tsdrives the real path against a local authorization server:Before the fix this scenario fails (
expected 1 to be 0); with the fix it passes. The existingconnect-panelbrowser scenario still passes, covering the happy-path open/connect flow under mount-on-open.Also included
A
self-contained-modalsskill that codifies the underlying rule (a modal's form and in-flight state live inside it and are destroyed on close by unmounting; a hand-writtenreset()is a review smell) so this lifecycle-leak class gets caught in review rather than re-introduced.