import { PermissionAction } from '@supabase/shared-types/out/constants' import { ExternalLink } from 'lucide-react' import Link from 'next/link' import { useEffect, useState } from 'react' import { toast } from 'sonner' import { useParams } from 'common' import { InlineLink } from 'components/ui/InlineLink' import { useProjectAddonRemoveMutation } from 'data/subscriptions/project-addon-remove-mutation' import { useProjectAddonUpdateMutation } from 'data/subscriptions/project-addon-update-mutation' import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query' import type { AddonVariantId } from 'data/subscriptions/types' import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions' import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization' import { useIsAwsCloudProvider } from 'hooks/misc/useSelectedProject' import { DOCS_URL } from 'lib/constants' import { formatCurrency } from 'lib/helpers' import { useAddonsPagePanel } from 'state/addons-page' import { Button, Radio, SidePanel, cn } from 'ui' import { Admonition } from 'ui-patterns' const IPv4SidePanel = () => { const isAws = useIsAwsCloudProvider() const { ref: projectRef } = useParams() const { data: organization } = useSelectedOrganizationQuery() const [selectedOption, setSelectedOption] = useState('ipv4_none') const { can: canUpdateIPv4 } = useAsyncCheckPermissions( PermissionAction.BILLING_WRITE, 'stripe.subscriptions' ) const { panel, closePanel } = useAddonsPagePanel() const visible = panel === 'ipv4' const { data: addons, isLoading } = useProjectAddonsQuery({ projectRef }) const { mutate: updateAddon, isLoading: isUpdating } = useProjectAddonUpdateMutation({ onSuccess: () => { toast.success(`Successfully enabled IPv4`) closePanel() }, onError: (error) => { toast.error(`Unable to enable IPv4: ${error.message}`) }, }) const { mutate: removeAddon, isLoading: isRemoving } = useProjectAddonRemoveMutation({ onSuccess: () => { toast.success(`Successfully disabled IPv4.`) closePanel() }, onError: (error) => { toast.error(`Unable to disable IPv4: ${error.message}`) }, }) const isSubmitting = isUpdating || isRemoving const subscriptionIpV4Option = (addons?.selected_addons ?? []).find( (addon) => addon.type === 'ipv4' ) const availableOptions = (addons?.available_addons ?? []).find((addon) => addon.type === 'ipv4')?.variants ?? [] const isFreePlan = organization?.plan?.id === 'free' const hasChanges = selectedOption !== (subscriptionIpV4Option?.variant.identifier ?? 'ipv4_none') const selectedIPv4 = availableOptions.find((option) => option.identifier === selectedOption) const isPgBouncerEnabled = !isFreePlan useEffect(() => { if (visible) { if (subscriptionIpV4Option !== undefined) { setSelectedOption(subscriptionIpV4Option.variant.identifier) } else { setSelectedOption('ipv4_none') } } }, [visible, isLoading]) const onConfirm = async () => { if (!projectRef) return console.error('Project ref is required') if (selectedOption === 'ipv4_none' && subscriptionIpV4Option !== undefined) { removeAddon({ projectRef, variant: subscriptionIpV4Option.variant.identifier }) } else { updateAddon({ projectRef, type: 'ipv4', variant: selectedOption as AddonVariantId }) } } return (

Dedicated IPv4 address

} >

Direct connections to the database only work if your client is able to resolve IPv6 addresses. Enabling the dedicated IPv4 add-on allows you to directly connect to your database via a IPv4 address.

{!isAws && ( )} {isPgBouncerEnabled ? ( ) : (

If you are connecting via the Shared connection pooler, you do not need this add-on as our pooler resolves to IPv4 addresses. You can check your connection info in your{' '} project database settings .

)}
setSelectedOption(event.target.value)} >

No IPv4 address

Use connection pooler or IPv6 for direct connections

$0

/ month

{availableOptions.map((option) => (

Dedicated IPv4 address

Allow direct database connections via IPv4 address

{formatCurrency(option.price)}

/ month / database

))}
{hasChanges && ( <> {selectedOption !== 'ipv4_none' && (

By default, this is only applied to the Primary database for your project. If{' '} Read replicas {' '} are used, each replica also gets its own IPv4 address, with a corresponding{' '} {formatCurrency(selectedIPv4?.price)}{' '} charge.

)}

There are no immediate charges. The addon is billed at the end of your billing cycle based on your usage and prorated to the hour.

)} {isFreePlan && (

Upgrade your plan to enable a IPv4 address for your project

)}
) } export default IPv4SidePanel