diff --git a/apps/studio/components/interfaces/BranchManagement/ConnectToGitHub.tsx b/apps/studio/components/interfaces/BranchManagement/ConnectToGitHub.tsx new file mode 100644 index 00000000000..d4256ee9e34 --- /dev/null +++ b/apps/studio/components/interfaces/BranchManagement/ConnectToGitHub.tsx @@ -0,0 +1,56 @@ +import { useParams } from 'common' +import { Github } from 'lucide-react' +import { useRouter } from 'next/router' +import { Button } from 'ui' + +import { useGitHubAuthorizationQuery } from '@/data/integrations/github-authorization-query' +import { useGitHubConnectionsQuery } from '@/data/integrations/github-connections-query' +import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' +import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' +import { openInstallGitHubIntegrationWindow } from '@/lib/github' +import { useAppStateSnapshot } from '@/state/app-state' + +export const ConnectToGitHub = () => { + const router = useRouter() + const { ref } = useParams() + const { data: project } = useSelectedProjectQuery() + const { data: selectedOrg } = useSelectedOrganizationQuery() + const { showCreateBranchModal, setShowCreateBranchModal } = useAppStateSnapshot() + + const isBranch = project?.parent_project_ref !== undefined + const projectRef = + project !== undefined ? (isBranch ? project.parent_project_ref : ref) : undefined + + const { data: gitHubAuthorization } = useGitHubAuthorizationQuery() + + const { data: connections } = useGitHubConnectionsQuery( + { organizationId: selectedOrg?.id }, + { enabled: showCreateBranchModal } + ) + const githubConnection = connections?.find((connection) => connection.project.ref === projectRef) + + const showAuthorizeCta = githubConnection && !gitHubAuthorization + + const onClick = () => { + if (showAuthorizeCta) { + openInstallGitHubIntegrationWindow('authorize') + } else { + if (showCreateBranchModal) setShowCreateBranchModal(false) + router.push(`/project/${projectRef}/settings/integrations`) + } + } + + return ( +
+
+ Sync with a GitHub branch +

+ Keep this preview branch in sync with a chosen GitHub branch +

+
+ +
+ ) +} diff --git a/apps/studio/components/interfaces/BranchManagement/CreateBranchModal.tsx b/apps/studio/components/interfaces/BranchManagement/CreateBranchModal.tsx index 1f50e17d6d6..d282a1e5eeb 100644 --- a/apps/studio/components/interfaces/BranchManagement/CreateBranchModal.tsx +++ b/apps/studio/components/interfaces/BranchManagement/CreateBranchModal.tsx @@ -3,7 +3,7 @@ import { PermissionAction } from '@supabase/shared-types/out/constants' import { useQueryClient } from '@tanstack/react-query' import { useDebounce } from '@uidotdev/usehooks' import { useFlag, useParams } from 'common' -import { Check, DatabaseZap, DollarSign, Github, GitMerge, Loader2 } from 'lucide-react' +import { Check, DatabaseZap, DollarSign, GitMerge, Loader2 } from 'lucide-react' import Image from 'next/image' import Link from 'next/link' import { useRouter } from 'next/router' @@ -25,7 +25,6 @@ import { FormControl, FormField, Input, - Label, Switch, Tooltip, TooltipContent, @@ -40,6 +39,7 @@ import { estimateDiskCost, estimateRestoreTime, } from './BranchManagement.utils' +import { ConnectToGitHub } from './ConnectToGitHub' import { TaxDisclaimer } from '@/components/interfaces/Billing/TaxDisclaimer' import { getInfrastructurePath } from '@/components/interfaces/Settings/Infrastructure/Infrastructure.utils' import { BranchingPITRNotice } from '@/components/layouts/AppLayout/EnableBranchingButton/BranchingPITRNotice' @@ -50,6 +50,7 @@ import { UpgradeToPro } from '@/components/ui/UpgradeToPro' import { useBranchCreateMutation } from '@/data/branches/branch-create-mutation' import { useBranchesQuery } from '@/data/branches/branches-query' import { DiskAttributesData, useDiskAttributesQuery } from '@/data/config/disk-attributes-query' +import { useGitHubAuthorizationQuery } from '@/data/integrations/github-authorization-query' import { useCheckGithubBranchValidity } from '@/data/integrations/github-branch-check-query' import { useGitHubConnectionsQuery } from '@/data/integrations/github-connections-query' import { projectKeys } from '@/data/projects/keys' @@ -118,6 +119,14 @@ export const CreateBranchModal = () => { }) const debouncedGitBranchName = useDebounce(gitBranchName, 500) + const { + data: githubAuthorization, + error: authorizationError, + isPending: isLoadingAuthorization, + isSuccess: isSuccessAuthorization, + isError: isErrorAuthorization, + } = useGitHubAuthorizationQuery() + const { data: connections, error: connectionsError, @@ -129,6 +138,11 @@ export const CreateBranchModal = () => { { enabled: showCreateBranchModal } ) + const isLoading = isLoadingAuthorization || isLoadingConnections + const isSuccess = isSuccessAuthorization && isSuccessConnections + const isError = isErrorAuthorization || isErrorConnections + const error = authorizationError || connectionsError + const { data: branches } = useBranchesQuery({ projectRef }) const { data: addons, isSuccess: isSuccessAddons } = useProjectAddonsQuery( { projectRef }, @@ -260,11 +274,6 @@ export const CreateBranchModal = () => { }) } - const handleGitHubClick = () => { - setShowCreateBranchModal(false) - router.push(`/project/${projectRef}/settings/integrations`) - } - useEffect(() => { if (showCreateBranchModal) form.reset() }, [form, showCreateBranchModal]) @@ -323,22 +332,24 @@ export const CreateBranchModal = () => { )} /> - {isLoadingConnections && ( + {isLoading && (
)} - {isErrorConnections && ( + {isError && ( )} - {isSuccessConnections && - (githubConnection ? ( + {isSuccess && + (!githubAuthorization || !githubConnection ? ( + + ) : ( { } labelOptional="Optional" - description="Automatically deploy changes on every commit" + description={ + githubAuthorization + ? 'Automatically deploy changes on every commit' + : undefined + } >
@@ -394,18 +409,6 @@ export const CreateBranchModal = () => { )} /> - ) : ( -
-
- -

- Keep this preview branch in sync with a chosen GitHub branch -

-
- -
))} {allowDataBranching && ( @@ -416,7 +419,7 @@ export const CreateBranchModal = () => { - + Include data {!hasPitrEnabled && Requires PITR} } @@ -426,6 +429,7 @@ export const CreateBranchModal = () => { > { const { ref } = useParams() - const router = useRouter() const { data: projectDetails } = useSelectedProjectQuery() const { data: selectedOrg } = useSelectedOrganizationQuery() @@ -55,6 +54,14 @@ export const EditBranchModal = ({ branch, visible, onClose }: EditBranchModalPro const projectRef = projectDetails !== undefined ? (isBranch ? projectDetails.parent_project_ref : ref) : undefined + const { + data: githubAuthorization, + error: authorizationError, + isPending: isLoadingAuthorization, + isSuccess: isSuccessAuthorization, + isError: isErrorAuthorization, + } = useGitHubAuthorizationQuery() + const { data: connections, error: connectionsError, @@ -65,6 +72,11 @@ export const EditBranchModal = ({ branch, visible, onClose }: EditBranchModalPro organizationId: selectedOrg?.id, }) + const isLoading = isLoadingAuthorization || isLoadingConnections + const isSuccess = isSuccessAuthorization && isSuccessConnections + const isError = isErrorAuthorization || isErrorConnections + const error = authorizationError || connectionsError + const { data: branches } = useBranchesQuery({ projectRef }) const { mutate: checkGithubBranchValidity, isPending: isChecking } = useCheckGithubBranchValidity( { onError: () => {} } @@ -113,14 +125,6 @@ export const EditBranchModal = ({ branch, visible, onClose }: EditBranchModalPro const isFormValid = form.formState.isValid && (!gitBranchName || isGitBranchValid) const canSubmit = isFormValid && !isUpdating && !isChecking - const openLinkerPanel = () => { - onClose() - - if (projectRef) { - router.push(`/project/${projectRef}/settings/integrations`) - } - } - const onSubmit = (data: z.infer) => { if (!projectRef) return console.error('Project ref is required') if (!branch?.project_ref) return console.error('Branch ref is required') @@ -179,8 +183,9 @@ export const EditBranchModal = ({ branch, visible, onClose }: EditBranchModalPro if (form.getValues('gitBranchName') !== requested) return setIsGitBranchValid(false) form.setError('gitBranchName', { - ...error, - message: `Unable to find branch "${branchName}" in ${repoOwner}/${repoName}`, + message: + error?.message ?? + `Unable to find branch "${branchName}" in ${repoOwner}/${repoName}`, }) }, } @@ -234,22 +239,24 @@ export const EditBranchModal = ({ branch, visible, onClose }: EditBranchModalPro )} /> - {isLoadingConnections && ( + {isLoading && (
)} - {isErrorConnections && ( + {isError && ( )} - {isSuccessConnections && - (githubConnection ? ( + {isSuccess && + (!githubAuthorization || !githubConnection ? ( + + ) : ( )} /> - ) : ( -
-
-
- -
-

- Optionally connect to a GitHub repository to manage migrations automatically - for this branch. -

-
- -
))}