Move user menu, create org menu#1992
Draft
GregorShear wants to merge 16 commits into
Draft
Conversation
e353adc to
fe8110d
Compare
2bbcc64 to
0f0a99c
Compare
…m home and admin pages
The org menu replaced the per-page TenantSelector (removed from the home and admin pages), which was what previously defaulted the selected tenant. Since OrgMenu is always mounted in the nav, default selectedTenant to the first admin-capable tenant when none is validly selected, while preserving a still-valid persisted selection.
0f0a99c to
a712916
Compare
Brings the org menu to parity with the removed per-page TenantSelector: - Honor a ?prefix= URL param (e.g. the billing add-payment-method CTA) the first time it appears, then keep a manual selection. A ref tracks the applied param so a stale value lingering in the URL doesn't override later org switches. - Drop the support-only dialog that listed the full prefix set (allPrefixes); support users now see the same top-level org list (tenantsWithAdmin) as everyone else, matching what the old selector showed.
Reverts the dialog removal from the previous commit. estuary-support users admin a large number of tenants and need a searchable list, so they keep the autocomplete dialog over the full admin prefix set; regular users keep the simple top-level org menu. Also fixes the defaulting effect to validate the current selection against the list each user actually sees (allPrefixes for support, tenantsWithAdmin otherwise) instead of always against the top-level orgs, so a support user's selection isn't reset to the first top-level org.
The support dialog was listing allPrefixes (useEntitiesStore_capabilities_adminable) — the full admin prefix set incl. sub-prefixes, which no tenant selector showed before this PR. Switch it to useEntitiesStore_tenantsWithAdmin, the exact list the old TenantSelector showed every user (regular and support), so support users get the identical top-level org list they had pre-change, just in the searchable dialog. Both selectors now share one list, so the defaulting effect no longer needs a per-user list.
When the click-to-accept (ToS/Privacy) check fails to fetch, LegalGuard renders a full-page error in place of the children — before the layout, and the now-relocated logout button in the nav, can render. That left a stuck user no way to sign out (logging out and back in clears a stale check). Add an optional actions slot to FullPageError and pass a Log out button (supabaseClient.auth.signOut()) from LegalGuard's error branch. The ToS accept screen already had this via the Actions cancel button; this fills the gap on the error screen.
Every FullPageError call site is behind auth (LegalGuard, UserInfoSummary, TenantBillingDetails, and the entities/storage-mappings hydrators) and is a dead-end a stuck user may need to escape. Move the Log out button into FullPageError itself and drop the opt-in actions prop / LegalGuard wiring added in the previous commit, so all full-page errors get the escape hatch consistently.
Most full-page errors (failed data hydration or fetches) are transient, so offer a page reload as the primary recovery action, with the logout escape hatch as the secondary.
Tenant selection is global app state, but it was being initialized inside OrgMenu, a presentational nav component. That made correctness depend on the menu's mount lifecycle. Extract the effect into useInitializeSelectedTenant and call it from TenantGuard, which only renders the app for users with tenant access. OrgMenu becomes a pure consumer of selectedTenant. Behavior is unchanged.
It reads the identity-provider-asserted user_metadata.email_verified, not Supabase's authoritative email_confirmed_at. Since production only supports SSO and social login, the provider always vouches for the email, so the field is true for practically every user (confirmed against prod) and is not a meaningful UI or analytics signal.
b148309 to
7cbc3e1
Compare
- ListItemLink takes a plain string title (callers format i18n), splits the overloaded link prop into explicit to/onClick, and gains an optional tooltip (defaults to title). Unused props and the dead NavWidths.FULL branch are gone. - All side-nav rows (route links, collapse toggle, help/user/org triggers) now render through ListItemLink, so NavTriggerButton is deleted. - UserMenu and OrgMenu are pure floating surfaces taking anchorEl/onClose, matching HelpMenu; Navigation owns the trigger rows and anchor state. OrgMenu picks the support dialog vs the popover internally from hasSupportAccess. - The lower nav section gets a distinct aria-label (navigation.ariaLabel.secondary).
7cbc3e1 to
1f93b3c
Compare
GregorShear
commented
Jun 16, 2026
Comment on lines
+61
to
+79
| <Stack direction="row" spacing={1}> | ||
| <Button | ||
| variant="contained" | ||
| onClick={() => { | ||
| window.location.reload(); | ||
| }} | ||
| > | ||
| <FormattedMessage id="cta.reload" /> | ||
| </Button> | ||
|
|
||
| <Button | ||
| variant="outlined" | ||
| onClick={() => { | ||
| void supabaseClient.auth.signOut(); | ||
| }} | ||
| > | ||
| <FormattedMessage id="cta.logout" /> | ||
| </Button> | ||
| </Stack> |
Contributor
Author
There was a problem hiding this comment.
The user menu (and logout menu item) moved to the sidenav, which the FullPageError omits, so putting a a logout button directly in the error dialog
GregorShear
commented
Jun 16, 2026
| import { useBillingStore } from 'src/stores/Billing'; | ||
| import { useTenantStore } from 'src/stores/Tenant'; | ||
|
|
||
| export function useTenantChangeReset() { |
Contributor
Author
There was a problem hiding this comment.
This hook is transitional - it extracts the billing reset logic from the deleted TenantOptions component.
A follow-up PR will key billing data on the selected tenant making this reset unnecessary.
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.
Summary
Centralizes how the selected organization is chosen and reorganizes the side nav. The org-selection behavior is the substantive change; the nav rework is structural/visual with no functional impact.
Functional changes
useInitializeSelectedTenant(run once fromTenantGuard), instead of as a side effect of a page-level dropdown.Secondary (no behavior change)
Help/user menus moved into the side nav; all rows unified under one
ListItemLink; dark/light toggle moved into the user menu.user menu, now with more dark mode button:

org menu, currently only for switching tenants

org menu for estuary-support users (regular customers won't see this)

Adding a logout button to the FullPageError component since the user menu (where the logout button normally lives) moved to the side nav, and that isn't rendered with FullPageError:
