feat(ui): redesign org/project switcher with searchable flyouts#2638
Conversation
Replace the single "Change project" dialog in the account popover with the web app's switcher pattern: separate Project and Organization sections, each with a chevron flyout listing the available options and a create action that opens the cloud app externally. - Searchable flyouts (Autocomplete) with the active item pinned first and the rest locale-sorted, matching web ordering - Org rows show the saved logo from /uploaded_media, falling back to a deterministic colored initial avatar - Flyouts pin align="start" via a local PinnedSubContent so filtering never makes the popup jump (quill's SubContent doesn't forward collisionAvoidance; TODO to upstream) - External-link indicators on create actions and Discord Generated-By: PostHog Code Task-Id: d746f1ce-5792-4a1c-87ce-cd27cb95b17a
|
React Doctor could not complete this scan.
Reviewed by React Doctor for commit |
Prompt To Fix All With AIFix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
packages/ui/src/features/sidebar/components/ProjectSwitcher.tsx:417-420
**Conflicting Tailwind width utilities in `PinnedSubContent`**
The component hardcodes `w-auto` in its class string, then appends the caller's `className` (always `"w-64 p-0"`) after it. This produces `...w-auto w-64 p-0` on the same element. When two Tailwind utilities targeting the same CSS property appear in the same class list, the winner is determined by which rule appears later in the compiled stylesheet — not by the order in the HTML attribute. This is an implementation detail of Tailwind's JIT compilation and is not guaranteed. Since `cn` is already available in the quill package (used in `SidebarItem.tsx` in this same directory), `cn()` would resolve the conflict reliably.
```suggestion
<BaseMenu.Popup
data-slot="dropdown-menu-sub-content"
className={`quill-menu__content quill-menu__sub-content ${className ?? ""}`}
>
```
Reviews (1): Last reviewed commit: "Merge branch 'main' into posthog-code/or..." | Re-trigger Greptile |
| <BaseMenu.Popup | ||
| data-slot="dropdown-menu-sub-content" | ||
| className={`quill-menu__content quill-menu__sub-content w-auto ${className ?? ""}`} | ||
| > |
There was a problem hiding this comment.
Conflicting Tailwind width utilities in
PinnedSubContent
The component hardcodes w-auto in its class string, then appends the caller's className (always "w-64 p-0") after it. This produces ...w-auto w-64 p-0 on the same element. When two Tailwind utilities targeting the same CSS property appear in the same class list, the winner is determined by which rule appears later in the compiled stylesheet — not by the order in the HTML attribute. This is an implementation detail of Tailwind's JIT compilation and is not guaranteed. Since cn is already available in the quill package (used in SidebarItem.tsx in this same directory), cn() would resolve the conflict reliably.
| <BaseMenu.Popup | |
| data-slot="dropdown-menu-sub-content" | |
| className={`quill-menu__content quill-menu__sub-content w-auto ${className ?? ""}`} | |
| > | |
| <BaseMenu.Popup | |
| data-slot="dropdown-menu-sub-content" | |
| className={`quill-menu__content quill-menu__sub-content ${className ?? ""}`} | |
| > |
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/ui/src/features/sidebar/components/ProjectSwitcher.tsx
Line: 417-420
Comment:
**Conflicting Tailwind width utilities in `PinnedSubContent`**
The component hardcodes `w-auto` in its class string, then appends the caller's `className` (always `"w-64 p-0"`) after it. This produces `...w-auto w-64 p-0` on the same element. When two Tailwind utilities targeting the same CSS property appear in the same class list, the winner is determined by which rule appears later in the compiled stylesheet — not by the order in the HTML attribute. This is an implementation detail of Tailwind's JIT compilation and is not guaranteed. Since `cn` is already available in the quill package (used in `SidebarItem.tsx` in this same directory), `cn()` would resolve the conflict reliably.
```suggestion
<BaseMenu.Popup
data-slot="dropdown-menu-sub-content"
className={`quill-menu__content quill-menu__sub-content ${className ?? ""}`}
>
```
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
|
For reviewers: I don’t feel strongly about the “open in browser” icons, it’s a bit much. |
charlesvien
left a comment
There was a problem hiding this comment.
This is much better, ty for this!

Problem
The account popover's "Change project" item opened a modal dialog, and there was no way to switch organizations from the app at all — switching to a project in another org was impossible. The main PostHog web app already solves this with separate Project and Organization sections with flyout pickers.
Changes
Replaces the single dialog with the web app's switcher pattern inside the lower-left account popover:
/organization/create-project,/create-organization) that opens the cloud app externally (withArrowSquareOutindicators, also added to the Discord link)Autocompleteinline) with the active item pinned first and a left-gutter checkmark, the rest locale-sorted to match web ordering/uploaded_media/...via the existinggetPostHogUrlhelper) with a deterministic colored-initial avatar fallback, like webuseSwitchOrgMutation; project switching stays onuseSelectProjectMutationPinnedSubContentpins the flyouts to open downward (collisionAvoidance: { align: "none" }) with a fixed list height, so filtering never resizes or flips the popup; quill'sDropdownMenuSubContentdoesn't forwardcollisionAvoidance, so this mirrors its markup with a TODO to upstream the propScreenshots to follow in a comment.
How did you test this?
pnpm dev:code): switched projects and orgs, searched both flyouts, verified active-first ordering, org logos/initials, external create links, and stable popup positioning while filteringgetPostHogUrl, TODO on the quill-internals fork, memoized item arrays/sort) are includedbiome checkclean;tscreports no errors in the changed file (the repo-widepnpm typecheckfailures inhost-router/useWorkspace.tsare pre-existing and untouched by this PR)Automatic notifications
Created with PostHog Code