mirror of
https://github.com/supabase/supabase.git
synced 2026-10-08 19:05:06 +03: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 -->
256 lines
9.5 KiB
TypeScript
256 lines
9.5 KiB
TypeScript
import { ChevronDown, PlusIcon, RefreshCw } from 'lucide-react'
|
|
import { useMemo, useState, type ComponentProps, type ReactNode } from 'react'
|
|
import type { FieldValues, Path, UseFormReturn } from 'react-hook-form'
|
|
import {
|
|
Button,
|
|
Command,
|
|
CommandEmpty,
|
|
CommandGroup,
|
|
CommandInput,
|
|
CommandItem,
|
|
CommandList,
|
|
CommandSeparator,
|
|
FormControl,
|
|
FormField,
|
|
Popover,
|
|
PopoverContent,
|
|
PopoverTrigger,
|
|
} from 'ui'
|
|
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
|
|
|
import { useGitHubAuthorizationQuery } from '@/data/integrations/github-authorization-query'
|
|
import { useGitHubRepositoriesQuery } from '@/data/integrations/github-repositories-query'
|
|
import { openInstallGitHubIntegrationWindow } from '@/lib/github'
|
|
import { EMPTY_ARR } from '@/lib/void'
|
|
|
|
export type GitHubRepository = {
|
|
id: string
|
|
name: string
|
|
installation_id: number
|
|
default_branch: string
|
|
}
|
|
|
|
export const GITHUB_ICON = (
|
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 98 96" className="w-5 shrink-0">
|
|
<title>GitHub icon</title>
|
|
<path
|
|
fill="currentColor"
|
|
fillRule="evenodd"
|
|
d="M48.854 0C21.839 0 0 22 0 49.217c0 21.756 13.993 40.172 33.405 46.69 2.427.49 3.316-1.059 3.316-2.362 0-1.141-.08-5.052-.08-9.127-13.59 2.934-16.42-5.867-16.42-5.867-2.184-5.704-5.42-7.17-5.42-7.17-4.448-3.015.324-3.015.324-3.015 4.934.326 7.523 5.052 7.523 5.052 4.367 7.496 11.404 5.378 14.235 4.074.404-3.178 1.699-5.378 3.074-6.6-10.839-1.141-22.243-5.378-22.243-24.283 0-5.378 1.94-9.778 5.014-13.2-.485-1.222-2.184-6.275.486-13.038 0 0 4.125-1.304 13.426 5.052a46.97 46.97 0 0 1 12.214-1.63c4.125 0 8.33.571 12.213 1.63 9.302-6.356 13.427-5.052 13.427-5.052 2.67 6.763.97 11.816.485 13.038 3.155 3.422 5.015 7.822 5.015 13.2 0 18.905-11.404 23.06-22.324 24.283 1.78 1.548 3.316 4.481 3.316 9.126 0 6.6-.08 11.897-.08 13.526 0 1.304.89 2.853 3.316 2.364 19.412-6.52 33.405-24.935 33.405-46.691C97.707 22 75.788 0 48.854 0z"
|
|
clipRule="evenodd"
|
|
/>
|
|
</svg>
|
|
)
|
|
|
|
export const useGitHubRepositoryOptions = () => {
|
|
const {
|
|
data: gitHubAuthorization,
|
|
isPending: isLoadingGitHubAuthorization,
|
|
refetch: refetchGitHubAuthorization,
|
|
} = useGitHubAuthorizationQuery()
|
|
|
|
const {
|
|
data: githubReposData,
|
|
isPending: isLoadingGitHubRepos,
|
|
refetch: refetchGitHubRepositories,
|
|
} = useGitHubRepositoriesQuery({
|
|
enabled: Boolean(gitHubAuthorization),
|
|
})
|
|
|
|
const githubRepos = useMemo<GitHubRepository[]>(
|
|
() =>
|
|
githubReposData?.repositories?.map((repo) => ({
|
|
id: repo.id.toString(),
|
|
name: repo.name,
|
|
installation_id: repo.installation_id,
|
|
default_branch: repo.default_branch || 'main',
|
|
})) ?? EMPTY_ARR,
|
|
[githubReposData]
|
|
)
|
|
|
|
const refetchGitHubAuthorizationAndRepositories = () => {
|
|
setTimeout(() => {
|
|
refetchGitHubAuthorization()
|
|
refetchGitHubRepositories()
|
|
}, 2000)
|
|
}
|
|
|
|
return {
|
|
gitHubAuthorization,
|
|
githubRepos,
|
|
hasPartialResponseDueToSSO: githubReposData?.partial_response_due_to_sso ?? false,
|
|
isLoading: isLoadingGitHubAuthorization || isLoadingGitHubRepos,
|
|
refetch: refetchGitHubAuthorizationAndRepositories,
|
|
}
|
|
}
|
|
|
|
interface GitHubRepositoryFieldProps<TFormValues extends FieldValues> {
|
|
form: UseFormReturn<TFormValues>
|
|
name: Path<TFormValues>
|
|
label: string
|
|
description?: ReactNode
|
|
layout?: ComponentProps<typeof FormItemLayout>['layout']
|
|
disabled?: boolean
|
|
selectedRepositoryName?: string
|
|
installationIdField?: Path<TFormValues>
|
|
repositoryNameField?: Path<TFormValues>
|
|
repositories: GitHubRepository[]
|
|
gitHubAuthorization: unknown | null
|
|
hasPartialResponseDueToSSO?: boolean
|
|
isLoading?: boolean
|
|
placeholder?: string
|
|
refetch: () => void
|
|
onConnectClick?: () => void
|
|
onRepositorySelect?: (repo: GitHubRepository) => void
|
|
}
|
|
|
|
export const GitHubRepositoryField = <TFormValues extends FieldValues>({
|
|
form,
|
|
name,
|
|
label,
|
|
description,
|
|
layout = 'horizontal',
|
|
disabled = false,
|
|
selectedRepositoryName,
|
|
installationIdField,
|
|
repositoryNameField,
|
|
repositories,
|
|
gitHubAuthorization,
|
|
hasPartialResponseDueToSSO = false,
|
|
isLoading = false,
|
|
placeholder = 'Choose GitHub repository',
|
|
refetch,
|
|
onConnectClick,
|
|
onRepositorySelect,
|
|
}: GitHubRepositoryFieldProps<TFormValues>) => {
|
|
const [isRepoSelectorOpen, setIsRepoSelectorOpen] = useState(false)
|
|
|
|
const currentRepositoryId = form.watch(name) as string | undefined
|
|
const selectedRepository = repositories.find((repo) => repo.id === currentRepositoryId)
|
|
|
|
return (
|
|
<FormField
|
|
control={form.control}
|
|
name={name}
|
|
render={({ field }) => (
|
|
<FormItemLayout label={label} layout={layout} description={description}>
|
|
{gitHubAuthorization === null ? (
|
|
<FormControl>
|
|
<Button
|
|
type="default"
|
|
size="small"
|
|
htmlType="button"
|
|
disabled={disabled}
|
|
onClick={() => {
|
|
onConnectClick?.()
|
|
openInstallGitHubIntegrationWindow('authorize', refetch)
|
|
}}
|
|
icon={GITHUB_ICON}
|
|
>
|
|
Connect GitHub
|
|
</Button>
|
|
</FormControl>
|
|
) : (
|
|
<Popover open={isRepoSelectorOpen} onOpenChange={setIsRepoSelectorOpen}>
|
|
<PopoverTrigger asChild>
|
|
<FormControl>
|
|
<Button
|
|
type="default"
|
|
htmlType="button"
|
|
className="justify-start h-[34px] w-full"
|
|
disabled={disabled || isLoading}
|
|
loading={isLoading}
|
|
icon={GITHUB_ICON}
|
|
iconRight={
|
|
<span className="grow flex justify-end">
|
|
<ChevronDown />
|
|
</span>
|
|
}
|
|
>
|
|
{selectedRepository?.name ||
|
|
selectedRepositoryName ||
|
|
(isLoading ? 'Loading GitHub repositories...' : placeholder)}
|
|
</Button>
|
|
</FormControl>
|
|
</PopoverTrigger>
|
|
<PopoverContent className="p-0" side="bottom" align="start" sameWidthAsTrigger>
|
|
<Command>
|
|
<CommandInput placeholder="Search repositories..." />
|
|
<CommandList className="!max-h-[220px]">
|
|
<CommandEmpty>No repositories found.</CommandEmpty>
|
|
{repositories.length > 0 ? (
|
|
<CommandGroup>
|
|
{repositories.map((repo) => (
|
|
<CommandItem
|
|
key={repo.id}
|
|
value={`${repo.name.replaceAll('"', '')}-${repo.id}`}
|
|
className="flex gap-2 items-center"
|
|
onSelect={() => {
|
|
field.onChange(repo.id)
|
|
|
|
if (installationIdField !== undefined) {
|
|
form.setValue(installationIdField, repo.installation_id as never, {
|
|
shouldDirty: true,
|
|
})
|
|
}
|
|
|
|
if (repositoryNameField !== undefined) {
|
|
form.setValue(repositoryNameField, repo.name as never, {
|
|
shouldDirty: true,
|
|
})
|
|
}
|
|
|
|
onRepositorySelect?.(repo)
|
|
setIsRepoSelectorOpen(false)
|
|
}}
|
|
>
|
|
{GITHUB_ICON}
|
|
<span className="truncate" title={repo.name}>
|
|
{repo.name}
|
|
</span>
|
|
</CommandItem>
|
|
))}
|
|
</CommandGroup>
|
|
) : null}
|
|
<CommandGroup>
|
|
<CommandItem
|
|
className="flex gap-2 items-center cursor-pointer"
|
|
onSelect={() => {
|
|
setIsRepoSelectorOpen(false)
|
|
openInstallGitHubIntegrationWindow('install', refetch)
|
|
}}
|
|
>
|
|
<PlusIcon size={16} />
|
|
Add GitHub Repositories
|
|
</CommandItem>
|
|
</CommandGroup>
|
|
{hasPartialResponseDueToSSO && (
|
|
<>
|
|
<CommandSeparator />
|
|
<CommandGroup>
|
|
<CommandItem
|
|
className="flex gap-2 items-start cursor-pointer"
|
|
onSelect={() => {
|
|
setIsRepoSelectorOpen(false)
|
|
openInstallGitHubIntegrationWindow('authorize', refetch)
|
|
}}
|
|
>
|
|
<RefreshCw size={16} className="mt-0.5 shrink-0" />
|
|
<div className="text-xs text-foreground-light">
|
|
Re-authorize GitHub with SSO to show all repositories
|
|
</div>
|
|
</CommandItem>
|
|
</CommandGroup>
|
|
</>
|
|
)}
|
|
</CommandList>
|
|
</Command>
|
|
</PopoverContent>
|
|
</Popover>
|
|
)}
|
|
</FormItemLayout>
|
|
)}
|
|
/>
|
|
)
|
|
}
|