import { zodResolver } from '@hookform/resolvers/zod'
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { useParams } from 'common'
import { capitalize } from 'lodash'
import Link from 'next/link'
import { Fragment, useEffect } from 'react'
import { SubmitHandler, useForm } from 'react-hook-form'
import { toast } from 'sonner'
import {
Alert,
AlertDescription,
AlertTitle,
Badge,
Button,
Form,
FormControl,
FormField,
FormInputGroupInput,
InputGroup,
InputGroupAddon,
InputGroupText,
Separator,
} from 'ui'
import { Admonition } from 'ui-patterns'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import {
PageSection,
PageSectionAside,
PageSectionContent,
PageSectionMeta,
PageSectionSummary,
PageSectionTitle,
} from 'ui-patterns/PageSection'
import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
import z from 'zod'
import { POOLING_OPTIMIZATIONS } from './ConnectionPooling.constants'
import AlertError from '@/components/ui/AlertError'
import { DocsButton } from '@/components/ui/DocsButton'
import { FormActions } from '@/components/ui/Forms/FormActions'
import { InlineLink } from '@/components/ui/InlineLink'
import Panel from '@/components/ui/Panel'
import { useMaxConnectionsQuery } from '@/data/database/max-connections-query'
import { usePgbouncerConfigQuery } from '@/data/database/pgbouncer-config-query'
import { usePgbouncerConfigurationUpdateMutation } from '@/data/database/pgbouncer-config-update-mutation'
import { useProjectAddonsQuery } from '@/data/subscriptions/project-addons-query'
import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements'
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
import { DOCS_URL } from '@/lib/constants'
const formId = 'pooling-configuration-form'
const PoolingConfigurationFormSchema = z.object({
default_pool_size: z.preprocess(
(val) => (val === '' || val === null || val === undefined ? undefined : val),
z.coerce.number().optional()
),
max_client_conn: z.preprocess(
(val) => (val === '' || val === null || val === undefined ? undefined : val),
z.coerce.number().optional()
),
})
/**
* [Joshen] PgBouncer configuration will be the main endpoint for GET and PATCH of pooling config
*/
export const ConnectionPooling = () => {
const { ref: projectRef } = useParams()
const { data: project } = useSelectedProjectQuery()
const { can: canUpdateConnectionPoolingConfiguration } = useAsyncCheckPermissions(
PermissionAction.UPDATE,
'projects',
{ resource: { project_id: project?.id } }
)
const {
data: pgbouncerConfig,
error: pgbouncerConfigError,
isPending: isLoadingPgbouncerConfig,
isError: isErrorPgbouncerConfig,
isSuccess: isSuccessPgbouncerConfig,
} = usePgbouncerConfigQuery({ projectRef })
const { hasAccess: hasDedicatedPooler } = useCheckEntitlements('dedicated_pooler')
const disablePoolModeSelection = !hasDedicatedPooler
const { data: maxConnData } = useMaxConnectionsQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
const { data: addons, isSuccess: isSuccessAddons } = useProjectAddonsQuery({ projectRef })
const { mutate: updatePoolerConfig, isPending: isUpdatingPoolerConfig } =
usePgbouncerConfigurationUpdateMutation()
const hasIpv4Addon = !!addons?.selected_addons.find((addon) => addon.type === 'ipv4')
const computeInstance = addons?.selected_addons.find((addon) => addon.type === 'compute_instance')
const computeSize =
computeInstance?.variant.name ?? capitalize(project?.infra_compute_size) ?? 'Nano'
const poolingOptimizations =
POOLING_OPTIMIZATIONS[
(computeInstance?.variant.identifier as keyof typeof POOLING_OPTIMIZATIONS) ??
(project?.infra_compute_size === 'nano' ? 'ci_nano' : 'ci_micro')
]
const defaultPoolSize = poolingOptimizations.poolSize ?? 15
const defaultMaxClientConn = poolingOptimizations.maxClientConn ?? 200
const form = useForm
Configuration is shared across all connection poolers.
Connection poolers
The maximum number of concurrent client connections allowed. This
value is fixed at {defaultMaxClientConn} based on your compute size
of {computeSize} and cannot be changed.{' '}