mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
feat: add IPv4 add on direct conn notice (#26903)
* feat: add IPv4 add on direct conn notice * feat: add session mode warning * fix: remove statement from Supavisor-related types * Revert change in api types file * Revert change in api types file * Update API types file via codegen * Smol feex * Temp lint fix * Fix * fix: include serverless mention --------- Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
This commit is contained in:
1 parent
d2bd47a32a
commit
cd930f5a2f
9 files changed
+397
-735
No files matched your search
+3
-3
@@ -57,7 +57,7 @@ const StringToPositiveNumber = z.union([
|
||||
|
||||
const FormSchema = z.object({
|
||||
default_pool_size: StringToPositiveNumber,
|
||||
pool_mode: z.union([z.literal('transaction'), z.literal('session'), z.literal('statement')]),
|
||||
pool_mode: z.union([z.literal('transaction'), z.literal('session')]),
|
||||
max_client_conn: StringToPositiveNumber,
|
||||
})
|
||||
|
||||
@@ -107,7 +107,7 @@ export const ConnectionPooling = () => {
|
||||
const form = useForm<z.infer<typeof FormSchema>>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
defaultValues: {
|
||||
pool_mode: poolingConfiguration?.pool_mode as 'transaction' | 'session' | 'statement',
|
||||
pool_mode: poolingConfiguration?.pool_mode as 'transaction' | 'session',
|
||||
default_pool_size: poolingConfiguration?.default_pool_size as number | undefined,
|
||||
max_client_conn: poolingConfiguration?.max_client_conn as number | undefined,
|
||||
},
|
||||
@@ -141,7 +141,7 @@ export const ConnectionPooling = () => {
|
||||
useEffect(() => {
|
||||
if (isSuccess) {
|
||||
form.reset({
|
||||
pool_mode: poolingConfiguration?.pool_mode as 'transaction' | 'session' | 'statement',
|
||||
pool_mode: poolingConfiguration?.pool_mode as 'transaction' | 'session',
|
||||
default_pool_size: poolingConfiguration?.default_pool_size as number | undefined,
|
||||
max_client_conn: poolingConfiguration?.max_client_conn as number | undefined,
|
||||
})
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import { ExternalLink } from 'lucide-react'
|
||||
|
||||
import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, Button } from 'ui'
|
||||
import { WarningIcon } from 'ui-patterns/Icons/StatusIcons'
|
||||
|
||||
export const IPv4DeprecationNotice = () => {
|
||||
return (
|
||||
<Alert_Shadcn_ variant="warning">
|
||||
<WarningIcon />
|
||||
<AlertTitle_Shadcn_>
|
||||
Direct database access is only available via IPv6-compatible networks.
|
||||
</AlertTitle_Shadcn_>
|
||||
<AlertDescription_Shadcn_ className="space-y-3">
|
||||
<p>
|
||||
We strongly recommend using connection pooling to connect to your database because it's
|
||||
compatible with both IPv4 and IPv6 networks. You'll only need to change the connection
|
||||
credentials that you're using in your application to the pooler's connection credentials.
|
||||
</p>
|
||||
<Button asChild type="default" icon={<ExternalLink />}>
|
||||
<a
|
||||
href="https://github.com/orgs/supabase/discussions/17817"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
</Button>
|
||||
</AlertDescription_Shadcn_>
|
||||
</Alert_Shadcn_>
|
||||
)
|
||||
}
|
||||
|
||||
export const IPv4AddonDirectConnectionNotice = () => {
|
||||
return (
|
||||
<Alert_Shadcn_ variant="default">
|
||||
<AlertTitle_Shadcn_>
|
||||
Direct database connections are recommended if you're connecting with session mode.
|
||||
</AlertTitle_Shadcn_>
|
||||
<AlertDescription_Shadcn_ className="space-y-3">
|
||||
<p>
|
||||
If you are not connecting to the database from serverless environments, we strongly
|
||||
recommend you connect to the database directly instead of using connection pooling for
|
||||
lower latency.
|
||||
</p>
|
||||
<p>
|
||||
Since your project has the IPv4 add on, you are not required to use the connection pooler
|
||||
even if your network only supports IPv4.
|
||||
</p>
|
||||
<Button asChild type="default" icon={<ExternalLink />}>
|
||||
<a
|
||||
href="https://supabase.com/docs/guides/database/connecting-to-postgres#connection-pooler"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
</Button>
|
||||
</AlertDescription_Shadcn_>
|
||||
</Alert_Shadcn_>
|
||||
)
|
||||
}
|
||||
|
||||
export const DefaultSessionModeNotice = () => {
|
||||
return (
|
||||
<Alert_Shadcn_ variant="warning">
|
||||
<WarningIcon />
|
||||
<AlertTitle_Shadcn_>You are not yet in Transaction mode.</AlertTitle_Shadcn_>
|
||||
<AlertDescription_Shadcn_ className="space-y-3">
|
||||
<p>
|
||||
You need to set your <span className="text-foreground">Pool Mode</span> to{' '}
|
||||
<span className="text-foreground">Transaction</span> in the{' '}
|
||||
<span className="text-foreground">Connection pooling configuration</span> section below in
|
||||
order to use transaction mode on port 6543.
|
||||
</p>
|
||||
<p>
|
||||
Otherwise, port 6543 will continue to connect in{' '}
|
||||
<span className="text-foreground">Session</span> mode.
|
||||
</p>
|
||||
</AlertDescription_Shadcn_>
|
||||
</Alert_Shadcn_>
|
||||
)
|
||||
}
|
||||
+20
-3
@@ -2,6 +2,7 @@ import { useParams, useTelemetryProps } from 'common'
|
||||
import { useRouter } from 'next/router'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
|
||||
import { getAddons } from 'components/interfaces/Billing/Subscription/Subscription.utils'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import DatabaseSelector from 'components/ui/DatabaseSelector'
|
||||
@@ -9,6 +10,7 @@ import Panel from 'components/ui/Panel'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import { usePoolingConfigurationQuery } from 'data/database/pooling-configuration-query'
|
||||
import { useReadReplicasQuery } from 'data/read-replicas/replicas-query'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
import { useSelectedProject } from 'hooks'
|
||||
import { pluckObjectFields } from 'lib/helpers'
|
||||
import Telemetry from 'lib/telemetry'
|
||||
@@ -28,7 +30,11 @@ import {
|
||||
Tooltip_Shadcn_,
|
||||
cn,
|
||||
} from 'ui'
|
||||
import { IPv4DeprecationNotice } from '../IPv4DeprecationNotice'
|
||||
import {
|
||||
DefaultSessionModeNotice,
|
||||
IPv4AddonDirectConnectionNotice,
|
||||
IPv4DeprecationNotice,
|
||||
} from '../DatabaseConnectionNotices'
|
||||
import { UsePoolerCheckbox } from '../UsePoolerCheckbox'
|
||||
import {
|
||||
constructConnStringSyntax,
|
||||
@@ -61,7 +67,7 @@ export const DatabaseConnectionString = ({ appearance }: DatabaseConnectionStrin
|
||||
const { project: projectDetails, isLoading: isProjectLoading } = useProjectContext()
|
||||
|
||||
const connectionStringsRef = useRef<HTMLDivElement>(null)
|
||||
const [poolingMode, setPoolingMode] = useState<'transaction' | 'session' | 'statement'>('session')
|
||||
const [poolingMode, setPoolingMode] = useState<'transaction' | 'session'>('transaction')
|
||||
const [selectedTab, setSelectedTab] = useState<
|
||||
'uri' | 'psql' | 'golang' | 'jdbc' | 'dotnet' | 'nodejs' | 'php' | 'python'
|
||||
>('uri')
|
||||
@@ -70,6 +76,7 @@ export const DatabaseConnectionString = ({ appearance }: DatabaseConnectionStrin
|
||||
projectRef,
|
||||
})
|
||||
const poolingConfiguration = poolingInfo?.find((x) => x.identifier === state.selectedDatabaseId)
|
||||
const defaultPoolingMode = poolingConfiguration?.pool_mode
|
||||
|
||||
const {
|
||||
data: databases,
|
||||
@@ -83,6 +90,9 @@ export const DatabaseConnectionString = ({ appearance }: DatabaseConnectionStrin
|
||||
(db) => db.identifier === state.selectedDatabaseId
|
||||
)
|
||||
|
||||
const { data: addons, isSuccess: isSuccessAddons } = useProjectAddonsQuery({ projectRef })
|
||||
const { ipv4: ipv4Addon } = getAddons(addons?.selected_addons ?? [])
|
||||
|
||||
const DB_FIELDS = ['db_host', 'db_name', 'db_port', 'db_user', 'inserted_at']
|
||||
const emptyState = { db_user: '', db_host: '', db_port: '', db_name: '' }
|
||||
const connectionInfo = pluckObjectFields(selectedDatabase || emptyState, DB_FIELDS)
|
||||
@@ -218,7 +228,14 @@ export const DatabaseConnectionString = ({ appearance }: DatabaseConnectionStrin
|
||||
onCheckedChange={snap.setUsePoolerConnection}
|
||||
onSelectPoolingMode={setPoolingMode}
|
||||
/>
|
||||
{!snap.usePoolerConnection && <IPv4DeprecationNotice />}
|
||||
{defaultPoolingMode === 'session' && poolingMode === 'transaction' && (
|
||||
<DefaultSessionModeNotice />
|
||||
)}
|
||||
{isSuccessAddons &&
|
||||
poolingMode === 'session' &&
|
||||
ipv4Addon !== undefined &&
|
||||
snap.usePoolerConnection && <IPv4AddonDirectConnectionNotice />}
|
||||
{ipv4Addon === undefined && !snap.usePoolerConnection && <IPv4DeprecationNotice />}
|
||||
<Input
|
||||
copy
|
||||
readOnly
|
||||
|
||||
+30
-7
@@ -2,19 +2,25 @@ import { useRouter } from 'next/router'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
|
||||
import { useParams, useTelemetryProps } from 'common'
|
||||
import { getAddons } from 'components/interfaces/Billing/Subscription/Subscription.utils'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import DatabaseSelector from 'components/ui/DatabaseSelector'
|
||||
import Panel from 'components/ui/Panel'
|
||||
import ShimmeringLoader from 'components/ui/ShimmeringLoader'
|
||||
import { usePoolingConfigurationQuery } from 'data/database/pooling-configuration-query'
|
||||
import { useReadReplicasQuery } from 'data/read-replicas/replicas-query'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
import { pluckObjectFields } from 'lib/helpers'
|
||||
import Telemetry from 'lib/telemetry'
|
||||
import { useDatabaseSelectorStateSnapshot } from 'state/database-selector'
|
||||
import { useDatabaseSettingsStateSnapshot } from 'state/database-settings'
|
||||
import { AlertDescription_Shadcn_, AlertTitle_Shadcn_, Alert_Shadcn_, Input } from 'ui'
|
||||
import { WarningIcon } from 'ui-patterns/Icons/StatusIcons'
|
||||
import { IPv4DeprecationNotice } from '../IPv4DeprecationNotice'
|
||||
import {
|
||||
DefaultSessionModeNotice,
|
||||
IPv4AddonDirectConnectionNotice,
|
||||
IPv4DeprecationNotice,
|
||||
} from '../DatabaseConnectionNotices'
|
||||
import { UsePoolerCheckbox } from '../UsePoolerCheckbox'
|
||||
import ResetDbPassword from './ResetDbPassword'
|
||||
|
||||
@@ -26,7 +32,7 @@ const DatabaseSettings = () => {
|
||||
const state = useDatabaseSelectorStateSnapshot()
|
||||
|
||||
const connectionStringsRef = useRef<HTMLDivElement>(null)
|
||||
const [poolingMode, setPoolingMode] = useState<'transaction' | 'session' | 'statement'>('session')
|
||||
const [poolingMode, setPoolingMode] = useState<'transaction' | 'session'>('transaction')
|
||||
|
||||
const {
|
||||
data: poolingInfo,
|
||||
@@ -44,15 +50,24 @@ const DatabaseSettings = () => {
|
||||
isError: isErrorReadReplicas,
|
||||
isSuccess: isSuccessReadReplicas,
|
||||
} = useReadReplicasQuery({ projectRef })
|
||||
const error = readReplicasError || poolingInfoError
|
||||
const isLoading = isLoadingReadReplicas || isLoadingPoolingInfo
|
||||
const isError = isErrorReadReplicas || isErrorPoolingInfo
|
||||
const isSuccess = isSuccessReadReplicas && isSuccessPoolingInfo
|
||||
const {
|
||||
data: addons,
|
||||
error: addOnsError,
|
||||
isLoading: isLoadingAddons,
|
||||
isError: isErrorAddons,
|
||||
isSuccess: isSuccessAddons,
|
||||
} = useProjectAddonsQuery({ projectRef })
|
||||
const error = readReplicasError || poolingInfoError || addOnsError
|
||||
const isLoading = isLoadingReadReplicas || isLoadingPoolingInfo || isLoadingAddons
|
||||
const isError = isErrorReadReplicas || isErrorPoolingInfo || isErrorAddons
|
||||
const isSuccess = isSuccessReadReplicas && isSuccessPoolingInfo && isSuccessAddons
|
||||
|
||||
const selectedDatabase = (databases ?? []).find(
|
||||
(db) => db.identifier === state.selectedDatabaseId
|
||||
)
|
||||
const primaryConfig = poolingInfo?.find((x) => x.identifier === state.selectedDatabaseId)
|
||||
const defaultPoolingMode = primaryConfig?.pool_mode
|
||||
const { ipv4: ipv4Addon } = getAddons(addons?.selected_addons ?? [])
|
||||
const isMd5 = primaryConfig?.connectionString.includes('?options=reference')
|
||||
|
||||
const DB_FIELDS = ['db_host', 'db_name', 'db_port', 'db_user']
|
||||
@@ -128,7 +143,15 @@ const DatabaseSettings = () => {
|
||||
onCheckedChange={snap.setUsePoolerConnection}
|
||||
onSelectPoolingMode={setPoolingMode}
|
||||
/>
|
||||
{!snap.usePoolerConnection && <IPv4DeprecationNotice />}
|
||||
{defaultPoolingMode === 'session' && poolingMode === 'transaction' && (
|
||||
<DefaultSessionModeNotice />
|
||||
)}
|
||||
{ipv4Addon !== undefined &&
|
||||
poolingMode === 'session' &&
|
||||
snap.usePoolerConnection && <IPv4AddonDirectConnectionNotice />}
|
||||
{ipv4Addon === undefined && !snap.usePoolerConnection && (
|
||||
<IPv4DeprecationNotice />
|
||||
)}
|
||||
{isMd5 && (
|
||||
<Alert_Shadcn_>
|
||||
<WarningIcon />
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
import {
|
||||
Alert_Shadcn_,
|
||||
IconAlertTriangle,
|
||||
AlertTitle_Shadcn_,
|
||||
AlertDescription_Shadcn_,
|
||||
Button,
|
||||
IconExternalLink,
|
||||
} from 'ui'
|
||||
|
||||
export const IPv4DeprecationNotice = () => {
|
||||
return (
|
||||
<Alert_Shadcn_ variant="warning">
|
||||
<IconAlertTriangle strokeWidth={2} />
|
||||
<AlertTitle_Shadcn_>
|
||||
Direct database access is only available via IPv6-compatible networks or if your project has
|
||||
the IPv4 add on.
|
||||
</AlertTitle_Shadcn_>
|
||||
<AlertDescription_Shadcn_ className="space-y-3">
|
||||
<p>
|
||||
We strongly recommend using <span className="text-foreground">connection pooling</span> to
|
||||
connect to your database because it's compatible with both IPv4 and IPv6 networks.
|
||||
</p>
|
||||
<p>
|
||||
You'll only need to change the connection credentials that you're using in your
|
||||
application to the pooler's connection credentials.
|
||||
</p>
|
||||
<Button asChild type="default" icon={<IconExternalLink strokeWidth={1.5} />}>
|
||||
<a
|
||||
href="https://github.com/orgs/supabase/discussions/17817"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Learn more
|
||||
</a>
|
||||
</Button>
|
||||
</AlertDescription_Shadcn_>
|
||||
</Alert_Shadcn_>
|
||||
)
|
||||
}
|
||||
@@ -30,7 +30,7 @@ import {
|
||||
interface UsePoolerCheckboxInterface {
|
||||
id: string
|
||||
checked: boolean
|
||||
poolingMode: 'transaction' | 'session' | 'statement'
|
||||
poolingMode: 'transaction' | 'session'
|
||||
onCheckedChange: (value: boolean) => void
|
||||
onSelectPoolingMode: (mode: 'transaction' | 'session') => void
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ export async function getDatabaseFunctions(
|
||||
if (connectionString) headers.set('x-connection-encrypted', connectionString)
|
||||
|
||||
const { data, error } = await get('/platform/pg-meta/{ref}/functions', {
|
||||
// @ts-ignore [Joshen] Temp, seems like API codegen is wrong
|
||||
params: { path: { ref: projectRef } },
|
||||
headers,
|
||||
signal,
|
||||
|
||||
@@ -28,12 +28,10 @@ const handleGet = async (req: NextApiRequest, res: NextApiResponse<ResponseData>
|
||||
usage_billing_enabled: false,
|
||||
plan: {
|
||||
id: 'enterprise',
|
||||
name: '',
|
||||
price: 0,
|
||||
name: 'Enterprise',
|
||||
},
|
||||
addons: [],
|
||||
project_addons: [],
|
||||
usage_fees: [],
|
||||
payment_method_type: '',
|
||||
billing_via_partner: false,
|
||||
billing_partner: 'fly',
|
||||
|
||||
Vendored
+259
-679
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user