| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- import { useParams } from 'common'
- import dynamic from 'next/dynamic'
- import { forwardRef, HTMLAttributes, useMemo } from 'react'
- import { cn } from 'ui'
- import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
- import { CopyCallbackContext } from 'ui-patterns/SimpleCodeBlock'
- import { getAddons } from '../Billing/Subscription/Subscription.utils'
- import type { projectKeys } from './Connect.types'
- import { getConnectionStrings } from './DatabaseSettings.utils'
- import { useProjectSettingsV2Query } from '@/data/config/project-settings-v2-query'
- import { usePgbouncerConfigQuery } from '@/data/database/pgbouncer-config-query'
- import { useSupavisorConfigurationQuery } from '@/data/database/supavisor-configuration-query'
- import { useProjectAddonsQuery } from '@/data/subscriptions/project-addons-query'
- import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements'
- import { pluckObjectFields } from '@/lib/helpers'
- import { useTrack } from '@/lib/telemetry/track'
- interface ConnectContentTabProps extends HTMLAttributes<HTMLDivElement> {
- projectKeys: projectKeys
- filePath: string
- connectionTab: 'App Frameworks' | 'Mobile Frameworks' | 'ORMs'
- selectedFrameworkOrTool: string
- connectionStringPooler?: {
- transactionShared: string
- sessionShared: string
- transactionDedicated?: string
- sessionDedicated?: string
- ipv4SupportedForDedicatedPooler: boolean
- direct?: string
- }
- }
- export const ConnectTabContent = forwardRef<HTMLDivElement, ConnectContentTabProps>(
- ({ projectKeys, filePath, connectionTab, selectedFrameworkOrTool, ...props }, ref) => {
- const { ref: projectRef } = useParams()
- const track = useTrack()
- const { hasAccess: allowPgBouncerSelection } = useCheckEntitlements('dedicated_pooler')
- const handleCopy = () => {
- const trackingProperties: {
- connectionTab: 'App Frameworks' | 'Mobile Frameworks' | 'ORMs'
- selectedItem: string
- connectionType?: string
- lang?: string
- } = {
- connectionTab,
- selectedItem: selectedFrameworkOrTool,
- }
- // Only include connectionType and lang for App Frameworks and Mobile Frameworks
- if (connectionTab !== 'ORMs') {
- trackingProperties.connectionType = 'Framework snippet'
- trackingProperties.lang = filePath.split('/').pop() ?? 'unknown'
- }
- track('connection_string_copied', trackingProperties)
- }
- const { data: settings } = useProjectSettingsV2Query({ projectRef })
- const { data: pgbouncerConfig } = usePgbouncerConfigQuery({ projectRef })
- const { data: supavisorConfig } = useSupavisorConfigurationQuery({ projectRef })
- const { data: addons } = 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(settings || emptyState, DB_FIELDS)
- const poolingConfigurationShared = supavisorConfig?.find((x) => x.database_type === 'PRIMARY')
- const poolingConfigurationDedicated = allowPgBouncerSelection ? pgbouncerConfig : undefined
- const connectionStringsShared = getConnectionStrings({
- connectionInfo,
- poolingInfo: {
- connectionString: poolingConfigurationShared?.connection_string ?? '',
- db_host: poolingConfigurationShared?.db_host ?? '',
- db_name: poolingConfigurationShared?.db_name ?? '',
- db_port: poolingConfigurationShared?.db_port ?? 0,
- db_user: poolingConfigurationShared?.db_user ?? '',
- },
- metadata: { projectRef },
- })
- const connectionStringsDedicated =
- poolingConfigurationDedicated !== undefined
- ? getConnectionStrings({
- connectionInfo,
- poolingInfo: {
- connectionString: poolingConfigurationDedicated.connection_string,
- db_host: poolingConfigurationDedicated.db_host,
- db_name: poolingConfigurationDedicated.db_name,
- db_port: poolingConfigurationDedicated.db_port,
- db_user: poolingConfigurationDedicated.db_user,
- },
- metadata: { projectRef },
- })
- : undefined
- const ContentFile = useMemo(() => {
- return dynamic<ConnectContentTabProps>(() => import(`./content/${filePath}/content`), {
- loading: () => (
- <div className="p-4 min-h-[331px]">
- <GenericSkeletonLoader />
- </div>
- ),
- })
- }, [filePath])
- return (
- <div ref={ref} {...props} className={cn('border rounded-lg', props.className)}>
- <CopyCallbackContext.Provider value={handleCopy}>
- <ContentFile
- projectKeys={projectKeys}
- filePath={filePath}
- connectionTab={connectionTab}
- selectedFrameworkOrTool={selectedFrameworkOrTool}
- connectionStringPooler={{
- transactionShared: connectionStringsShared.pooler.uri,
- sessionShared: connectionStringsShared.pooler.uri.replace('6543', '5432'),
- transactionDedicated: connectionStringsDedicated?.pooler.uri,
- sessionDedicated: connectionStringsDedicated?.pooler.uri.replace('6543', '5432'),
- ipv4SupportedForDedicatedPooler: !!ipv4Addon,
- direct: connectionStringsShared.direct.uri,
- }}
- onCopy={handleCopy}
- />
- </CopyCallbackContext.Provider>
- </div>
- )
- }
- )
- ConnectTabContent.displayName = 'ConnectTabContent'
|