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 = ( GitHub icon ) 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( () => 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 { form: UseFormReturn name: Path label: string description?: ReactNode layout?: ComponentProps['layout'] disabled?: boolean selectedRepositoryName?: string installationIdField?: Path repositoryNameField?: Path repositories: GitHubRepository[] gitHubAuthorization: unknown | null hasPartialResponseDueToSSO?: boolean isLoading?: boolean placeholder?: string refetch: () => void onConnectClick?: () => void onRepositorySelect?: (repo: GitHubRepository) => void } export const GitHubRepositoryField = ({ 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) => { const [isRepoSelectorOpen, setIsRepoSelectorOpen] = useState(false) const currentRepositoryId = form.watch(name) as string | undefined const selectedRepository = repositories.find((repo) => repo.id === currentRepositoryId) return ( ( {gitHubAuthorization === null ? ( { onConnectClick?.() openInstallGitHubIntegrationWindow('authorize', refetch) }} icon={GITHUB_ICON} > Connect GitHub ) : ( } > {selectedRepository?.name || selectedRepositoryName || (isLoading ? 'Loading GitHub repositories...' : placeholder)} No repositories found. {repositories.length > 0 ? ( {repositories.map((repo) => ( { 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} {repo.name} ))} ) : null} { setIsRepoSelectorOpen(false) openInstallGitHubIntegrationWindow('install', refetch) }} > Add GitHub Repositories {hasPartialResponseDueToSSO && ( <> { setIsRepoSelectorOpen(false) openInstallGitHubIntegrationWindow('authorize', refetch) }} > Re-authorize GitHub with SSO to show all repositories > )} )} )} /> ) }