import { zodResolver } from '@hookform/resolvers/zod' import { useParams } from 'common' import { Check, ExternalLink, Loader2 } from 'lucide-react' import Link from 'next/link' import { useEffect, useState } from 'react' import { useForm } from 'react-hook-form' import { toast } from 'sonner' import * as z from 'zod' import AlertError from 'components/ui/AlertError' import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader' import { useBranchCreateMutation } from 'data/branches/branch-create-mutation' import { useBranchesQuery } from 'data/branches/branches-query' import { useCheckGithubBranchValidity } from 'data/integrations/github-branch-check-query' import { useGitHubConnectionsQuery } from 'data/integrations/github-connections-query' import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' import { useSelectedProject } from 'hooks/misc/useSelectedProject' import { Button, FormControl_Shadcn_, FormField_Shadcn_, FormItem_Shadcn_, FormMessage_Shadcn_, Form_Shadcn_, Input_Shadcn_, Modal, } from 'ui' import { Admonition } from 'ui-patterns' interface CreateBranchModalProps { visible: boolean onClose: () => void } const CreateBranchModal = ({ visible, onClose }: CreateBranchModalProps) => { const { ref } = useParams() const projectDetails = useSelectedProject() const selectedOrg = useSelectedOrganization() // [Joshen] There's something weird with RHF that I can't figure out atm // but calling form.formState.isValid somehow removes the onBlur check, // and makes the validation run onChange instead. This is a workaround const [isValid, setIsValid] = useState(false) const isBranch = projectDetails?.parent_project_ref !== undefined const projectRef = projectDetails !== undefined ? (isBranch ? projectDetails.parent_project_ref : ref) : undefined const { data: connections, error: connectionsError, isLoading: isLoadingConnections, isSuccess: isSuccessConnections, isError: isErrorConnections, } = useGitHubConnectionsQuery({ organizationId: selectedOrg?.id, }) const { data: branches } = useBranchesQuery({ projectRef }) const { mutateAsync: checkGithubBranchValidity, isLoading: isChecking } = useCheckGithubBranchValidity({ onError: () => {}, }) const { mutate: createBranch, isLoading: isCreating } = useBranchCreateMutation({ onSuccess: () => { toast.success('Successfully created new branch') onClose() }, }) const githubConnection = connections?.find( (connection) => connection.project.ref === projectDetails?.parentRef ) const [repoOwner, repoName] = githubConnection?.repository.name.split('/') ?? [] const formId = 'create-branch-form' const FormSchema = z.object({ branchName: z.string().superRefine(async (val, ctx) => { if ((branches ?? []).some((branch) => branch.git_branch === val)) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'This branch already has a Preview Branch', }) return } if (val.length > 0) { try { if (!githubConnection?.id) throw new Error('No GitHub connection found') await checkGithubBranchValidity({ connectionId: githubConnection.id, branchName: val, }) setIsValid(true) } catch (error) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: `Unable to find branch from ${repoOwner}/${repoName}`, }) setIsValid(false) return } } }), }) const form = useForm>({ mode: 'onBlur', reValidateMode: 'onBlur', resolver: zodResolver(FormSchema), defaultValues: { branchName: '' }, }) const canSubmit = form.getValues('branchName').length > 0 && !isChecking && isValid const onSubmit = (data: z.infer) => { if (!projectRef) return console.error('Project ref is required') createBranch({ projectRef, branchName: data.branchName, gitBranch: data.branchName }) } useEffect(() => { if (form && visible) { setIsValid(false) form.reset() } }, [form, visible]) return (
setIsValid(false)} > {isLoadingConnections && } {isErrorConnections && ( )} {isSuccessConnections && (

Your project is currently connected to the repository:

{githubConnection?.repository.name}

)}

Choose a Git Branch to base your Preview Branch on. Any migration changes added to this Git Branch will be run on this new Preview Branch.

(
{isChecking ? ( ) : isValid ? ( ) : null}
)} />
) } export default CreateBranchModal