mirror of
https://github.com/supabase/supabase.git
synced 2026-06-15 18:17:09 +08:00
## Problem The `_Shadcn_` suffix isn't needed anymore on `Command` components ## Solution - Remove the `_Shadcn_` suffix - Simplify UI package exports - Apply prettier <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Refactor** * Simplified command component imports and exports across the UI library by removing internal naming aliases and adopting direct component references. Updated the public UI package barrel export to use wildcard re-exports for cleaner API surface. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/supabase/supabase/pull/46153?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
173 lines
6.3 KiB
TypeScript
173 lines
6.3 KiB
TypeScript
import { useBreakpoint, useParams } from 'common'
|
|
import { Boxes, ChevronsUpDown, Plus } from 'lucide-react'
|
|
import Link from 'next/link'
|
|
import { useRouter } from 'next/router'
|
|
import { useState } from 'react'
|
|
import {
|
|
Command,
|
|
CommandEmpty,
|
|
CommandGroup,
|
|
CommandInput,
|
|
CommandItem,
|
|
CommandList,
|
|
CommandSeparator,
|
|
Popover,
|
|
PopoverContent,
|
|
PopoverTrigger,
|
|
ScrollArea,
|
|
SidebarMenu,
|
|
SidebarMenuButton,
|
|
SidebarMenuItem,
|
|
} from 'ui'
|
|
import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
|
|
|
|
import { OrgSelectorSheet } from './OrgSelectorSheet'
|
|
import { OrgCommandItem } from '@/components/layouts/AppLayout/OrgCommandItem'
|
|
import { useOrganizationsQuery } from '@/data/organizations/organizations-query'
|
|
import { useOrgProjectsInfiniteQuery } from '@/data/projects/org-projects-infinite-query'
|
|
import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
|
|
import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
|
|
|
|
export function OrgSelector() {
|
|
const router = useRouter()
|
|
const { slug: routeSlug } = useParams()
|
|
const { data: selectedOrganization } = useSelectedOrganizationQuery()
|
|
const { data: organizations, isPending: isLoadingOrganizations } = useOrganizationsQuery()
|
|
const organizationCreationEnabled = useIsFeatureEnabled('organizations:create')
|
|
|
|
const [open, setOpen] = useState(false)
|
|
|
|
const slug = selectedOrganization?.slug
|
|
const isPlatformOrg = selectedOrganization?.plan?.id === 'platform'
|
|
const selectedOrgInitial = selectedOrganization?.name?.trim().charAt(0).toUpperCase() || 'O'
|
|
const { data: projects } = useOrgProjectsInfiniteQuery(
|
|
{ slug, limit: 1 },
|
|
{ enabled: Boolean(slug) && !isPlatformOrg }
|
|
)
|
|
|
|
const numProjects = projects?.pages[0]?.pagination.count
|
|
const projectsLabel = isPlatformOrg
|
|
? 'Platform'
|
|
: typeof numProjects === 'number'
|
|
? `${numProjects} project${numProjects === 1 ? '' : 's'}`
|
|
: 'No projects'
|
|
|
|
const isMobile = useBreakpoint('md')
|
|
|
|
if (isLoadingOrganizations) return <ShimmeringLoader className="ml-1 w-[120px]" />
|
|
|
|
const triggerButton = (
|
|
<SidebarMenuButton
|
|
size="lg"
|
|
className="data-open:bg-sidebar-accent data-open:text-sidebar-accent-foreground gap-2 h-auto text-left group px-1.5 py-1 touch-manipulation"
|
|
onClick={isMobile ? () => setOpen(true) : undefined}
|
|
>
|
|
<span className="flex w-8 aspect-square shrink-0 items-center justify-center rounded-sm border bg-surface-100 text-xs font-medium text-foreground-lighter">
|
|
{selectedOrgInitial}
|
|
</span>
|
|
<div className="flex min-w-0 flex-1 flex-col text-left -mb-0.5">
|
|
<div className="truncate text-foreground font-medium leading-tight min-w-[100px] max-w-[250px]">
|
|
{selectedOrganization?.name ?? 'Select organization'}
|
|
</div>
|
|
{selectedOrganization && (
|
|
<div className="flex items-center gap-1 truncate text-foreground-light leading-tight text-xs">
|
|
<Boxes className="shrink-0 size-3" strokeWidth={1.5} />
|
|
<span>{projectsLabel}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
<ChevronsUpDown
|
|
strokeWidth={1}
|
|
className="ml-auto text-foreground-light md:hidden md:group-hover:block w-4! h-4!"
|
|
/>
|
|
</SidebarMenuButton>
|
|
)
|
|
|
|
if (isMobile) {
|
|
return (
|
|
<>
|
|
<SidebarMenu className="shrink">
|
|
<SidebarMenuItem>
|
|
{isLoadingOrganizations ? <ShimmeringLoader className="p-2 w-[90px]" /> : triggerButton}
|
|
</SidebarMenuItem>
|
|
</SidebarMenu>
|
|
<OrgSelectorSheet
|
|
open={open}
|
|
onOpenChange={setOpen}
|
|
onClose={() => setOpen(false)}
|
|
selectedOrganization={selectedOrganization ?? null}
|
|
/>
|
|
</>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<SidebarMenu>
|
|
<SidebarMenuItem>
|
|
<Popover open={open} onOpenChange={setOpen} modal={false}>
|
|
<PopoverTrigger asChild>{triggerButton}</PopoverTrigger>
|
|
<PopoverContent className="p-0" side="bottom" align="start">
|
|
<Command>
|
|
<CommandInput placeholder="Find organization..." />
|
|
<CommandList>
|
|
<CommandEmpty>No organizations found</CommandEmpty>
|
|
<CommandGroup>
|
|
<ScrollArea
|
|
className={(organizations || []).length > 7 ? 'h-full md:h-[210px]' : ''}
|
|
>
|
|
{organizations?.map((org) => (
|
|
<OrgCommandItem
|
|
key={org.slug}
|
|
org={org}
|
|
selectedSlug={slug}
|
|
routePathname={router.pathname}
|
|
hasRouteSlug={!!routeSlug}
|
|
onClose={() => setOpen(false)}
|
|
/>
|
|
))}
|
|
</ScrollArea>
|
|
</CommandGroup>
|
|
<CommandSeparator />
|
|
<CommandGroup>
|
|
<CommandItem
|
|
className="cursor-pointer w-full"
|
|
onSelect={() => {
|
|
setOpen(false)
|
|
router.push('/organizations')
|
|
}}
|
|
onClick={() => setOpen(false)}
|
|
>
|
|
<Link href="/organizations" className="flex items-center gap-2 w-full">
|
|
<p>All Organizations</p>
|
|
</Link>
|
|
</CommandItem>
|
|
</CommandGroup>
|
|
{organizationCreationEnabled && (
|
|
<>
|
|
<CommandSeparator />
|
|
<CommandGroup>
|
|
<CommandItem
|
|
className="cursor-pointer w-full"
|
|
onSelect={() => {
|
|
setOpen(false)
|
|
router.push('/new')
|
|
}}
|
|
onClick={() => setOpen(false)}
|
|
>
|
|
<Link href="/new" className="flex items-center gap-2 w-full">
|
|
<Plus size={14} strokeWidth={1.5} />
|
|
<p>New organization</p>
|
|
</Link>
|
|
</CommandItem>
|
|
</CommandGroup>
|
|
</>
|
|
)}
|
|
</CommandList>
|
|
</Command>
|
|
</PopoverContent>
|
|
</Popover>
|
|
</SidebarMenuItem>
|
|
</SidebarMenu>
|
|
)
|
|
}
|