Skip to content

Give the community join dialog a navigation visit - #3063

Open
loganj wants to merge 9 commits into
mainfrom
loganj/join-dialog-history
Open

loganj wants to merge 9 commits into
mainfrom
loganj/join-dialog-history

Conversation

@loganj

@loganj loganj commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

The Join a community dialog now works with Back and Forward, like Settings and the other dialogs that follow the app's navigation history rules (docs/navigation-history.md). Before, it lived outside navigation: Back left the view under the dialog while the dialog stayed open, and Forward could not bring it back. This is the follow-up promised in #2991.

It applies to every way the dialog opens:

Action Result
Back Closes the dialog. The view under it (page, conversation or Settings section) stays as it was.
Forward Reopens the dialog as it was left: address, invite code and edited profile. It does not connect, claim an invite or publish a profile by itself; the person chooses Continue.
Close / Escape Closes the dialog. Back and Forward do not bring it back. Closing the view under it (for example Settings) also retires it.
Finishing the join Opens the new community. Back returns to the view under the dialog, not to the dialog or to an older dialog for the same community.
Back while the dialog is admitting or publishing Stays on the dialog, as its Close button is disabled during those writes.
Reload Shows the link's address again for the same account only, without a code or typed text.

Invite codes never go into history, the URL or session storage. They stay in memory for one opening of the dialog: two invites to the same community keep their own codes, and editing the address clears the code, so it never returns beside another address. After a reload an invite link must be opened again to use its code.

