mirror of
https://github.com/supabase/supabase.git
synced 2026-10-12 21:05:06 +03:00
connection string full layout
This commit is contained in:
3 files changed
+160
-290
No files matched your search
@@ -356,32 +356,3 @@ export const CONNECTION_TYPES = [
|
||||
export const PGBOUNCER_ENABLED_BUT_NO_IPV4_ADDON_TEXT =
|
||||
'Purchase IPv4 add-on or use Shared Pooler if on a IPv4 network'
|
||||
export const IPV4_ADDON_TEXT = 'Connections are IPv4 proxied with IPv4 add-on'
|
||||
|
||||
export type ConnectionStringMethod = 'direct' | 'transaction' | 'session'
|
||||
|
||||
export const connectionStringMethodOptions: Record<
|
||||
ConnectionStringMethod,
|
||||
{ value: string; label: string; description: string; badge: string }
|
||||
> = {
|
||||
direct: {
|
||||
value: 'direct',
|
||||
label: 'Direct connection',
|
||||
description:
|
||||
'Ideal for applications with persistent and long-lived connections, such as those running on virtual machines or long-standing containers.',
|
||||
badge: 'IPv4 Compatible',
|
||||
},
|
||||
transaction: {
|
||||
value: 'transaction',
|
||||
label: 'Transaction pooler',
|
||||
description:
|
||||
'Ideal for stateless applications like serverless functions where each interaction with Postgres is brief and isolated.',
|
||||
badge: 'IPv4 Compatible',
|
||||
},
|
||||
session: {
|
||||
value: 'session',
|
||||
label: 'Session pooler',
|
||||
description:
|
||||
'Only recommended as an alternative to Direct Connection, when connecting via an IPv4 network.',
|
||||
badge: 'IPv4 Only',
|
||||
},
|
||||
}
|
||||
@@ -87,9 +87,6 @@ export const Connect = () => {
|
||||
const [queryFramework, setQueryFramework] = useQueryState('framework', parseAsString)
|
||||
const [queryUsing, setQueryUsing] = useQueryState('using', parseAsString)
|
||||
const [queryWith, setQueryWith] = useQueryState('with', parseAsString)
|
||||
const [_, setQueryType] = useQueryState('type', parseAsString)
|
||||
const [__, setQuerySource] = useQueryState('source', parseAsString)
|
||||
const [___, setQueryMethod] = useQueryState('method', parseAsString)
|
||||
|
||||
const [connectionObject, setConnectionObject] = useState<ConnectionType[]>(FRAMEWORKS)
|
||||
const [selectedParent, setSelectedParent] = useState(connectionObject[0].key) // aka nextjs
|
||||
@@ -245,20 +242,13 @@ export const Connect = () => {
|
||||
selectedGrandchild,
|
||||
})
|
||||
|
||||
const resetQueryStates = () => {
|
||||
setQueryFramework(null)
|
||||
setQueryUsing(null)
|
||||
setQueryWith(null)
|
||||
setQueryType(null)
|
||||
setQuerySource(null)
|
||||
setQueryMethod(null)
|
||||
}
|
||||
|
||||
const handleDialogChange = (open: boolean) => {
|
||||
if (!open) {
|
||||
setShowConnect(null)
|
||||
setTab(null)
|
||||
resetQueryStates()
|
||||
setQueryFramework(null)
|
||||
setQueryUsing(null)
|
||||
setQueryWith(null)
|
||||
} else {
|
||||
setShowConnect(open)
|
||||
}
|
||||
@@ -321,8 +311,8 @@ export const Connect = () => {
|
||||
<span>Connect</span>
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className={cn('sm:max-w-5xl p-0 rounded-lg')} centered={false}>
|
||||
<DialogHeader className={cn('text-left', DIALOG_PADDING_X)}>
|
||||
<DialogContent className={cn('sm:max-w-5xl p-0')} centered={false}>
|
||||
<DialogHeader className={DIALOG_PADDING_X}>
|
||||
<DialogTitle>
|
||||
Connect to your project
|
||||
{connectionTypes.length === 1 ? ` via ${connectionTypes[0].label.toLowerCase()}` : null}
|
||||
@@ -332,13 +322,7 @@ export const Connect = () => {
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<Tabs_Shadcn_
|
||||
defaultValue={tab}
|
||||
onValueChange={(value) => {
|
||||
resetQueryStates()
|
||||
handleConnectionType(value)
|
||||
}}
|
||||
>
|
||||
<Tabs_Shadcn_ defaultValue={tab} onValueChange={(value) => handleConnectionType(value)}>
|
||||
{connectionTypes.length > 1 ? (
|
||||
<TabsList_Shadcn_ className={cn('flex overflow-x-scroll gap-x-4', DIALOG_PADDING_X)}>
|
||||
{connectionTypes.map((type) => (
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { ChevronDown, GlobeIcon, InfoIcon } from 'lucide-react'
|
||||
import { parseAsString, useQueryState } from 'nuqs'
|
||||
import { HTMLAttributes, ReactNode, useEffect, useMemo, useState } from 'react'
|
||||
import { ChevronDown } from 'lucide-react'
|
||||
import { HTMLAttributes, ReactNode, useMemo, useState } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { getAddons } from 'components/interfaces/Billing/Subscription/Subscription.utils'
|
||||
@@ -19,6 +18,7 @@ import { pluckObjectFields } from 'lib/helpers'
|
||||
import { useDatabaseSelectorStateSnapshot } from 'state/database-selector'
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
CodeBlock,
|
||||
CollapsibleContent_Shadcn_,
|
||||
CollapsibleTrigger_Shadcn_,
|
||||
@@ -35,12 +35,10 @@ import {
|
||||
import { Admonition } from 'ui-patterns'
|
||||
import {
|
||||
CONNECTION_PARAMETERS,
|
||||
type ConnectionStringMethod,
|
||||
DATABASE_CONNECTION_TYPES,
|
||||
DatabaseConnectionType,
|
||||
IPV4_ADDON_TEXT,
|
||||
PGBOUNCER_ENABLED_BUT_NO_IPV4_ADDON_TEXT,
|
||||
connectionStringMethodOptions,
|
||||
} from './Connect.constants'
|
||||
import { CodeBlockFileHeader, ConnectionPanel } from './ConnectionPanel'
|
||||
import { getConnectionStrings } from './DatabaseSettings.utils'
|
||||
@@ -52,7 +50,7 @@ const StepLabel = ({
|
||||
...props
|
||||
}: { number: number; children: ReactNode } & HTMLAttributes<HTMLDivElement>) => (
|
||||
<div {...props} className={cn('flex items-center gap-2', props.className)}>
|
||||
<div className="flex font-mono text-xs items-center justify-center min-w-6 w-6 h-6 border border-strong rounded-md bg-surface-100">
|
||||
<div className="flex font-mono text-xs items-center justify-center w-6 h-6 border border-strong rounded-md bg-surface-100">
|
||||
{number}
|
||||
</div>
|
||||
<span>{children}</span>
|
||||
@@ -68,74 +66,12 @@ export const DatabaseConnectionString = () => {
|
||||
const { data: org } = useSelectedOrganizationQuery()
|
||||
const state = useDatabaseSelectorStateSnapshot()
|
||||
|
||||
// URL state management
|
||||
const [queryType, setQueryType] = useQueryState('type', parseAsString.withDefault('uri'))
|
||||
const [querySource, setQuerySource] = useQueryState('source', parseAsString)
|
||||
const [queryMethod, setQueryMethod] = useQueryState('method', parseAsString.withDefault('direct'))
|
||||
|
||||
const [selectedTab, setSelectedTab] = useState<DatabaseConnectionType>('uri')
|
||||
const [selectedMethod, setSelectedMethod] = useState<ConnectionStringMethod>('direct')
|
||||
|
||||
const sharedPoolerPreferred = useMemo(() => {
|
||||
return org?.plan?.id === 'free'
|
||||
}, [org])
|
||||
|
||||
// Sync URL state with component state on mount and when URL changes
|
||||
useEffect(() => {
|
||||
const validTypes = DATABASE_CONNECTION_TYPES.map((t) => t.id)
|
||||
if (queryType && validTypes.includes(queryType as DatabaseConnectionType)) {
|
||||
setSelectedTab(queryType as DatabaseConnectionType)
|
||||
} else if (queryType && !validTypes.includes(queryType as DatabaseConnectionType)) {
|
||||
setQueryType('uri')
|
||||
setSelectedTab('uri')
|
||||
}
|
||||
|
||||
const validMethods: ConnectionStringMethod[] = ['direct', 'transaction', 'session']
|
||||
if (queryMethod && validMethods.includes(queryMethod as ConnectionStringMethod)) {
|
||||
setSelectedMethod(queryMethod as ConnectionStringMethod)
|
||||
} else if (queryMethod && !validMethods.includes(queryMethod as ConnectionStringMethod)) {
|
||||
setQueryMethod('direct')
|
||||
setSelectedMethod('direct')
|
||||
}
|
||||
|
||||
if (querySource && querySource !== state.selectedDatabaseId) {
|
||||
state.setSelectedDatabaseId(querySource)
|
||||
} else if (!querySource && state.selectedDatabaseId !== projectRef) {
|
||||
state.setSelectedDatabaseId(projectRef)
|
||||
}
|
||||
}, [queryType, queryMethod, querySource, state])
|
||||
|
||||
// Sync component state changes back to URL
|
||||
const handleTabChange = (connectionType: DatabaseConnectionType) => {
|
||||
setSelectedTab(connectionType)
|
||||
setQueryType(connectionType)
|
||||
}
|
||||
|
||||
const handleMethodChange = (method: ConnectionStringMethod) => {
|
||||
setSelectedMethod(method)
|
||||
setQueryMethod(method)
|
||||
}
|
||||
|
||||
const handleDatabaseChange = (databaseId: string) => {
|
||||
if (databaseId === projectRef) {
|
||||
setQuerySource(null)
|
||||
} else {
|
||||
setQuerySource(databaseId)
|
||||
}
|
||||
}
|
||||
|
||||
// Sync database selector state changes back to URL
|
||||
useEffect(() => {
|
||||
if (state.selectedDatabaseId && state.selectedDatabaseId !== querySource) {
|
||||
// Only set source in URL if it's not the primary database
|
||||
if (state.selectedDatabaseId === projectRef) {
|
||||
setQuerySource(null)
|
||||
} else {
|
||||
setQuerySource(state.selectedDatabaseId)
|
||||
}
|
||||
}
|
||||
}, [state.selectedDatabaseId, querySource, projectRef])
|
||||
|
||||
const {
|
||||
data: pgbouncerConfig,
|
||||
error: pgbouncerError,
|
||||
@@ -200,14 +136,14 @@ export const DatabaseConnectionString = () => {
|
||||
|
||||
const handleCopy = (
|
||||
connectionTypeId: string,
|
||||
connectionStringMethod: 'direct' | 'transaction_pooler' | 'session_pooler'
|
||||
connectionMethod: 'direct' | 'transaction_pooler' | 'session_pooler'
|
||||
) => {
|
||||
const connectionInfo = DATABASE_CONNECTION_TYPES.find((type) => type.id === connectionTypeId)
|
||||
const connectionType = connectionInfo?.label ?? 'Unknown'
|
||||
const lang = connectionInfo?.lang ?? 'Unknown'
|
||||
sendEvent({
|
||||
action: 'connection_string_copied',
|
||||
properties: { connectionType, lang, connectionMethod: connectionStringMethod },
|
||||
properties: { connectionType, lang, connectionMethod },
|
||||
groups: { project: projectRef ?? 'Unknown', organization: org?.slug ?? 'Unknown' },
|
||||
})
|
||||
}
|
||||
@@ -285,7 +221,12 @@ export const DatabaseConnectionString = () => {
|
||||
<span className="flex items-center text-foreground-lighter px-3 rounded-lg rounded-r-none text-xs border border-button border-r-0">
|
||||
Type
|
||||
</span>
|
||||
<Select_Shadcn_ value={selectedTab} onValueChange={handleTabChange}>
|
||||
<Select_Shadcn_
|
||||
value={selectedTab}
|
||||
onValueChange={(connectionType: DatabaseConnectionType) =>
|
||||
setSelectedTab(connectionType)
|
||||
}
|
||||
>
|
||||
<SelectTrigger_Shadcn_ size="small" className="w-auto rounded-l-none">
|
||||
<SelectValue_Shadcn_ />
|
||||
</SelectTrigger_Shadcn_>
|
||||
@@ -298,32 +239,7 @@ export const DatabaseConnectionString = () => {
|
||||
</SelectContent_Shadcn_>
|
||||
</Select_Shadcn_>
|
||||
</div>
|
||||
<DatabaseSelector
|
||||
portal={false}
|
||||
buttonProps={{ size: 'small' }}
|
||||
onSelectId={handleDatabaseChange}
|
||||
/>
|
||||
<div className="flex">
|
||||
<span className="flex items-center text-foreground-lighter px-3 rounded-lg rounded-r-none text-xs border border-button border-r-0">
|
||||
Method
|
||||
</span>
|
||||
<Select_Shadcn_ value={selectedMethod} onValueChange={handleMethodChange}>
|
||||
<SelectTrigger_Shadcn_ size="small" className="w-auto rounded-l-none">
|
||||
<SelectValue_Shadcn_ size="tiny">
|
||||
{connectionStringMethodOptions[selectedMethod].label}
|
||||
</SelectValue_Shadcn_>
|
||||
</SelectTrigger_Shadcn_>
|
||||
<SelectContent_Shadcn_ className="max-w-sm">
|
||||
{Object.keys(connectionStringMethodOptions).map((method) => (
|
||||
<ConnectionStringMethodSelectItem
|
||||
key={method}
|
||||
method={method as ConnectionStringMethod}
|
||||
poolerBadge={poolerBadge}
|
||||
/>
|
||||
))}
|
||||
</SelectContent_Shadcn_>
|
||||
</Select_Shadcn_>
|
||||
</div>
|
||||
<DatabaseSelector portal={false} buttonProps={{ size: 'small' }} />
|
||||
</div>
|
||||
|
||||
{isLoading && (
|
||||
@@ -342,16 +258,15 @@ export const DatabaseConnectionString = () => {
|
||||
<div className="flex flex-col divide-y divide-border">
|
||||
{/* // handle non terminal examples */}
|
||||
{hasCodeExamples && (
|
||||
<div className="flex flex-col w-full">
|
||||
<div className="grid lg:grid-cols-3 gap-4 lg:gap-5 py-8 px-4 md:px-7">
|
||||
<StepLabel number={++stepNumber} className="items-start">
|
||||
<div className="grid grid-cols-2 gap-x-20 w-full px-4 md:px-7 py-8">
|
||||
<div>
|
||||
<StepLabel number={++stepNumber} className="mb-4">
|
||||
Install the following
|
||||
</StepLabel>
|
||||
{exampleInstallCommands?.map((cmd) => (
|
||||
{exampleInstallCommands?.map((cmd, i) => (
|
||||
<CodeBlock
|
||||
key={`example-install-command-${cmd}`}
|
||||
key={i}
|
||||
className="[&_code]:text-[12px] [&_code]:text-foreground"
|
||||
wrapperClassName="lg:col-span-2"
|
||||
value={cmd}
|
||||
hideLineNumbers
|
||||
language="bash"
|
||||
@@ -361,12 +276,12 @@ export const DatabaseConnectionString = () => {
|
||||
))}
|
||||
</div>
|
||||
{exampleFiles && exampleFiles?.length > 0 && (
|
||||
<div className="grid lg:grid-cols-3 gap-4 lg:gap-5 border-t py-8 px-4 md:px-7">
|
||||
<StepLabel number={++stepNumber} className="items-start">
|
||||
<div>
|
||||
<StepLabel number={++stepNumber} className="mb-4">
|
||||
Add file to project
|
||||
</StepLabel>
|
||||
{exampleFiles?.map((file) => (
|
||||
<div key={`example-files-${file.name}`} className="lg:col-span-2">
|
||||
{exampleFiles?.map((file, i) => (
|
||||
<div key={i}>
|
||||
<CodeBlockFileHeader title={file.name} />
|
||||
<CodeBlock
|
||||
wrapperClassName="[&_pre]:max-h-40 [&_pre]:px-4 [&_pre]:py-3 [&_pre]:rounded-t-none"
|
||||
@@ -385,84 +300,122 @@ export const DatabaseConnectionString = () => {
|
||||
<div>
|
||||
{hasCodeExamples && (
|
||||
<div className="px-4 md:px-7 pt-8">
|
||||
<StepLabel number={++stepNumber}>Connect to your database</StepLabel>
|
||||
<StepLabel number={++stepNumber}>Choose type of connection</StepLabel>
|
||||
</div>
|
||||
)}
|
||||
<div className="px-4 md:px-7 py-8">
|
||||
{selectedMethod === 'direct' && (
|
||||
<ConnectionPanel
|
||||
type="direct"
|
||||
title={connectionStringMethodOptions.direct.label}
|
||||
contentType={contentType}
|
||||
lang={lang}
|
||||
fileTitle={fileTitle}
|
||||
description={connectionStringMethodOptions.direct.description}
|
||||
connectionString={connectionStrings['direct'][selectedTab]}
|
||||
ipv4Status={{
|
||||
type: !ipv4Addon ? 'error' : 'success',
|
||||
title: !ipv4Addon ? 'Not IPv4 compatible' : 'IPv4 compatible',
|
||||
description:
|
||||
!sharedPoolerPreferred && !ipv4Addon
|
||||
? PGBOUNCER_ENABLED_BUT_NO_IPV4_ADDON_TEXT
|
||||
: sharedPoolerPreferred
|
||||
? 'Use Session Pooler if on a IPv4 network or purchase IPv4 add-on'
|
||||
: IPV4_ADDON_TEXT,
|
||||
links: buttonLinks,
|
||||
}}
|
||||
parameters={[
|
||||
{ ...CONNECTION_PARAMETERS.host, value: connectionInfo.db_host },
|
||||
{ ...CONNECTION_PARAMETERS.port, value: connectionInfo.db_port },
|
||||
{ ...CONNECTION_PARAMETERS.database, value: connectionInfo.db_name },
|
||||
{ ...CONNECTION_PARAMETERS.user, value: connectionInfo.db_user },
|
||||
]}
|
||||
onCopyCallback={() => handleCopy(selectedTab, 'direct')}
|
||||
/>
|
||||
)}
|
||||
<div className="divide-y divide-border-muted [&>div]:px-4 [&>div]:md:px-7 [&>div]:py-8">
|
||||
<ConnectionPanel
|
||||
type="direct"
|
||||
title="Direct connection"
|
||||
contentType={contentType}
|
||||
lang={lang}
|
||||
fileTitle={fileTitle}
|
||||
description="Ideal for applications with persistent, long-lived connections, such as those running on virtual machines or long-standing containers."
|
||||
connectionString={connectionStrings['direct'][selectedTab]}
|
||||
ipv4Status={{
|
||||
type: !ipv4Addon ? 'error' : 'success',
|
||||
title: !ipv4Addon ? 'Not IPv4 compatible' : 'IPv4 compatible',
|
||||
description:
|
||||
!sharedPoolerPreferred && !ipv4Addon
|
||||
? PGBOUNCER_ENABLED_BUT_NO_IPV4_ADDON_TEXT
|
||||
: sharedPoolerPreferred
|
||||
? 'Use Session Pooler if on a IPv4 network or purchase IPv4 add-on'
|
||||
: IPV4_ADDON_TEXT,
|
||||
links: buttonLinks,
|
||||
}}
|
||||
parameters={[
|
||||
{ ...CONNECTION_PARAMETERS.host, value: connectionInfo.db_host },
|
||||
{ ...CONNECTION_PARAMETERS.port, value: connectionInfo.db_port },
|
||||
{ ...CONNECTION_PARAMETERS.database, value: connectionInfo.db_name },
|
||||
{ ...CONNECTION_PARAMETERS.user, value: connectionInfo.db_user },
|
||||
]}
|
||||
onCopyCallback={() => handleCopy(selectedTab, 'direct')}
|
||||
/>
|
||||
|
||||
{selectedMethod === 'transaction' && IS_PLATFORM && (
|
||||
<ConnectionPanel
|
||||
type="transaction"
|
||||
title={connectionStringMethodOptions.transaction.label}
|
||||
contentType={contentType}
|
||||
lang={lang}
|
||||
badge={poolerBadge}
|
||||
fileTitle={fileTitle}
|
||||
description={connectionStringMethodOptions.transaction.description}
|
||||
connectionString={connectionStrings['pooler'][selectedTab]}
|
||||
ipv4Status={{
|
||||
type: !sharedPoolerPreferred && !ipv4Addon ? 'error' : 'success',
|
||||
title:
|
||||
!sharedPoolerPreferred && !ipv4Addon
|
||||
? 'Not IPv4 compatible'
|
||||
: 'IPv4 compatible',
|
||||
description:
|
||||
!sharedPoolerPreferred && !ipv4Addon
|
||||
? PGBOUNCER_ENABLED_BUT_NO_IPV4_ADDON_TEXT
|
||||
: sharedPoolerPreferred
|
||||
? 'Transaction pooler connections are IPv4 proxied for free.'
|
||||
: IPV4_ADDON_TEXT,
|
||||
links: !sharedPoolerPreferred ? buttonLinks : undefined,
|
||||
}}
|
||||
notice={['Does not support PREPARE statements']}
|
||||
parameters={[
|
||||
{ ...CONNECTION_PARAMETERS.host, value: poolingConfiguration?.db_host ?? '' },
|
||||
{
|
||||
...CONNECTION_PARAMETERS.port,
|
||||
value: poolingConfiguration?.db_port.toString() ?? '6543',
|
||||
},
|
||||
{
|
||||
...CONNECTION_PARAMETERS.database,
|
||||
value: poolingConfiguration?.db_name ?? '',
|
||||
},
|
||||
{ ...CONNECTION_PARAMETERS.user, value: poolingConfiguration?.db_user ?? '' },
|
||||
{ ...CONNECTION_PARAMETERS.pool_mode, value: 'transaction' },
|
||||
]}
|
||||
onCopyCallback={() => handleCopy(selectedTab, 'transaction_pooler')}
|
||||
/>
|
||||
)}
|
||||
|
||||
{selectedMethod === 'session' && IS_PLATFORM && (
|
||||
{IS_PLATFORM && (
|
||||
<>
|
||||
<ConnectionPanel
|
||||
type="transaction"
|
||||
title="Transaction pooler"
|
||||
contentType={contentType}
|
||||
lang={lang}
|
||||
badge={poolerBadge}
|
||||
fileTitle={fileTitle}
|
||||
description="Ideal for stateless applications like serverless functions where each interaction with Postgres is brief and isolated."
|
||||
connectionString={connectionStrings['pooler'][selectedTab]}
|
||||
ipv4Status={{
|
||||
type: !sharedPoolerPreferred && !ipv4Addon ? 'error' : 'success',
|
||||
title:
|
||||
!sharedPoolerPreferred && !ipv4Addon
|
||||
? 'Not IPv4 compatible'
|
||||
: 'IPv4 compatible',
|
||||
description:
|
||||
!sharedPoolerPreferred && !ipv4Addon
|
||||
? PGBOUNCER_ENABLED_BUT_NO_IPV4_ADDON_TEXT
|
||||
: sharedPoolerPreferred
|
||||
? 'Transaction pooler connections are IPv4 proxied for free.'
|
||||
: IPV4_ADDON_TEXT,
|
||||
links: !sharedPoolerPreferred ? buttonLinks : undefined,
|
||||
}}
|
||||
notice={['Does not support PREPARE statements']}
|
||||
parameters={[
|
||||
{ ...CONNECTION_PARAMETERS.host, value: poolingConfiguration?.db_host ?? '' },
|
||||
{
|
||||
...CONNECTION_PARAMETERS.port,
|
||||
value: poolingConfiguration?.db_port.toString() ?? '6543',
|
||||
},
|
||||
{
|
||||
...CONNECTION_PARAMETERS.database,
|
||||
value: poolingConfiguration?.db_name ?? '',
|
||||
},
|
||||
{ ...CONNECTION_PARAMETERS.user, value: poolingConfiguration?.db_user ?? '' },
|
||||
{ ...CONNECTION_PARAMETERS.pool_mode, value: 'transaction' },
|
||||
]}
|
||||
onCopyCallback={() => handleCopy(selectedTab, 'transaction_pooler')}
|
||||
>
|
||||
{!sharedPoolerPreferred && !ipv4Addon && (
|
||||
<Collapsible_Shadcn_ className="group">
|
||||
<CollapsibleTrigger_Shadcn_
|
||||
asChild
|
||||
className="w-full justify-start !last:rounded-b group-data-[state=open]:rounded-b-none border-light mt-4 px-3"
|
||||
>
|
||||
<Button
|
||||
type="default"
|
||||
size="large"
|
||||
iconRight={
|
||||
<ChevronDown className="transition group-data-[state=open]:rotate-180" />
|
||||
}
|
||||
className="text-foreground !bg-dash-sidebar justify-between"
|
||||
>
|
||||
<div className="text-xs flex items-center p-2">
|
||||
<span>Using the Shared Pooler</span>
|
||||
<Badge variant={'brand'} size={'small'} className="ml-2">
|
||||
IPv4 compatible
|
||||
</Badge>
|
||||
</div>
|
||||
</Button>
|
||||
</CollapsibleTrigger_Shadcn_>
|
||||
<CollapsibleContent_Shadcn_ className="bg-dash-sidebar rounded-b border text-xs">
|
||||
<p className="px-3 py-2">
|
||||
Only recommended when your network does not support IPv6. Added latency
|
||||
compared to dedicated pooler.
|
||||
</p>
|
||||
<CodeBlock
|
||||
wrapperClassName={cn(
|
||||
'[&_pre]:border-x-0 [&_pre]:border-b-0 [&_pre]:px-4 [&_pre]:py-3',
|
||||
'[&_pre]:rounded-t-none'
|
||||
)}
|
||||
language={lang}
|
||||
value={supavisorConnectionStrings['pooler'][selectedTab]}
|
||||
className="[&_code]:text-[12px] [&_code]:text-foreground"
|
||||
hideLineNumbers
|
||||
onCopyCallback={() => handleCopy(selectedTab, 'transaction_pooler')}
|
||||
/>
|
||||
</CollapsibleContent_Shadcn_>
|
||||
</Collapsible_Shadcn_>
|
||||
)}
|
||||
</ConnectionPanel>
|
||||
|
||||
{sharedPoolerPreferred && ipv4Addon && (
|
||||
<Admonition
|
||||
type="warning"
|
||||
@@ -475,14 +428,15 @@ export const DatabaseConnectionString = () => {
|
||||
</p>
|
||||
</Admonition>
|
||||
)}
|
||||
|
||||
<ConnectionPanel
|
||||
type="session"
|
||||
title={connectionStringMethodOptions.session.label}
|
||||
title="Session pooler"
|
||||
contentType={contentType}
|
||||
lang={lang}
|
||||
badge="Shared Pooler"
|
||||
fileTitle={fileTitle}
|
||||
description={connectionStringMethodOptions.session.description}
|
||||
description="Only recommended as an alternative to Direct Connection, when connecting via an IPv4 network."
|
||||
connectionString={supavisorConnectionStrings['pooler'][selectedTab].replace(
|
||||
'6543',
|
||||
'5432'
|
||||
@@ -511,22 +465,23 @@ export const DatabaseConnectionString = () => {
|
||||
</div>
|
||||
|
||||
{examplePostInstallCommands && (
|
||||
<div className="grid lg:grid-cols-3 gap-4 lg:gap-5 w-full px-4 md:px-7 py-8">
|
||||
<StepLabel number={++stepNumber} className="items-start">
|
||||
Add the configuration package to read the settings
|
||||
</StepLabel>
|
||||
{examplePostInstallCommands?.map((cmd) => (
|
||||
<CodeBlock
|
||||
key={`example-post-install-commands-${cmd}`}
|
||||
className="text-sm"
|
||||
wrapperClassName="lg:col-span-2"
|
||||
value={cmd}
|
||||
hideLineNumbers
|
||||
language="bash"
|
||||
>
|
||||
{cmd}
|
||||
</CodeBlock>
|
||||
))}
|
||||
<div className="grid grid-cols-2 gap-20 w-full px-4 md:px-7 py-10">
|
||||
<div>
|
||||
<StepLabel number={++stepNumber} className="mb-4">
|
||||
Add the configuration package to read the settings
|
||||
</StepLabel>
|
||||
{examplePostInstallCommands?.map((cmd, i) => (
|
||||
<CodeBlock
|
||||
key={i}
|
||||
className="text-sm"
|
||||
value={cmd}
|
||||
hideLineNumbers
|
||||
language="bash"
|
||||
>
|
||||
{cmd}
|
||||
</CodeBlock>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -581,43 +536,3 @@ export const DatabaseConnectionString = () => {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const ConnectionStringMethodSelectItem = ({
|
||||
method,
|
||||
poolerBadge,
|
||||
}: {
|
||||
method: ConnectionStringMethod
|
||||
poolerBadge: string
|
||||
}) => (
|
||||
<SelectItem_Shadcn_ value={method} className="[&>span:first-child]:top-3.5">
|
||||
<div className="flex flex-col w-full py-1">
|
||||
<div>{connectionStringMethodOptions[method].label}</div>
|
||||
<div className="text-foreground-lighter text-xs">
|
||||
{connectionStringMethodOptions[method].description}
|
||||
</div>
|
||||
<div className="flex items-center gap-1 mt-2">
|
||||
{method === 'session' ? (
|
||||
<Badge variant="outline" size="small" className="flex gap-1 text-foreground-lighter">
|
||||
<InfoIcon className="w-3 h-3" />
|
||||
{connectionStringMethodOptions[method].badge}
|
||||
</Badge>
|
||||
) : (
|
||||
<Badge variant="outline" size="small" className="flex gap-1 text-foreground-lighter">
|
||||
<GlobeIcon className="w-3 h-3" />
|
||||
{connectionStringMethodOptions[method].badge}
|
||||
</Badge>
|
||||
)}
|
||||
{method === 'transaction' && (
|
||||
<Badge variant="outline" size="small" className="text-foreground-lighter">
|
||||
{poolerBadge}
|
||||
</Badge>
|
||||
)}
|
||||
{method === 'session' && (
|
||||
<Badge variant="outline" size="small" className="text-foreground-lighter">
|
||||
Shared Pooler
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</SelectItem_Shadcn_>
|
||||
)
|
||||
Reference in new issue
Block a user