Preview comment login link + create-project pending state
Two small auth/preview-deploy annoyances, from Misha:
in the table of deployed stuff, can we use the click-and-login thing like in this comment. actually, maybe it should just be a suffix on the
## Environment Config Leasetitle. Just like aLogin ↗<a>tag with target=_blank or something. So no extra space used-upin the auth worker when I click create project there's no spinner and the create button doesn't get disabled, so I often click it twice and get an error the second time (it's nbd, i eventually get navigated anyway but a little annoying)
Status#
Both parts implemented and tested (133 preview unit tests, 95 auth tests,
typecheck/lint/knip green). PR: https://github.com/iterate/iterate/pull/2475.
Remaining: live verification of the Login ↗ link via this PR's own preview
comment (added the preview label to trigger it despite draft).
1. Login ↗ suffix on the preview PR comment heading#
The preview section in the PR body is rendered by
renderCloudflarePreviewSection in scripts/preview/preview.ts. Make the
heading:
## Environment Config Lease [Login ↗](https://os.iterate-preview-N.com/api/iterate-auth/login?login_hint=prNNNN%2Btest%40nustom.com)Decisions (assumptions, since Misha was brief):
-
Markdown link, not a literal
<a target="_blank">— GitHub's HTML sanitizer stripstargetanyway, and markdown-in-heading renders fine on GitHub. -
Login URL = os preview base URL (derived from the lease's doppler config via the typed
envs.tsmap — same source deploys use) +/api/iterate-auth/login?login_hint=pr<PR#>+test@nustom.com, matching the click-and-login link in the referenced comment.+test@nustom.comemails get the fixed OTP424242on preview slots, so this is one-click-ish login. -
Per-PR
login_hint(pr2474+test@nustom.com) so each PR's testing lands on its own user by default. -
No link when there's no lease recorded, or the doppler config isn't a known os environment (render must never throw).
-
thread
pullRequestNumberintorenderCloudflarePreviewPullRequestBody/renderCloudflarePreviewSection(required third param; the one production callsite inupdateCloudflarePreviewStatealready had it) -
heading suffix with login URL derived from lease doppler config (
previewLoginUrlinscripts/preview/preview.ts, resolved throughcloudflarePreviewApps.os.resolvePreviewAppConfig) -
update/extend
scripts/preview/preview.test.ts(link asserted in the round-trip test; no-lease and unknown-config cases assert no link)
2. Create-project button stays enabled during post-success redirect#
The auth app's create-project surfaces (apps/auth/src/routes/_auth/project-access.tsx)
do disable + relabel while the mutation is pending. The actual gap: on
success the code assigns window.location.href and returns, react-query flips
isPending back to false, and the button re-enables (labeled "Create
project" again) while the browser is still loading the redirect target. That's
the window where the second click lands and errors with a duplicate — and "I
eventually get navigated anyway" because the first redirect completes.
Fix: a redirect() helper that assigns window.location.href and returns a
never-resolving promise. Returned from onSuccess (or awaited in
mutationFn), react-query keeps the mutation pending until the page unloads,
so every button gated on isSubmitting stays disabled through the navigation.
-
redirect()helper; use it for allwindow.location.hrefassignments inproject-access.tsx(create org+project, create project, save selection, deny) (redirectAndStayPendingat the bottom of the file; theExternalRedirectcomponent'swindow.location.replaceis untouched — it renders nothing, so there's no button to re-enable) [ ] regression test(skipped: apps/auth has no jsdom/component-test infra and the helper is 3 lines; standing up React test infra for it isn't worth it. The behavior is covered by the docstring + preview e2e exercising the flow.)
Follow-up: email login_hint was dropped at the os hop#
Misha tried the deployed link and didn't get the "Login with /login route in apps/auth/src/lib/server.ts (which serves
os's /api/iterate-auth/login, the URL the PR comment links to) only
forwarded login_hint=email|google and silently dropped email addresses.
Mobile QRs link to auth directly, which is why they never hit this.
[x](superseded: main landed the identical fix in parallel via the click-and-login work — inline predicate inforwardableLoginHinthelper + RP forwarding + client type + testlib/server.ts, same client type widening, same test case. Resolved the merge in main's favor and deleted this branch's duplicates (a2aa1fe40); this branch is back to just the Login ↗ link + project-access pending fix.)
Implementation log#
- Worktree
../worktrees/iterate/preview-login-link-and-create-project-pending, branch of the same name, offorigin/main(0790f2170).