feat(webapp): redesign the side menu project and organization menus#4066
feat(webapp): redesign the side menu project and organization menus#4066samejr wants to merge 51 commits into
Conversation
The top-left menu now represents the organization: it shows the org name and avatar and opens a flat list of org-level pages (Settings, Usage, Billing, Billing alerts, Team, an Integrations submenu, Switch organization, Account, Logout). Projects move into a dedicated "Project" section in the menu body: a project picker dropdown with the environment selector directly beneath it.
The Project menu trigger now matches the other side menu items: its label and folder icon are dimmed by default and brighten on hover, instead of staying highlighted. The environment selector shows a "[name] environment" tooltip on hover. It opens instantly when the side menu is collapsed and after a short delay when expanded.
Add an end tree-connector to the left of the environment selector and remove the gap between it and the project dropdown, so the environment reads as nested under the project in the side menu.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughThe org route loader now detects RBAC and SSO plugin availability, exposes both flags in loader data, and adds hooks for reading them. The side menu is reorganized into separate organization and project selectors: the organization popover lists org-level actions, integrations, account, logout, and organization switching, while the project selector shows project-only actions. 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Preview Deployment
|
Bump the org menu and project picker popover items to a 20px leading icon and a 0.90625rem label so they match the side menu nav items. The project folder icons keep their indigo color and the Vercel and Slack icons keep their smaller size.
…oll area Move the Project header, project picker, and environment selector into a fixed region so they stay put while the nav list scrolls, and shift the scroll divider down to the top of the scrollable section.
The side menu environment switcher is now a segmented control (Dev, Staging, Prev, Prod) instead of a dropdown, with each segment tinted in its environment color when active. The Dev segment shows the local dev server connection as a small pulsing dot with a hover tooltip, replacing the old connection button and modal. Preview opens a popover to switch branches and shows the active branch name. When the side menu is collapsed it falls back to the original dropdown selector, which is also still used on the blank-state panels and the Limits page.
- Revert the environment segmented control back to the dropdown selector, restoring the dev connection button and its modal - Hide the org, project, and environment selector chevrons until hover - Reorganize the project popover so New project and Project settings sit above a divider, before the project list - Remove the Environments header from the environment popover - Fix the dev connection button being clipped and tune the scroll section padding
…ide menu - Brighten the project selector trigger label and icon - Keep a constant 1px border on the project selector (transparent when collapsed) so it no longer nudges 1px on collapse - Animate the scroll section left padding in sync with the side menu collapse, matching its duration and easing - Remove the H shortcut key from the Help & Feedback button and surface it in a 500ms hover tooltip instead, keeping the shortcut working - Match the Help & Feedback label to the other side menu items (size and dimmed color)
- Apply the scrollable section left padding to the top Project section (Project header, project selector, environment selector), animated in sync with the collapse - Keep the menus reducing width instead of shifting right by holding their right edge - Match the section right and bottom padding to the left padding for symmetry, since there is no scrollbar in this section - Leave the organization menu unchanged
# Conflicts: # apps/webapp/app/components/navigation/SideMenu.tsx # apps/webapp/app/routes/_app.orgs.$organizationSlug/route.tsx
@trigger.dev/build
trigger.dev
@trigger.dev/core
@trigger.dev/python
@trigger.dev/react-hooks
@trigger.dev/redis-worker
@trigger.dev/rsc
@trigger.dev/schema-to-json
@trigger.dev/sdk
commit: |
- Replace the Ask AI button in the side menu footer with a collapse toggle that mirrors the middle handle (toggles the menu, Collapse/Expand tooltip with the cmd+b shortcut) - Add an animated LeftSideMenuIcon (scaleX transform so it animates on the compositor and never snaps) that animates on button hover, dimmed by default and bright on hover - Swap in a static LeftSideMenuCollapsedIcon when the menu is collapsed, and match the tooltip open delay to the Help and Feedback button - Add LeftSideMenuIcon to the storybook icons route Removes the Ask AI button and its cmd+i shortcut from the footer.
…r button The side menu footer collapse button now handles toggling, so the middle-right handle (and its animated chevron) is redundant. The cmd+b shortcut is preserved.
…llapsing The top section's bottom padding was pb-1 when collapsed and pb-2.5 when open, causing a vertical layout shift below the environment menu on toggle. Make it a constant pb-2.5 so only the horizontal padding animates.
- Add an Account menu (user avatar button) to the top of the side menu, between the organization menu and where the impersonation button used to be - The menu links to Profile, Personal Access Tokens, and Security, plus Logout - For admins it adds an Admin dashboard / Stop impersonating item with the cmd+esc shortcut shown inline, replacing the old permanent admin/impersonation button - Move Logout out of the organization menu into the account menu, and add a divider above Switch organization
Add a ChainLinkIcon and use it for the Private connections item in both the organization settings side menu and the organization dropdown, replacing the heroicons link icon.
…eholder - Replace the heroicons UserCircleIcon fallback in UserProfilePhoto/UserAvatar with the custom AvatarCircleIcon, matching the account menu Profile item - Size the account button avatar to match the popover menu item icons (20px)
Adopt the Security page's row-and-divider pattern on /account: each setting is a row with the title on the left and its control on the right. Profile picture, Full name, Email address, and a "Receive onboarding emails" toggle switch sit on equal-height rows, and the Update button is now a primary button.
…he project menu Bump the Env popover's item icons (size-5) and labels (text-[0.90625rem]) to match the Project popover, including the preview/dev branch submenu, its branch list, and the "Manage branches" footer. Applied only at these call sites so the shared EnvironmentLabel/EnvironmentCombo defaults used across the app are unchanged.
The Org, Project, Environment, Account, and Help & Feedback trigger buttons and the collapsible section headers now snap on hover instead of fading, matching the nav items in the scrollable area. The Project selector keeps a border-color transition so its outline still fades on collapse. Help & Feedback also gains the same up/down disclosure chevron the other menu triggers reveal on hover.
The disclosure chevron is a hover affordance with no meaning in the collapsed rail, but it was left mounted there. Rendering it only when the side menu is expanded keeps the collapsed icon clean and stops the chevron slot from affecting the collapsed button's layout or paint.
SimpleTooltip removed its trigger from the tab order (tabIndex=-1), so every side menu item wrapped in one (the nav links and the org/project/environment/account selectors) was skipped when tabbing. Add an opt-in tabbable prop to SimpleTooltip and set it on those triggers, give each the focus-custom ring, and turn the collapsible section headers into real buttons so they are keyboard-operable too. Tab order now follows the DOM top to bottom in both the expanded and collapsed states.
The shared focus-custom outline sat just outside the border box (offset 0), so it was clipped by any ancestor with overflow hidden/auto (scroll areas, the side menu grid) and covered by adjacent elements' backgrounds. Draw it 1px inside instead so the full ring is always visible. Applies everywhere focus-custom is used.
Resolves conflicts across the side menu files against main's Tailwind v3 to v4 migration: keep the side menu redesign, resize, keyboard-focus, and account/help menu work; adopt v4 class syntax (h-8! important suffix) and main's functional additions (environment list revalidate-on-open, changelog URL sanitizing). tailwind.config.js is removed (v4 config lives in tailwind.css) and the focus ring inset is re-applied there.
… menu The side menu still used the old charcoal-* utility classes and v3 arbitrary spacing after the v4 merge. Switch to the semantic aliases the rest of the app adopted (background-hover, grid-bright, surface-control) and the numeric spacing scale (pl-1.75, min-w-56, min-w-64). No visual change: the aliases resolve to the same underlying shades.
In the Switch organization submenu, New organization now sits above the list of organizations with the divider below it, instead of below the list.
In the dev and preview branch submenus, the Manage branches link now sits above the branch list with the divider below it, instead of below the list.
When a side menu section is collapsed its items are visually hidden (height 0) but stayed in the DOM, so keyboard and screen-reader users could still focus them. Mark the collapsed content inert so it is removed from both the tab order and the accessibility tree, restoring it when the section expands.
Bump the inset focus-custom ring's border-radius from 3px to 5px so the corners read as slightly rounder now that the ring sits inside the element.
…m pages Add a 1.5px-stroke variant of the avatar placeholder icon (AvatarCircleIconThin) alongside the 2px default, and a thin prop on UserAvatar/UserProfilePhoto. Use it for the account page's profile picture and the team page member rows; every other avatar keeps the 2px variant.
Add AvatarCircleIconExtraThin (1.25px stroke) and switch the avatar placeholder's thin boolean to a strokeWidth prop (1.25 | 1.5 | 2). The team page member rows use the 1.25px variant at a slightly smaller size; the account profile picture keeps 1.5px; every other avatar stays at 2px.
…esize While the side menu is being drag-resized, the account, dev-connection and collapse buttons (each sitting to the right of a primary item) used to stay put and overlap the org, environment and Help items as the row narrowed. Fade them out during the drag and return them on release.
The previous fix faded the account, dev connection and collapse buttons with a class based opacity transition. During a quick drag that 200ms transition lagged behind the shrinking row, so the buttons stayed briefly visible and overlapped the org and Help items (the reported dark overlay). Drive the account and dev connection opacity from the imperative --sm-label-opacity variable instead so it tracks the drag frame by frame with no lag, and hide the collapse button instantly (it cannot use the variable because it stays visible as the expand button when the menu is collapsed).
…id-drag Fading the secondary buttons out was not enough: while drag-resizing, the account, dev connection and collapse buttons and the hover chevrons still held their full layout width, so as the row narrowed they pushed the primary item's overflow clip edge into its icon. The org avatar and Help & Feedback icon were progressively swallowed by the clip and read as a dark panel covering them. Drive those widths from the per frame --sm-label-opacity variable instead, in the same curve as the fade, so the space is handed back to the primary item as the menu narrows and its icon stays fully visible at every width. The collapse button only shrinks while dragging since it keeps its natural size as the expand affordance when the menu rests collapsed.
…gging the side menu open The nav item labels already reveal in real time during a drag-open, but the org, project, environment and Help & Feedback labels were gated on the collapsed state, which only flips on release, so they stayed hidden for the whole drag and popped in at the end. Drive their width and opacity from the per frame --sm-label-opacity variable instead, exactly like the nav items, and keep those rows in their expanded arrangement while a drag is in progress so the revealing label has the layout it needs in both directions. Outside the resizable side menu the variable is unset and falls back to fully visible, so the environment selector and help popover render unchanged everywhere else.
…utton label, env tooltip) - Flush the side menu preference debounce only on real unmount. The unmount effect listed the fetcher in its deps, and useFetcher returns a fresh object every render, so the cleanup fired on every re-render and prematurely flushed the 500ms debounce. A drag re-renders constantly, so this turned one save into many. Hold the flush routine in a ref and give the effect an empty dep array. - Give the dev server connection button an accessible name so screen readers announce it (it was icon only). - Only show the environment selector tooltip on the collapsed rail, matching the org and project selectors. It had switched to an always-on delayed tooltip, which also leaked into the blank-state panels and Limits page that reuse this selector.
While the side menu is dragged or animated between open and collapsed, the button and nav labels used to shrink their text box in lockstep with the fade, so the text visibly truncated (with an ellipsis) as the row narrowed. Drive the visible fade purely by opacity so the text stays at full width and simply fades in place. Labels that are wider than the row still clip at its edge, now without an ellipsis. The selector label width cap still scales to zero as the label finishes fading, so an invisible label never holds layout width (which would push the row's clip edge into the icon). EnvironmentLabel gains a `truncate` prop (default true) so only the side menu opts out; every other usage is unchanged.
…enu open The collapse/expand button shrank its width and opacity with the --sm-label-opacity variable during any drag. On a close drag that fades it out so it does not overlap Help & Feedback as the row narrows, which is correct. But on an open drag from collapsed, the same variable runs 0 to 1, so the button (which when collapsed is the expand affordance) started at zero width and only scaled back in near the end of the drag, so its icon appeared to grow from nothing. Only apply the shrink while dragging closed; while dragging open the button keeps its natural size and stays visible throughout.
…lapse The left padding of the scroll body interpolated smoothly with --sm-collapse, but the right-hand spacing came from a reserved scrollbar gutter that is a fixed width and gets dropped abruptly when the scrollbar is hidden on collapse, so it jumped instead of animating. Drop the reserved gutter and drive the right padding with the same variable as the left, so both edges animate together. The thin scrollbar still appears when the nav list overflows; it just no longer reserves a fixed gutter while idle.
…the collapse animation Restores the no-layout-shift behavior (the scroll body no longer jumps sideways when the nav list starts or stops overflowing) that was dropped when the right padding was made to animate. The two conflict directly: a reserved gutter is a fixed width that cannot animate to the collapsed inset. Resolve it with a handoff. The gutter is reserved (scrollbar-gutter: stable) only while the menu is fully settled open; during any drag or open/close animation it is dropped and the right padding takes over, interpolating from the gutter's own width down to the collapsed inset so the swap has no seam. The gutter width is platform dependent, so it is measured once on mount and exposed as --sm-sb-gutter. An isAnimating flag keeps the gutter from being reserved mid-animation, which would otherwise cramp the narrow menu during a button/hotkey expand.
When the side menu is collapsed the standalone account button is hidden, so the account actions (Profile, Personal Access Tokens, Security, Logout, and the admin/impersonation entries) were only reachable by expanding the menu first. Surface them on the collapsed rail: the org popover (the one menu always reachable when collapsed) now shows an "Account" item at the top, divided from the org items, that opens the full account menu as a submenu. To keep it maintainable the account entries are extracted into a shared AccountMenuItems component used by both the standalone account popover and the submenu, and the hover submenu behind Switch organization and Integrations is generalized into a shared SideMenuPopoverSubMenu, so new nested menus and account entries are easy to add in one place.
… org menu Moves the "Account" submenu shown on the collapsed rail from the top of the org popover to the bottom, with the divider now above it instead of below.
The admin shortcut (Cmd/Ctrl+Esc to open the admin dashboard, or to stop impersonating while impersonating) was registered inside the account menu, which only mounts on project pages. So it did nothing on the account, organization settings and admin pages. Move it into a GlobalShortcuts component mounted once at the app root, so it works on every page regardless of which side menu is rendered, and remove the account-menu registration so it never fires twice. GlobalShortcuts is the place to add future app-wide shortcuts.
…apturable) Cmd+Esc can't be captured on Chrome/macOS: the browser doesn't deliver an Escape keydown to the page while a modifier is held, so no listener ever sees it (confirmed with a Radix dialog, which closes on any Escape keydown, not closing on Cmd+Esc). That is why the admin shortcut did nothing. Switch it to Cmd+Option+A (Ctrl+Alt+A on Windows): an admin-only, two-modifier combo that no user-facing or browser shortcut uses, and which is actually delivered because it is a letter key. It is matched on event.code (KeyA) so it still works when Option makes the key report an alternate character on macOS, which is why it is a small raw listener in GlobalShortcuts rather than the key-based shortcut hook. The account-menu badge now reads Cmd Option A.
This is a test concept that separates Projects from the Org menu in the main side menu.
Preview URL: https://samejr-org-menu-update.triggerlabs.dev/