Skip to content

Move user menu, create org menu#1992

Draft
GregorShear wants to merge 16 commits into
mainfrom
greg/move-avatar
Draft

Move user menu, create org menu#1992
GregorShear wants to merge 16 commits into
mainfrom
greg/move-avatar

Conversation

@GregorShear

@GregorShear GregorShear commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

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

  • Tenant selection is bootstrapped app-wide via useInitializeSelectedTenant (run once from TenantGuard), instead of as a side effect of a page-level dropdown.
  • One tenant switcher: the side-nav org switcher replaces the per-page selectors on the home and admin pages.
  • Full-page errors always offer logout + reload, so any error screen (including legal-check) can recover.

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.

ezgif-524cddc361fdc64e

user menu, now with more dark mode button:
Screenshot 2026-06-06 at 1 27 34 PM

org menu, currently only for switching tenants
Screenshot 2026-06-06 at 1 27 38 PM

org menu for estuary-support users (regular customers won't see this)
Screenshot 2026-06-06 at 1 27 46 PM

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:
Screenshot 2026-06-15 at 3 40 18 PM

@GregorShear GregorShear requested a review from a team as a code owner June 6, 2026 17:29
@GregorShear GregorShear marked this pull request as draft June 7, 2026 02:13
@GregorShear GregorShear force-pushed the greg/move-avatar branch 2 times, most recently from 2bbcc64 to 0f0a99c Compare June 10, 2026 01:04
Base automatically changed from greg/minor-styles to main June 11, 2026 15:31
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.
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.
@GregorShear GregorShear force-pushed the greg/move-avatar branch 2 times, most recently from b148309 to 7cbc3e1 Compare June 16, 2026 03:21
- 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).
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>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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 GregorShear marked this pull request as ready for review June 16, 2026 03:49
@GregorShear GregorShear added the change:planned This is a planned change label Jun 16, 2026
import { useBillingStore } from 'src/stores/Billing';
import { useTenantStore } from 'src/stores/Tenant';

export function useTenantChangeReset() {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

@GregorShear GregorShear marked this pull request as draft June 17, 2026 14:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

change:planned This is a planned change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant