diff --git a/apps/studio/components/interfaces/Settings/Addons/CustomDomainSidePanel.tsx b/apps/studio/components/interfaces/Settings/Addons/CustomDomainSidePanel.tsx
index dbc8995cbbf59..8541721f47e54 100644
--- a/apps/studio/components/interfaces/Settings/Addons/CustomDomainSidePanel.tsx
+++ b/apps/studio/components/interfaces/Settings/Addons/CustomDomainSidePanel.tsx
@@ -1,9 +1,4 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
-import { AlertCircle, ExternalLink } from 'lucide-react'
-import Link from 'next/link'
-import { useEffect, useState } from 'react'
-import { toast } from 'sonner'
-
import { useFlag, useParams } from 'common'
import { useProjectAddonRemoveMutation } from 'data/subscriptions/project-addon-remove-mutation'
import { useProjectAddonUpdateMutation } from 'data/subscriptions/project-addon-update-mutation'
@@ -14,18 +9,24 @@ import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization'
import { DOCS_URL } from 'lib/constants'
import { formatCurrency } from 'lib/helpers'
+import { AlertCircle } from 'lucide-react'
+import Link from 'next/link'
+import { useEffect, useState } from 'react'
+import { toast } from 'sonner'
import { useAddonsPagePanel } from 'state/addons-page'
import {
Alert,
+ Alert_Shadcn_,
AlertDescription_Shadcn_,
AlertTitle_Shadcn_,
- Alert_Shadcn_,
Button,
+ cn,
Radio,
SidePanel,
- cn,
} from 'ui'
+import { DocsButton } from '@/components/ui/DocsButton'
+
const CustomDomainSidePanel = () => {
const { ref: projectRef } = useParams()
const { data: organization } = useSelectedOrganizationQuery()
@@ -119,17 +120,9 @@ const CustomDomainSidePanel = () => {
: undefined
}
header={
-
+
Custom domains
- }>
-
- About custom domains
-
-
+
}
>
diff --git a/apps/studio/components/interfaces/Settings/Addons/IPv4SidePanel.tsx b/apps/studio/components/interfaces/Settings/Addons/IPv4SidePanel.tsx
index 872f88ea00833..a381a9c9326b0 100644
--- a/apps/studio/components/interfaces/Settings/Addons/IPv4SidePanel.tsx
+++ b/apps/studio/components/interfaces/Settings/Addons/IPv4SidePanel.tsx
@@ -1,10 +1,6 @@
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 { DocsButton } from 'components/ui/DocsButton'
import { InlineLink } from 'components/ui/InlineLink'
import { useProjectAddonRemoveMutation } from 'data/subscriptions/project-addon-remove-mutation'
import { useProjectAddonUpdateMutation } from 'data/subscriptions/project-addon-update-mutation'
@@ -16,8 +12,11 @@ import { useSelectedOrganizationQuery } from 'hooks/misc/useSelectedOrganization
import { useIsAwsCloudProvider } from 'hooks/misc/useSelectedProject'
import { DOCS_URL } from 'lib/constants'
import { formatCurrency } from 'lib/helpers'
+import Link from 'next/link'
+import { useEffect, useState } from 'react'
+import { toast } from 'sonner'
import { useAddonsPagePanel } from 'state/addons-page'
-import { Button, Radio, SidePanel, cn } from 'ui'
+import { Button, cn, RadioGroup_Shadcn_, RadioGroupLargeItem_Shadcn_, SidePanel } from 'ui'
import { Admonition } from 'ui-patterns'
const IPv4SidePanel = () => {
@@ -62,12 +61,41 @@ const IPv4SidePanel = () => {
const availableOptions =
(addons?.available_addons ?? []).find((addon) => addon.type === 'ipv4')?.variants ?? []
- const isFreePlan = organization?.plan?.id === 'free'
const { hasAccess: hasAccessToIPv4, isLoading: isLoadingEntitlement } =
useCheckEntitlements('ipv4')
const hasChanges = selectedOption !== (subscriptionIpV4Option?.variant.identifier ?? 'ipv4_none')
const selectedIPv4 = availableOptions.find((option) => option.identifier === selectedOption)
- const isPgBouncerEnabled = !isFreePlan
+
+ const ipv4Options = [
+ {
+ value: 'ipv4_none',
+ id: 'ipv4_none',
+ title: 'No IPv4 address',
+ description: 'Use shared pooler or IPv6 for database connections.',
+ priceContent: (
+ <>
+
$0
+
/ month
+ >
+ ),
+ priceRowClassName: 'mt-2',
+ },
+ ...availableOptions.map((option) => ({
+ value: option.identifier,
+ id: option.identifier,
+ title: 'Dedicated IPv4 address',
+ description: 'Allow database connections from IPv4 networks.',
+ priceContent: (
+ <>
+
+ {formatCurrency(option.price)}
+
+
/ month / database
+ >
+ ),
+ priceRowClassName: 'mt-3',
+ })),
+ ]
useEffect(() => {
if (visible) {
@@ -112,26 +140,22 @@ const IPv4SidePanel = () => {
: undefined
}
header={
-
+
Dedicated IPv4 address
- }>
-
- About dedicated IPv4 addresses
-
-
+
}
>
- 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.
+ Your project’s direct connection endpoint and dedicated pooler are IPv6-only by default.
+ Enable the dedicated IPv4 address add-on to connect from IPv4-only networks.
+
+
+
+ The shared pooler endpoint accepts IPv4 connections by default and does not require this
+ add-on.
{!isAws && (
@@ -141,84 +165,42 @@ const IPv4SidePanel = () => {
/>
)}
- {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)}
- >
-
+
-
-
-
-
- Use connection pooler or IPv6 for direct connections
-
-
-
-
-
- {availableOptions.map((option) => (
-
-
-
-
Dedicated IPv4 address
-
-
-
- Allow direct database connections via IPv4 address
-
-
-
- {formatCurrency(option.price)}
-
-
- / month / database
-
+ {ipv4Options.map((option) => (
+
+
+
{option.title}
+
{option.description}
+
+ {option.priceContent}
-
-
- ))}
-
-
+
+ ))}
+
+
+ )}
{hasChanges && (
<>
@@ -230,29 +212,25 @@ const IPv4SidePanel = () => {
/>
{selectedOption !== 'ipv4_none' && (
- By default, this is only applied to the Primary database for your project. If{' '}
-
- Read replicas
- {' '}
+ 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.
+ There are no immediate charges. The add-on is billed at the end of your billing
+ cycle based on your usage and prorated to the hour.
>
)}
{!hasAccessToIPv4 && (
- Upgrade your plan to enable a IPv4 address for your project
+ Upgrade your plan to enable an IPv4 address for your project