import { zodResolver } from '@hookform/resolvers/zod' import { useFlag, useParams } from 'common' import { AlertCircle, AlertTriangle } from 'lucide-react' import Link from 'next/link' import { useRouter } from 'next/router' import { useEffect, useState } from 'react' import { useForm } from 'react-hook-form' import { toast } from 'sonner' import { Alert, AlertDescription, AlertTitle, Badge, Button, Dialog, DialogContent, DialogFooter, DialogHeader, DialogSection, DialogSectionSeparator, DialogTitle, DialogTrigger, Form, FormControl, FormField, Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, } from 'ui' import { Admonition } from 'ui-patterns/admonition' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import { z } from 'zod' import { PLAN_DETAILS } from '@/components/interfaces/DiskManagement/ui/DiskManagement.constants' import { Markdown } from '@/components/interfaces/Markdown' import { extractPostgresVersionDetails } from '@/components/interfaces/ProjectCreation/PostgresVersionSelector' import { ButtonTooltip } from '@/components/ui/ButtonTooltip' import { useDiskAttributesQuery } from '@/data/config/disk-attributes-query' import { ProjectUpgradeTargetVersion, useProjectUpgradeEligibilityQuery, } from '@/data/config/project-upgrade-eligibility-query' import { useSetProjectStatus } from '@/data/projects/project-detail-query' import { useProjectUpgradeMutation } from '@/data/projects/project-upgrade-mutation' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' import { DOCS_URL, PROJECT_STATUS } from '@/lib/constants' const formatValue = ({ postgres_version, release_channel }: ProjectUpgradeTargetVersion) => { return `${postgres_version}|${release_channel}` } export const ProjectUpgradeAlert = () => { const router = useRouter() const { ref } = useParams() const { data: org } = useSelectedOrganizationQuery() const { setProjectStatus } = useSetProjectStatus() const [showUpgradeModal, setShowUpgradeModal] = useState(false) const projectUpgradeDisabled = useFlag('disableProjectUpgrade') const planId = org?.plan.id ?? 'free' const { data: diskAttributes } = useDiskAttributesQuery({ projectRef: ref }) const { includedDiskGB: includedDiskGBMeta } = PLAN_DETAILS[planId] const includedDiskGB = includedDiskGBMeta[diskAttributes?.attributes.type ?? 'gp3'] const isDiskSizeUpdated = diskAttributes?.attributes.size_gb !== includedDiskGB const { data } = useProjectUpgradeEligibilityQuery({ projectRef: ref }) const currentPgVersion = (data?.current_app_version ?? '').split('supabase-postgres-')[1] const latestPgVersion = (data?.latest_app_version ?? '').split('supabase-postgres-')[1] const durationEstimateHours = data?.duration_estimate_hours || 1 const legacyAuthCustomRoles = data?.legacy_auth_custom_roles || [] const { mutate: upgradeProject, isPending: isUpgrading } = useProjectUpgradeMutation({ onSuccess: (res, variables) => { setProjectStatus({ ref: variables.ref, status: PROJECT_STATUS.UPGRADING }) toast.success('Upgrading project') router.push(`/project/${variables.ref}?upgradeInitiated=true&trackingId=${res.tracking_id}`) }, }) const onConfirmUpgrade = async (values: z.infer) => { if (!ref) return toast.error('Project ref not found') const { postgresVersionSelection } = values const versionDetails = extractPostgresVersionDetails(postgresVersionSelection) if (!versionDetails) return toast.error('Invalid Postgres version') if (!versionDetails.postgresEngine) return toast.error('Missing target version') upgradeProject({ ref, target_version: versionDetails.postgresEngine, release_channel: versionDetails.releaseChannel, }) } const FormSchema = z.object({ postgresVersionSelection: z.string(), }) const form = useForm>({ resolver: zodResolver(FormSchema), mode: 'onChange', defaultValues: { postgresVersionSelection: '', }, }) useEffect(() => { const defaultValue = data?.target_upgrade_versions?.[0] ? formatValue(data.target_upgrade_versions[0]) : '' form.setValue('postgresVersionSelection', defaultValue) }, [data, form]) return ( Your project can be upgraded to the latest version of Postgres

The latest version of Postgres ({latestPgVersion}) is available for your project.

setShowUpgradeModal(open)}> Upgrade project Confirm to upgrade Postgres version

All services will be offline and you will not be able to downgrade back to Postgres {currentPgVersion}.

{isDiskSizeUpdated && ( )} {/* @ts-ignore */} {(data?.potential_breaking_changes ?? []).length > 0 && ( Breaking changes

Your project will be upgraded across major versions of Postgres. This may involve breaking changes.

)} {legacyAuthCustomRoles.length > 0 && ( Custom Postgres roles will not work automatically after upgrade

You must run a series of commands after upgrading.

This is because new Postgres versions use scram-sha-256 authentication by default and do not support md5, as it has been deprecated.

Run the following commands after the upgrade:

{legacyAuthCustomRoles.map((role) => (
ALTER ROLE {role} WITH PASSWORD 'newpassword';
))}
)} ( )} />
) }