import { SupportCategories } from '@supabase/shared-types/out/constants' import { useParams } from 'common' import { CpuIcon, Lock, Microchip } from 'lucide-react' import { useMemo } from 'react' import { UseFormReturn, useWatch } from 'react-hook-form' import { cn, FormField, HoverCard, HoverCardContent, HoverCardTrigger, RadioGroupCard, RadioGroupCardItem, Skeleton, Tooltip, TooltipContent, TooltipTrigger, } from 'ui' import { ComputeBadge } from 'ui-patterns/ComputeBadge' import { DiskStorageSchemaType } from '../DiskManagement.schema' import { ComputeInstanceAddonVariantId, InfraInstanceSize } from '../DiskManagement.types' import { ComputeAddonVariant, getAvailableComputeOptions, mapComputeSizeNameToAddonVariantId, } from '../DiskManagement.utils' import { BillingChangeBadge } from '../ui/BillingChangeBadge' import FormMessage from '../ui/FormMessage' import { useShowMicroUpgradeBadge } from './useShowMicroUpgradeBadge' import { SupportLink } from '@/components/interfaces/Support/SupportLink' import { InlineLink } from '@/components/ui/InlineLink' import { useProjectAddonsQuery } from '@/data/subscriptions/project-addons-query' import { useHighAvailability } from '@/hooks/misc/useHighAvailability' import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' const SKELETON_PLACEHOLDER_COUNT = 6 /** * to do: this could be a type from api-types */ type ComputeSizeFieldProps = { form: UseFormReturn disabled?: boolean } export function ComputeSizeFieldMeta() { return

Hardware resources allocated to your Postgres database

} type ComputeSectionBillingBadgeProps = { form: UseFormReturn show: boolean beforePrice: number afterPrice: number } export function ComputeSectionBillingBadge({ form, show, beforePrice, afterPrice, }: ComputeSectionBillingBadgeProps) { const computeSize = useWatch({ control: form.control, name: 'computeSize' }) const { showMicroUpgradeBadge } = useShowMicroUpgradeBadge() return ( ) } export function ComputeSizeField({ form, disabled }: ComputeSizeFieldProps) { const { ref } = useParams() const { data: org } = useSelectedOrganizationQuery() const { project, isProjectLoading, isEntitlementLoading, showMicroUpgradeBadge } = useShowMicroUpgradeBadge() const { isHighAvailability } = useHighAvailability() // High Availability projects run on a fixed compute size during Alpha, // so every option other than the project's current size is locked const currentComputeVariantId = project?.infra_compute_size ? mapComputeSizeNameToAddonVariantId(project.infra_compute_size) : undefined const showComputePrice = useIsFeatureEnabled('project_addons:show_compute_price') const { data: addons, isPending: isAddonsLoading, error: addonsError, } = useProjectAddonsQuery({ projectRef: ref }) const isLoading = isProjectLoading || isAddonsLoading || isEntitlementLoading const { control, setValue, trigger } = form const availableAddons = useMemo(() => { return addons?.available_addons ?? [] }, [addons]) const availableOptions = useMemo(() => { /** * Returns the available compute options for the project * Also handles backwards compatibility for older API versions * Also handles a case in which Nano is not available from the API */ return getAvailableComputeOptions(availableAddons, project?.cloud_provider) }, [availableAddons, project?.cloud_provider]) const subscriptionPitr = addons?.selected_addons.find((addon) => addon.type === 'pitr') const showSkeletons = isLoading const showLoadError = !isLoading && !!addonsError const showComputeOptions = !isLoading && !addonsError return ( (
{ setValue('computeSize', value, { shouldDirty: true, shouldValidate: true, }) trigger('provisionedIOPS') trigger('throughput') }} disabled={disabled} className={cn( !addonsError && 'grid grid-cols-2 gap-4 @[680px]:grid-cols-3 @[900px]:grid-cols-4' )} > {showSkeletons && Array(SKELETON_PLACEHOLDER_COUNT) .fill(0) .map((_, i) => )} {showLoadError && (

{addonsError?.message}

)} {showComputeOptions && ( <> {availableOptions.map((compute) => { const lockedMicroDueToPITR = compute.identifier === 'ci_micro' && !!subscriptionPitr const lockedNanoDueToPlan = org?.plan.id !== 'free' && project?.infra_compute_size !== 'nano' && compute.identifier === 'ci_nano' const lockedDueToHighAvailability = isHighAvailability && compute.identifier !== currentComputeVariantId const lockedOption = lockedNanoDueToPlan || lockedMicroDueToPITR || lockedDueToHighAvailability // Nano on a paid plan is billed at the Micro rate const isNanoBilledAsMicro = org?.plan.id !== 'free' && project?.infra_compute_size === 'nano' && compute.identifier === 'ci_nano' const price = isNanoBilledAsMicro ? availableOptions.find( (option: ComputeAddonVariant) => option.identifier === 'ci_micro' )?.price : compute.price const cpuLabel = (() => { const cpuCores = compute.meta?.cpu_cores if (typeof cpuCores === 'number') { return `${cpuCores}-core CPU` } if (cpuCores) { return `${cpuCores} CPU` } return 'CPU' })() return (
{showMicroUpgradeBadge && compute.identifier === 'ci_micro' && (
e.stopPropagation()} onPointerDown={(e) => e.stopPropagation()} > Free Upgrade
e.stopPropagation()} >

Upgrade to Micro Compute

This Project is already paying for Micro Compute. You can upgrade to Micro Compute at any time when convenient.

)}
{lockedOption && (
)} {!lockedOption && showComputePrice && ( <> ${price} {' '} /{' '} {compute.price_interval === 'monthly' ? 'month' : 'hour'} )}
{compute.identifier === 'ci_nano' && 'Up to '} {compute.meta?.memory_gb ?? 0} GB memory
{cpuLabel}
{lockedDueToHighAvailability && ( Compute size can't be changed on High Availability projects during Alpha )} {!lockedDueToHighAvailability && lockedMicroDueToPITR && ( Project has PITR enabled which requires a minimum of Small compute. Please{' '} disable PITR {' '} first before selecting Micro )} } /> ) })} {!isHighAvailability && (
Contact Us
Custom memory
Custom CPU
)} )}
)} /> ) }