diff --git a/apps/studio/components/interfaces/Settings/Integrations/GithubIntegration/GitHubIntegrationConnectionForm.tsx b/apps/studio/components/interfaces/Settings/Integrations/GithubIntegration/GitHubIntegrationConnectionForm.tsx index 1d9d98afe9d..cb022790ea9 100644 --- a/apps/studio/components/interfaces/Settings/Integrations/GithubIntegration/GitHubIntegrationConnectionForm.tsx +++ b/apps/studio/components/interfaces/Settings/Integrations/GithubIntegration/GitHubIntegrationConnectionForm.tsx @@ -1,30 +1,11 @@ import { zodResolver } from '@hookform/resolvers/zod' import { PermissionAction } from '@supabase/shared-types/out/constants' -import { IS_PLATFORM } from 'common' -import { useBranchCreateMutation } from 'data/branches/branch-create-mutation' -import { useBranchUpdateMutation } from 'data/branches/branch-update-mutation' -import { useBranchesQuery } from 'data/branches/branches-query' -import { useGitHubAuthorizationQuery } from 'data/integrations/github-authorization-query' -import { useCheckGithubBranchValidity } from 'data/integrations/github-branch-check-query' -import { useGitHubConnectionCreateMutation } from 'data/integrations/github-connection-create-mutation' -import { useGitHubConnectionDeleteMutation } from 'data/integrations/github-connection-delete-mutation' -import { useGitHubConnectionUpdateMutation } from 'data/integrations/github-connection-update-mutation' -import { useGitHubRepositoriesQuery } from 'data/integrations/github-repositories-query' -import type { GitHubConnection } from 'data/integrations/integrations.types' -import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions' -import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' -import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' -import { DOCS_URL } from 'lib/constants' -import { openInstallGitHubIntegrationWindow } from 'lib/github' -import { EMPTY_ARR } from 'lib/void' +import { AnimatePresence, motion } from 'framer-motion' import { ChevronDown, Loader2, PlusIcon, RefreshCw } from 'lucide-react' import { useEffect, useMemo, useState } from 'react' import { useForm } from 'react-hook-form' import { toast } from 'sonner' import { - Alert_Shadcn_, - AlertDescription_Shadcn_, - AlertTitle_Shadcn_, Button, Card, CardContent, @@ -46,11 +27,30 @@ import { PopoverTrigger_Shadcn_, Switch, } from 'ui' -import { InlineLink } from 'components/ui/InlineLink' +import { Admonition } from 'ui-patterns/admonition' import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import * as z from 'zod' + +import { InlineLink } from '@/components/ui/InlineLink' +import { UpgradeToPro } from '@/components/ui/UpgradeToPro' +import { useBranchCreateMutation } from '@/data/branches/branch-create-mutation' +import { useBranchUpdateMutation } from '@/data/branches/branch-update-mutation' +import { useBranchesQuery } from '@/data/branches/branches-query' +import { useGitHubAuthorizationQuery } from '@/data/integrations/github-authorization-query' +import { useCheckGithubBranchValidity } from '@/data/integrations/github-branch-check-query' +import { useGitHubConnectionCreateMutation } from '@/data/integrations/github-connection-create-mutation' +import { useGitHubConnectionDeleteMutation } from '@/data/integrations/github-connection-delete-mutation' +import { useGitHubConnectionUpdateMutation } from '@/data/integrations/github-connection-update-mutation' +import { useGitHubRepositoriesQuery } from '@/data/integrations/github-repositories-query' +import type { GitHubConnection } from '@/data/integrations/integrations.types' import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements' +import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions' +import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' +import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' +import { DOCS_URL } from '@/lib/constants' +import { openInstallGitHubIntegrationWindow } from '@/lib/github' +import { EMPTY_ARR } from '@/lib/void' const GITHUB_ICON = ( @@ -69,7 +69,7 @@ interface GitHubIntegrationConnectionFormProps { connection?: GitHubConnection } -const GitHubIntegrationConnectionForm = ({ +export const GitHubIntegrationConnectionForm = ({ disabled = false, connection, }: GitHubIntegrationConnectionFormProps) => { @@ -82,8 +82,8 @@ const GitHubIntegrationConnectionForm = ({ const { hasAccess: hasAccessToGitHubIntegration, isLoading: isLoadingEntitlements } = useCheckEntitlements('integrations.github_connections') - const promptProPlanUpgrade = - IS_PLATFORM && !isLoadingEntitlements && !hasAccessToGitHubIntegration + + const { hasAccess: hasAccessToBranching } = useCheckEntitlements('branching_limit') const { can: canUpdateGitHubConnection } = useAsyncCheckPermissions( PermissionAction.UPDATE, @@ -460,7 +460,7 @@ const GitHubIntegrationConnectionForm = ({
- ( - - - - - - )} - /> -
+ {!!currentRepositoryId && ( + - ( - -
+ + ( + -
- {isCheckingBranch && } -
-
-
- )} - /> -
-
- - - - Branching and billing - - Branching Compute is not covered by your organization's Spend Cap. Costs - should be closely monitored, as they may be incurred.{' '} - - Learn more - - - - {/* Automatic Branching Section */} -
- ( - - - + )} + /> + + + {/* Production Branch Sync Section */} +
+ ( + + + + + + )} + /> + +
+ ( + +
+ + + +
+ {isCheckingBranch && ( + + )} +
+
+
+ )} /> - - - )} - /> - -
- ( - - - - - +
+
+ + + {hasAccessToBranching ? ( + + Branching Compute is not covered by your organization's Spend Cap. + Costs should be closely monitored, as they may be incurred.{' '} + + Learn more + + + ) : ( + )} - /> - ( - + ( + + + + + + )} + /> + +
- - field.onChange(val)} - disabled={!newBranchPerPr || disabled || !canUpdateGitHubConnection} - /> - - - )} - /> -
-
-
- -
- {connection && ( - - )} -
-
- {githubSettingsForm.formState.isDirty && ( - - )} - -
-
+ ( + + + + + + )} + /> + + ( + + + field.onChange(val)} + disabled={ + !hasAccessToBranching || + !newBranchPerPr || + !canUpdateGitHubConnection + } + /> + + + )} + /> +
+ +
+ +
+ {connection && ( + + )} +
+
+ {githubSettingsForm.formState.isDirty && ( + + )} + +
+
+ + )} + @@ -801,5 +832,3 @@ const GitHubIntegrationConnectionForm = ({ ) } - -export default GitHubIntegrationConnectionForm diff --git a/apps/studio/components/interfaces/Settings/Integrations/GithubIntegration/GithubSection.tsx b/apps/studio/components/interfaces/Settings/Integrations/GithubIntegration/GithubSection.tsx index 9ce834daa0b..4d87acfc1be 100644 --- a/apps/studio/components/interfaces/Settings/Integrations/GithubIntegration/GithubSection.tsx +++ b/apps/studio/components/interfaces/Settings/Integrations/GithubIntegration/GithubSection.tsx @@ -1,22 +1,22 @@ import { PermissionAction } from '@supabase/shared-types/out/constants' +import { IS_PLATFORM, useFlag, useParams } from 'common' import { useMemo } from 'react' +import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader' -import { useGitHubAuthorizationQuery } from '@/data/integrations/github-authorization-query' -import { useParams } from 'common' +import { GitHubIntegrationConnectionForm } from './GitHubIntegrationConnectionForm' import { ScaffoldContainer, ScaffoldSection, ScaffoldSectionContent, ScaffoldSectionDetail, -} from 'components/layouts/Scaffold' -import NoPermission from 'components/ui/NoPermission' -import { UpgradeToPro } from 'components/ui/UpgradeToPro' -import { useGitHubConnectionsQuery } from 'data/integrations/github-connections-query' -import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions' -import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' -import { BASE_PATH, IS_PLATFORM } from 'lib/constants' -import { GenericSkeletonLoader } from 'ui-patterns' -import GitHubIntegrationConnectionForm from './GitHubIntegrationConnectionForm' +} from '@/components/layouts/Scaffold' +import NoPermission from '@/components/ui/NoPermission' +import { UpgradeToPro } from '@/components/ui/UpgradeToPro' +import { useGitHubAuthorizationQuery } from '@/data/integrations/github-authorization-query' +import { useGitHubConnectionsQuery } from '@/data/integrations/github-connections-query' +import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions' +import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' +import { BASE_PATH } from '@/lib/constants' const IntegrationImageHandler = ({ title }: { title: 'vercel' | 'github' }) => { return ( @@ -37,6 +37,7 @@ export const GitHubSection = () => { const isProPlanAndUp = organization?.plan?.id !== 'free' const promptProPlanUpgrade = IS_PLATFORM && !isProPlanAndUp + const isGithubOnFreePlan = useFlag('githubOnFreePlan') const { data: gitHubAuthorization } = useGitHubAuthorizationQuery() @@ -74,7 +75,7 @@ export const GitHubSection = () => { branches for every pull request.

