feat: Enable Github on free plan under a feature flag (#44171)

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
This commit is contained in:
Ivan VasilovandJoshen Lim authored and GitHub committed 2026-03-25 11:54:30 +01:00
1 parent b84068f173
commit bd10880d52
4 files changed
+334 -283

No files matched your search

@@ -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 = (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 98 96" className="w-6">
@@ -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 = ({
<Button
type="default"
className="justify-start h-[34px] w-full"
disabled={disabled || isLoadingGitHubRepos}
disabled={isLoadingGitHubRepos}
loading={isLoadingGitHubRepos}
icon={
<div className="bg-black shadow rounded p-1 w-6 h-6 flex justify-center items-center">
@@ -553,213 +553,244 @@ const GitHubIntegrationConnectionForm = ({
)}
/>
</CardContent>
<CardContent className={cn(!currentRepositoryId && 'opacity-25 pointer-events-none')}>
<FormField_Shadcn_
control={githubSettingsForm.control}
name="supabaseDirectory"
render={({ field }) => (
<FormItemLayout
layout="flex-row-reverse"
label="Working directory"
description="Path to working directory with your supabase folder"
>
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
placeholder="supabase"
autoComplete="off"
disabled={disabled || !canUpdateGitHubConnection}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
</CardContent>
<CardContent className={cn(!currentRepositoryId && 'opacity-25 pointer-events-none')}>
{/* Production Branch Sync Section */}
<div className="space-y-4">
<FormField_Shadcn_
control={githubSettingsForm.control}
name="enableProductionSync"
render={({ field }) => (
<FormItemLayout
layout="flex-row-reverse"
label="Deploy to production"
description="Deploy changes to production on push including PR merges"
>
<FormControl_Shadcn_>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
disabled={disabled || !canUpdateGitHubConnection}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<div
className={cn(
'space-y-4 pl-6 border-l',
(!enableProductionSync || disabled) && 'opacity-25 pointer-events-none'
)}
<AnimatePresence>
{!!currentRepositoryId && (
<motion.div
initial={{ opacity: 0, y: -16 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -16 }}
>
<FormField_Shadcn_
control={githubSettingsForm.control}
name="branchName"
render={({ field }) => (
<FormItemLayout
layout="flex-row-reverse"
label="Production branch name"
description="The GitHub branch to sync with your production database (e.g., main, master)"
>
<div className="relative w-full">
<CardContent>
<FormField_Shadcn_
control={githubSettingsForm.control}
name="supabaseDirectory"
render={({ field }) => (
<FormItemLayout
layout="flex-row-reverse"
label="Working directory"
description="Path to working directory with your supabase folder"
>
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
placeholder="supabase"
autoComplete="off"
disabled={
disabled || !canUpdateGitHubConnection || !enableProductionSync
}
disabled={!canUpdateGitHubConnection}
/>
</FormControl_Shadcn_>
<div className="absolute top-2.5 right-3 flex items-center gap-2">
{isCheckingBranch && <Loader2 size={14} className="animate-spin" />}
</div>
</div>
</FormItemLayout>
)}
/>
</div>
</div>
</CardContent>
<CardContent className={cn(!currentRepositoryId && 'opacity-25 pointer-events-none')}>
<Alert_Shadcn_ variant="warning" className="mb-4">
<AlertTitle_Shadcn_>Branching and billing</AlertTitle_Shadcn_>
<AlertDescription_Shadcn_>
Branching Compute is not covered by your organization&apos;s Spend Cap. Costs
should be closely monitored, as they may be incurred.{' '}
<InlineLink
href={`${DOCS_URL}/guides/platform/cost-control#usage-items-not-covered-by-the-spend-cap`}
>
Learn more
</InlineLink>
</AlertDescription_Shadcn_>
</Alert_Shadcn_>
{/* Automatic Branching Section */}
<div className="space-y-4">
<FormField_Shadcn_
control={githubSettingsForm.control}
name="new_branch_per_pr"
render={({ field }) => (
<FormItemLayout
layout="flex-row-reverse"
label="Automatic branching"
description="Create preview branches for every pull request"
>
<FormControl_Shadcn_>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
disabled={disabled || !canCreateGitHubConnection}
</FormItemLayout>
)}
/>
</CardContent>
<CardContent>
{/* Production Branch Sync Section */}
<div className="space-y-4">
<FormField_Shadcn_
control={githubSettingsForm.control}
name="enableProductionSync"
render={({ field }) => (
<FormItemLayout
layout="flex-row-reverse"
label="Deploy to production"
description="Deploy changes to production on push including PR merges"
>
<FormControl_Shadcn_>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
disabled={!canUpdateGitHubConnection}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<div
className={cn(
'space-y-4 pl-6 border-l',
!enableProductionSync && 'opacity-25 pointer-events-none'
)}
>
<FormField_Shadcn_
control={githubSettingsForm.control}
name="branchName"
render={({ field }) => (
<FormItemLayout
layout="flex-row-reverse"
label="Production branch name"
description="The GitHub branch to sync with your production database (e.g., main, master)"
>
<div className="relative w-full">
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
autoComplete="off"
disabled={!canUpdateGitHubConnection || !enableProductionSync}
/>
</FormControl_Shadcn_>
<div className="absolute top-2.5 right-3 flex items-center gap-2">
{isCheckingBranch && (
<Loader2 size={14} className="animate-spin" />
)}
</div>
</div>
</FormItemLayout>
)}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<div
className={cn(
'space-y-4 pl-6 border-l',
(!newBranchPerPr || disabled) && 'opacity-25 pointer-events-none'
)}
>
<FormField_Shadcn_
control={githubSettingsForm.control}
name="branchLimit"
render={({ field }) => (
<FormItemLayout
layout="flex-row-reverse"
label="Branch limit"
description="Maximum number of preview branches"
>
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
type="number"
autoComplete="off"
disabled={!newBranchPerPr || disabled || !canUpdateGitHubConnection}
/>
</FormControl_Shadcn_>
</FormItemLayout>
</div>
</div>
</CardContent>
<CardContent>
{hasAccessToBranching ? (
<Admonition type="warning" title="Branching and billing" className="mb-4">
Branching Compute is not covered by your organization&apos;s Spend Cap.
Costs should be closely monitored, as they may be incurred.{' '}
<InlineLink
href={`${DOCS_URL}/guides/platform/cost-control#usage-items-not-covered-by-the-spend-cap`}
>
Learn more
</InlineLink>
</Admonition>
) : (
<UpgradeToPro
className="mb-4"
layout="vertical"
source="projectIntegrations"
featureProposition="automatically create preview branches from pull requests"
primaryText="Branching with GitHub integration"
secondaryText="Upgrade to the Pro Plan to enable branching and automatically create preview branches for every pull request"
docsUrl={`${DOCS_URL}/guides/deployment/branching`}
/>
)}
/>
<FormField_Shadcn_
control={githubSettingsForm.control}
name="supabaseChangesOnly"
render={({ field }) => (
<FormItemLayout
layout="flex-row-reverse"
label="Supabase changes only"
description="Only create branches when Supabase files change"
{/* Automatic Branching Section */}
<div className="space-y-4">
<FormField_Shadcn_
disabled={!hasAccessToBranching}
control={githubSettingsForm.control}
name="new_branch_per_pr"
render={({ field }) => (
<FormItemLayout
layout="flex-row-reverse"
label="Automatic branching"
className={cn(!hasAccessToBranching && 'opacity-25')}
description="Create preview branches for every pull request"
>
<FormControl_Shadcn_>
<Switch
checked={!hasAccessToBranching ? false : field.value}
onCheckedChange={field.onChange}
disabled={!hasAccessToBranching || !canCreateGitHubConnection}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<div
className={cn(
'space-y-4 pl-6 border-l',
(!hasAccessToBranching || !newBranchPerPr) &&
'opacity-25 pointer-events-none'
)}
>
<FormControl_Shadcn_>
<Switch
checked={field.value}
onCheckedChange={(val) => field.onChange(val)}
disabled={!newBranchPerPr || disabled || !canUpdateGitHubConnection}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
</div>
</div>
</CardContent>
<CardFooter className="flex justify-between items-center">
<div>
{connection && (
<Button
type="outline"
onClick={handleRemoveIntegration}
disabled={isDeletingConnection}
loading={isDeletingConnection}
>
Disable integration
</Button>
)}
</div>
<div className="flex space-x-2">
{githubSettingsForm.formState.isDirty && (
<Button
type="default"
onClick={() => {
githubSettingsForm.reset()
}}
disabled={disabled || !canUpdateGitHubConnection}
>
Cancel
</Button>
)}
<Button
type={promptProPlanUpgrade ? 'default' : 'primary'}
htmlType="submit"
disabled={
disabled ||
(!connection && !canCreateGitHubConnection) ||
(connection && !canUpdateGitHubConnection) ||
isCheckingBranch ||
isLoading ||
(!connection && !githubSettingsForm.getValues().repositoryId) ||
(connection && !githubSettingsForm.formState.isDirty)
}
loading={isCheckingBranch || isLoading}
>
{connection ? 'Save changes' : 'Enable integration'}
</Button>
</div>
</CardFooter>
<FormField_Shadcn_
control={githubSettingsForm.control}
name="branchLimit"
render={({ field }) => (
<FormItemLayout
layout="flex-row-reverse"
label="Branch limit"
description="Maximum number of preview branches"
>
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
type="number"
autoComplete="off"
value={!hasAccessToBranching ? 0 : field.value}
disabled={
!hasAccessToBranching ||
!newBranchPerPr ||
!canUpdateGitHubConnection
}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<FormField_Shadcn_
control={githubSettingsForm.control}
name="supabaseChangesOnly"
render={({ field }) => (
<FormItemLayout
layout="flex-row-reverse"
label="Supabase changes only"
description="Only create branches when Supabase files change"
>
<FormControl_Shadcn_>
<Switch
checked={!hasAccessToBranching ? false : field.value}
onCheckedChange={(val) => field.onChange(val)}
disabled={
!hasAccessToBranching ||
!newBranchPerPr ||
!canUpdateGitHubConnection
}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
</div>
</div>
</CardContent>
<CardFooter className="flex justify-between items-center">
<div>
{connection && (
<Button
type="outline"
onClick={handleRemoveIntegration}
disabled={isDeletingConnection}
loading={isDeletingConnection}
>
Disable integration
</Button>
)}
</div>
<div className="flex space-x-2">
{githubSettingsForm.formState.isDirty && (
<Button
type="default"
onClick={() => githubSettingsForm.reset()}
disabled={!canUpdateGitHubConnection}
>
Cancel
</Button>
)}
<Button
type="default"
htmlType="submit"
disabled={
!hasAccessToGitHubIntegration ||
(!connection && !canCreateGitHubConnection) ||
(connection && !canUpdateGitHubConnection) ||
isCheckingBranch ||
isLoading ||
(!connection && !githubSettingsForm.getValues().repositoryId) ||
(connection && !githubSettingsForm.formState.isDirty)
}
loading={isCheckingBranch || isLoading}
>
{connection ? 'Save changes' : 'Enable integration'}
</Button>
</div>
</CardFooter>
</motion.div>
)}
</AnimatePresence>
</Card>
</form>
</Form_Shadcn_>
@@ -801,5 +832,3 @@ const GitHubIntegrationConnectionForm = ({
</>
)
}
export default GitHubIntegrationConnectionForm
@@ -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.
</p>
{promptProPlanUpgrade && (
{!isGithubOnFreePlan && promptProPlanUpgrade && (
<div className="mb-6">
<UpgradeToPro
layout="vertical"
@@ -86,9 +87,12 @@ export const GitHubSection = () => {
</div>
)}
{/* [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) && (
<GitHubIntegrationConnectionForm
disabled={promptProPlanUpgrade}
connection={existingConnection}
@@ -1,4 +1,5 @@
import { ChevronsUpDown, GitBranch } from 'lucide-react'
import { forwardRef } from 'react'
import { cn, SidebarMenuButton } from 'ui'
export interface ProjectBranchSelectorTriggerProps {
@@ -11,41 +12,52 @@ export interface ProjectBranchSelectorTriggerProps {
onClick?: () => void
}
export function ProjectBranchSelectorTrigger({
displayProjectName,
selectedOrgInitial,
isBranch,
branchDisplayName,
onClick,
}: ProjectBranchSelectorTriggerProps) {
return (
<SidebarMenuButton
size="lg"
className="group py-1 gap-1.5 w-full flex h-auto text-left data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground touch-manipulation"
onClick={onClick}
>
<div className="relative flex h-8 aspect-square shrink-0 items-center bg-background-muted group-hover:border-stronger justify-center rounded border border-strong text-xs">
{selectedOrgInitial}
</div>
<div className="text-left flex-grow min-w-0">
<div className="w-full truncate text-foreground leading-tight max-w-[250px]">
{displayProjectName}
export const ProjectBranchSelectorTrigger = forwardRef<
HTMLButtonElement,
ProjectBranchSelectorTriggerProps
>(
(
{
displayProjectName,
selectedOrgInitial,
isBranch,
branchDisplayName,
onClick,
}: ProjectBranchSelectorTriggerProps,
ref
) => {
return (
<SidebarMenuButton
size="lg"
className="group py-1 gap-1.5 w-full flex h-auto text-left data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground touch-manipulation"
onClick={onClick}
ref={ref}
>
<div className="relative flex h-8 aspect-square shrink-0 items-center bg-background-muted group-hover:border-stronger justify-center rounded border border-strong text-xs">
{selectedOrgInitial}
</div>
<div
className={cn(
'flex items-center gap-0.5',
isBranch ? 'text-foreground-lighter' : 'text-warning'
)}
>
<GitBranch className="shrink-0 size-3" strokeWidth={1.5} />
<span className="truncate min-w-0 leading-tight text-xs">{branchDisplayName}</span>
<div className="text-left flex-grow min-w-0">
<div className="w-full truncate text-foreground leading-tight max-w-[250px]">
{displayProjectName}
</div>
<div
className={cn(
'flex items-center gap-0.5',
isBranch ? 'text-foreground-lighter' : 'text-warning'
)}
>
<GitBranch className="shrink-0 size-3" strokeWidth={1.5} />
<span className="truncate min-w-0 leading-tight text-xs">{branchDisplayName}</span>
</div>
</div>
</div>
<ChevronsUpDown
strokeWidth={1.5}
className="ml-auto text-foreground-lighter !w-4 !h-4 md:hidden md:group-hover:flex"
/>
</SidebarMenuButton>
)
}
<ChevronsUpDown
strokeWidth={1.5}
className="ml-auto text-foreground-lighter !w-4 !h-4 md:hidden md:group-hover:flex"
/>
</SidebarMenuButton>
)
}
)
ProjectBranchSelectorTrigger.displayName = 'ProjectBranchSelectorTrigger'
+17 -11
View File
@@ -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 (
<Admonition
@@ -47,16 +50,19 @@ export const UpgradeToPro = ({
description={secondaryText}
className={cn(fullWidth && 'border-0 rounded-none border-b', className)}
actions={
<UpgradePlanButton
plan={planToUpgrade}
addon={addon}
source={source}
featureProposition={featureProposition}
disabled={disabled}
variant={variant}
>
{buttonText}
</UpgradePlanButton>
<>
<UpgradePlanButton
plan={planToUpgrade}
addon={addon}
source={source}
featureProposition={featureProposition}
disabled={disabled}
variant={variant}
>
{buttonText}
</UpgradePlanButton>
{!!docsUrl && <DocsButton href={docsUrl} />}
</>
}
/>
)