import { zodResolver } from '@hookform/resolvers/zod'
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { useEffect, useState } from 'react'
import { useForm, useWatch } from 'react-hook-form'
import { toast } from 'sonner'
import {
Button,
Card,
CardContent,
CardFooter,
Form,
FormControl,
FormField,
FormInputGroupInput,
InputGroup,
InputGroupAddon,
InputGroupText,
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from 'ui'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import { GenericSkeletonLoader, ShimmeringLoader } from 'ui-patterns/ShimmeringLoader'
import * as z from 'zod'
import { convertPoolSize, isAllocationUnit } from './PerformanceSettingsForm.utils'
import { ScaffoldSection, ScaffoldSectionTitle } from '@/components/layouts/Scaffold'
import { AlertError } from '@/components/ui/AlertError'
import { NoPermission } from '@/components/ui/NoPermission'
import { UpgradeToPro } from '@/components/ui/UpgradeToPro'
import { useAuthConfigQuery } from '@/data/auth/auth-config-query'
import { useAuthConfigUpdateMutation } from '@/data/auth/auth-config-update-mutation'
import { useMaxConnectionsQuery } from '@/data/database/max-connections-query'
import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements'
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
import { IS_PLATFORM } from '@/lib/constants'
const FormSchema = z.object({
API_MAX_REQUEST_DURATION: z.coerce
.number()
.min(5, 'Must be 5 or larger')
.max(30, 'Must be a value no greater than 30'),
DB_MAX_POOL_SIZE: z.coerce.number().min(1),
DB_MAX_POOL_SIZE_UNIT: z.enum(['percent', 'connections']),
})
export const DatabaseFormSchema = z
.object({
DB_MAX_POOL_SIZE: z.coerce.number().min(1),
DB_MAX_POOL_SIZE_UNIT: z.enum(['percent', 'connections']),
})
.superRefine((data, ctx) => {
if (data.DB_MAX_POOL_SIZE_UNIT === 'percent') {
if (data.DB_MAX_POOL_SIZE < 1 || data.DB_MAX_POOL_SIZE > 100) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ['DB_MAX_POOL_SIZE'],
message: 'Percentage must be between 1 and 100',
})
}
}
})
export const PerformanceSettingsForm = () => {
const { data: project } = useSelectedProjectQuery()
const { hasAccess: hasAccessToPerformance, isLoading: isLoadingEntitlement } =
useCheckEntitlements('auth.performance_settings')
const { can: canReadConfig } = useAsyncCheckPermissions(
PermissionAction.READ,
'custom_config_gotrue'
)
const { can: canUpdateConfig } = useAsyncCheckPermissions(
PermissionAction.UPDATE,
'custom_config_gotrue'
)
const [isUpdatingRequestDurationForm, setIsUpdatingRequestDurationForm] = useState(false)
const [isUpdatingDatabaseForm, setIsUpdatingDatabaseForm] = useState(false)
const {
data: authConfig,
error: authConfigError,
isError,
isLoading: isLoadingAuthConfig,
} = useAuthConfigQuery({ projectRef: project?.ref })
const { data: maxConnData, isLoading: isLoadingMaxConns } = useMaxConnectionsQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
const maxConnectionLimit = maxConnData?.maxConnections ?? 60
const promptUpgrade = IS_PLATFORM && !isLoadingEntitlement && !hasAccessToPerformance
const { mutate: updateAuthConfig } = useAuthConfigUpdateMutation()
const requestDurationForm = useForm({
resolver: zodResolver(
z.object({ API_MAX_REQUEST_DURATION: FormSchema.shape.API_MAX_REQUEST_DURATION })
),
defaultValues: { API_MAX_REQUEST_DURATION: 10 },
})
const databaseForm = useForm
10+ seconds recommended