- {promptProPlanUpgrade && ( + {!isGithubOnFreePlan && promptProPlanUpgrade && (
{
)} - {/* [Joshen] Show connection form if GH has already been authorized OR no GH authorization but on a paid plan */} - {/* So this shouldn't render if there's no GH authorization and on a free plan */} - {(!!gitHubAuthorization || !promptProPlanUpgrade) && ( + {/* [Joshen] Show connection form only if one of the following is true: + - GH has already been authorized OR + - no GH authorization but on a paid plan OR + - on a free plan but the GitHub integration flag is enabled + */} + {(!!gitHubAuthorization || !promptProPlanUpgrade || isGithubOnFreePlan) && ( void } -export function ProjectBranchSelectorTrigger({ - displayProjectName, - selectedOrgInitial, - isBranch, - branchDisplayName, - onClick, -}: ProjectBranchSelectorTriggerProps) { - return ( - -
- {selectedOrgInitial} -
-
-
- {displayProjectName} +export const ProjectBranchSelectorTrigger = forwardRef< + HTMLButtonElement, + ProjectBranchSelectorTriggerProps +>( + ( + { + displayProjectName, + selectedOrgInitial, + isBranch, + branchDisplayName, + onClick, + }: ProjectBranchSelectorTriggerProps, + ref + ) => { + return ( + +
+ {selectedOrgInitial}
-
- - {branchDisplayName} +
+
+ {displayProjectName} +
+
+ + {branchDisplayName} +
-
- -
- ) -} + + + ) + } +) + +ProjectBranchSelectorTrigger.displayName = 'ProjectBranchSelectorTrigger' diff --git a/apps/studio/components/ui/UpgradeToPro.tsx b/apps/studio/components/ui/UpgradeToPro.tsx index e7059d417d9..c7e8b5ebf28 100644 --- a/apps/studio/components/ui/UpgradeToPro.tsx +++ b/apps/studio/components/ui/UpgradeToPro.tsx @@ -1,7 +1,8 @@ import { ReactNode } from 'react' - import { cn } from 'ui' import { Admonition } from 'ui-patterns' + +import { DocsButton } from './DocsButton' import { UpgradePlanButton } from './UpgradePlanButton' interface UpgradeToProProps { @@ -21,6 +22,7 @@ interface UpgradeToProProps { layout?: 'vertical' | 'horizontal' variant?: 'default' | 'primary' className?: string + docsUrl?: string } export const UpgradeToPro = ({ @@ -37,6 +39,7 @@ export const UpgradeToPro = ({ layout = 'horizontal', variant = 'primary', className, + docsUrl, }: UpgradeToProProps) => { return ( - {buttonText} - + <> + + {buttonText} + + {!!docsUrl && } + } /> )