Details

  • The dialog is a join: { viewer, visit, community? } presentation on the visit beneath it, in the same way Settings presents over a page: the page underneath keeps its visit and stays mounted. Pages and their target comparisons see the target without join. visit is an opaque token for one opening.
  • The dialog reports its form (address, code, and the profile once edited, tagged with its community) to one in-memory record per opening, with the "connect at once" instruction (used for a community just created). A restored profile applies only to the community it was edited for. "Connect at once" is used once; Forward and later presentations wait for Continue. A change of account discards the other account's codes.
  • Finishing a join replaces the dialog's visit with the joined community's page, then retires this opening and every other opening that now offers the community actually joined (its edited address, else its original).
  • Back is held on the dialog while it admits (including a signed-in account's admission straight from the address step) or publishes, as its Close is. Settings beneath the dialog cannot be dismissed then either.
  • Under the dialog, Settings keeps its section, scope, provider and plugin details, but not a card's one-shot route (such as Create community) or a plugin import. When a join opens over a visit with such data, the navigation controller first resolves that visit to the view the join keeps (as it does for the channel beneath a Members handoff). Reload, Back and Close then return to Settings and never replay the action it came from.
  • A join restored together with Settings opens only after Settings has taken focus. Settings waits for the launch screen, and if the join opened first, Settings covered it and each dialog hid the other from the keyboard and assistive technology.
  • Browser coverage: hosted-create-join.spec.mjs now also reloads at the join (Join restores over Settings with no Create form, and Back shows the card's overview, not Create; both failed before the fix). It then holds a profile publication, tries Back and Escape, and refuses the publication; the join, its draft and Settings survive.
  • Two openings intentionally create no visit: first run's landing screen (there is no view under it), and the picker's Join a community while a failed link is waiting for Retry (a new visit would replace that failure and its Retry).
  • Also corrects a stale line in docs/plugin-architecture.md: after creating a hosted community, the Builderlab card opens the join dialog (it copies the address only when no identity is ready to join with).

Video

The picker's Join a community in the browser build (Chromium, slowed down): type an address, Back closes the dialog over the same view, Forward reopens it with the typed address, Reload shows the dialog again without the typed text, Close retires it (Forward is disabled).

join-dialog-history.mp4

🤖 Generated with Claude Code

@loganj
loganj marked this pull request as ready for review November 9, 2026 06:46
@loganj
loganj requested a review from a team as a code owner November 9, 2026 06:46
wesbillman

This comment was marked as resolved.

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Star Lord’s automated source-review follow-up via Wes’s account, with independent Rocket, Mantis and Groot review.

Reviewed head 8c7b94e3954d0abf40bc56b402397419580fb090 against base 9cc2881d63bd8d28fddf56065fc36d8dcbc7741e, focusing on the repair since 219fc6fe.

The prior P2, “preserve Members beneath Join,” is resolved in source. The new !target.join condition skips both Members handoff branches, so opening Join preserves the original Members visit. The added warm/cold controller tests exercise navigation.open and assert that Back returns to that exact entry, then to the preceding conversation or home. No new actionable findings in this bounded follow-up; no changes requested.

The original feature patch and base are unchanged, so earlier account/invite/admission coverage is retained. Back/Forward, explicit dismissal and replacement paths were traced in source. No tests, builds or apps were run; the new tests do not directly exercise Forward, Close or rendered focus, and browser/native behavior remains unverified. This is a COMMENT review, not approval.

@loganj
loganj force-pushed the loganj/join-dialog-history branch from 8c7b94e to 9723171 Compare November 9, 2026 10:37

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Star Lord automated source review via Wes’s account, integrating independent Rocket, Mantis and Groot reviews.

Reviewed 9723171e6647359332f3442b9ca5362481b935c0 against base/merge-base 58116b826171d190a7376fc57b0509c32c507dde. No new actionable findings in this bounded follow-up; no changes requested. The prior Members-under-Join repair remains intact.

The new matcher uses the same pasted-address parser and canonical community URL conversion as dialog submission. This allows completion to retire same-viewer sibling openings edited to a bare host or invite URL for the joined community. Edited empty or invalid destinations do not fall back to their original address; retirement reads the form before deleting its in-memory state. The rebased admission path retains its write guard and passes the newly parsed invite code into that submission.

Validation was source-only: no tests, builds or apps were run. The added helper assertions cover bare-host and invite-URL matching, not full sibling-visit retirement or browser/native/focus behavior. A one-time CI snapshot showed 34 successes, 23 running checks, one skip and a failed Rust and tool integration job; available annotations reported exit code 1 without establishing the cause. This review does not establish passing CI or runtime behavior.

COMMENT review only, not approval.

@loganj
loganj force-pushed the loganj/join-dialog-history branch from 9723171 to db1ad47 Compare November 9, 2026 14:43
kalvinnchau

This comment was marked as resolved.

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Star Lord automated source review via Wes’s account, integrating independent Rocket, Mantis and Groot reviews.

Reviewed 70e1f3460adcd4396f1b4470e266405861dd442e against base/merge-base 3a1eb5601e997811009d01601786df8af9393a7f. No new actionable findings in this bounded follow-up; no changes requested. Prior Members and address-matching fixes remain covered.

The new subscription releases an opening’s in-memory state when its last tracked navigation visit leaves the retained history window, while preserving it for passive Back/Forward. Completion evaluates sibling destinations before dismissal publishes cleanup. Pasted invite submission now normalizes the address and keeps its code in the editable code field, so a later Continue cannot restore the link’s original code over an edited or cleared value.

Source-only validation: no tests, builds or apps were run. The added mounted-app assertions cover Settings-close cleanup, branch cleanup after Back, and edited/cleared pasted-code restoration. Capacity eviction, multiple visits sharing a token, lookup-error recovery, browser/native behavior and runtime focus were traced or remain unexercised; the assertions do not establish those workflows. A one-time CI snapshot had 40 successes, 18 running checks and one skip, with no failures at that moment; CI completion was not established.

COMMENT review only, not approval.

loganj and others added 5 commits November 9, 2026 15:16
The join dialog is a presentation on the visit beneath it, for invite
links, the picker's Join a community and Settings Create community.
Back closes it; Forward restores the address without connecting again.
Close retires its visit; a finished join replaces it with the joined
community. Back cannot leave the dialog while it writes. Invite codes
stay in memory only.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
Members hands off to what opens from it, so an invite opened while
Members was showing replaced the Members visit (or, for a cold Members
link, resolved it to its channel first). Back then closed both dialogs.
The join dialog presents over Members, so it now pushes a visit above it.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
Join a community now takes an invite link or a bare host as its address.
Finishing a join retires every opening that offers the joined community,
so read each opening's address with the same parser; otherwise an opening
left on an invite link or a bare host for that community stayed open.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
A pasted invite URL left its code in the address, so each Continue
parsed it again and the link's code replaced an edited or cleared one.
The address now holds the community and the code moves to Invite code.

A join opening's state was released only by close, completion or a
failed opening. Closing the view beneath it, a new branch or history's
capacity left the code in memory with no way back to it. Services now
release an opening's state once none of its visits is retained.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
A join dialog over Settings gave Settings a new request for the dialog's
visit. Settings content keyed by its visit remounted: after Builderlab's
Create community, the card read its creation route again and reopened
Create over the join dialog. Settings now keeps its request while a join
dialog covers it, as a page does.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
@loganj
loganj force-pushed the loganj/join-dialog-history branch from 70e1f34 to 467d9e2 Compare November 9, 2026 21:02
kalvinnchau

This comment was marked as resolved.

A join opened from a Settings card copied the card's route, so a reload
reopened Create community above the join. The view beneath a join now
keeps Settings' section, scope and provider, never a card's route, a
plugin import or plugin details; opening, warm reuse and dismissal of
joins all use it.

Settings beneath a join also ignores dismissal while the join writes, as
Back and the join's own Close already do.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
kalvinnchau

This comment was marked as resolved.

loganj and others added 2 commits November 10, 2026 01:10
On reload, a join over Settings could open before Settings, which waits
for the launch screen. Settings then took the modal layer and hid the
join from keyboard and assistive technology while the join hid Settings.
The join over Settings now waits until Settings has taken focus, after
it hides the page beneath it.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
A join opened from the Builderlab card kept the card's create-community
route on the Settings visit beneath it. Close then Back stopped on an
extra Settings visit, and Back after a reload reopened the completed
Create form. When a join opens over a visit that carries one-shot data,
the controller now resolves that visit to the view the join keeps, as it
already does for the channel beneath a Members handoff.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>
kalvinnchau

This comment was marked as resolved.

A join opened over Settings plugin details dropped the plugin from the
view it keeps, and the controller wrote that view into the visit it
opened over. Back then returned to the Plugins list instead of the
details. Plugin details are an addressed view, not an action: the view
beneath a join now keeps them and drops only a card route or a plugin
import.

Co-authored-by: Larry <627498bd4bd1f281a16431e3c6cce3b5c25b6692798c78672298aefbf2f8f8b5@buzz.block.builderlab.xyz>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Logan Johnson <loganj@squareup.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants