import { useFlag, useParams } from 'common' import { UseFormReturn } from 'react-hook-form' import type { CloudProvider } from 'shared-data' import { Badge, cn, FormField, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Tooltip, TooltipContent, TooltipTrigger, } from 'ui' import { Admonition } from 'ui-patterns/admonition' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import { CreateProjectForm } from './ProjectCreation.schema' import { getAvailableRegions } from './ProjectCreation.utils' import AlertError from '@/components/ui/AlertError' import { InlineLink } from '@/components/ui/InlineLink' import Panel from '@/components/ui/Panel' import { useDefaultRegionQuery } from '@/data/misc/get-default-region-query' import { useOrganizationAvailableRegionsQuery } from '@/data/organizations/organization-available-regions-query' import { useIncidentStatusQuery } from '@/data/platform/incident-status-query' import type { DesiredInstanceSize } from '@/data/projects/new-project.constants' import { BASE_PATH, PROVIDERS } from '@/lib/constants' interface RegionSelectorProps { form: UseFormReturn instanceSize?: DesiredInstanceSize layout?: 'vertical' | 'horizontal' } // [Joshen] Let's use a library to maintain the flag SVGs in the future // I tried using https://flagpack.xyz/docs/development/react/ but couldn't get it to render // ^ can try again next time // Maps smart region group codes to the specific-region code prefixes they contain. // Used to check whether an incident affecting specific regions also affects a smart region selection. const SMART_REGION_PREFIXES: Record> = { americas: ['us-', 'ca-', 'sa-'], emea: ['eu-', 'me-', 'af-'], apac: ['ap-'], } function smartRegionMatchesSpecific(smartCode: string, specificCode: string): boolean { return (SMART_REGION_PREFIXES[smartCode] ?? []).some((prefix) => specificCode.startsWith(prefix)) } // Map backend region names to user-friendly display names const getDisplayNameForSmartRegion = (name: string): string => { if (name === 'APAC') { return 'Asia-Pacific' } return name } export const RegionSelector = ({ form, instanceSize, layout = 'horizontal', }: RegionSelectorProps) => { const { slug } = useParams() const cloudProvider = form.getValues('cloudProvider') as CloudProvider const smartRegionEnabled = useFlag('enableSmartRegion') const { data: statusData } = useIncidentStatusQuery() const { incidents = [] } = statusData ?? {} const { isPending: isLoadingDefaultRegion } = useDefaultRegionQuery( { cloudProvider }, { enabled: !smartRegionEnabled } ) const { data: availableRegionsData, isPending: isLoadingAvailableRegions, isError: isErrorAvailableRegions, error: errorAvailableRegions, } = useOrganizationAvailableRegionsQuery( { slug, cloudProvider, desiredInstanceSize: instanceSize }, { enabled: smartRegionEnabled, staleTime: 1000 * 60 * 5 } // 5 minutes ) const smartRegions = availableRegionsData?.all.smartGroup ?? [] const allRegions = availableRegionsData?.all.specific ?? [] const recommendedSmartRegions = new Set( [availableRegionsData?.recommendations.smartGroup.code].filter(Boolean) ) const recommendedSpecificRegions = new Set( availableRegionsData?.recommendations.specific.map((region) => region.code) ) const availableRegions = getAvailableRegions(PROVIDERS[cloudProvider].id) const regionsArray = Object.entries(availableRegions).map(([_key, value]) => { return { code: value.code, name: value.displayName, provider: cloudProvider, status: undefined, } }) const regionOptions = smartRegionEnabled ? allRegions : regionsArray const isLoading = smartRegionEnabled ? isLoadingAvailableRegions : isLoadingDefaultRegion const showNonProdFields = process.env.NEXT_PUBLIC_ENVIRONMENT === 'local' || process.env.NEXT_PUBLIC_ENVIRONMENT === 'staging' const allSelectableRegions = [...smartRegions, ...regionOptions] if (isErrorAvailableRegions) { return } return ( { const selectedRegion = allSelectableRegions.find((region) => { return !!region.name && region.name === field.value }) const affectingIncidents = incidents.filter((incident) => { const affectedRegions = incident.cache?.affected_regions ?? [] if (affectedRegions.length === 0 || selectedRegion?.code === undefined) return false // Specific region: direct code match if (affectedRegions.includes(selectedRegion.code)) return true // Smart region: match if any affected region falls within the smart group return affectedRegions.some((specificCode) => smartRegionMatchesSpecific(selectedRegion.code, specificCode) ) }) return ( <>

Select the region closest to your users for the best performance.

{showNonProdFields && (

Only these regions are supported for local/staging projects:

  • East US (North Virginia)
  • Central EU (Frankfurt)
  • Southeast Asia (Singapore)
)} } >
{affectingIncidents.length > 0 && ( We're currently investigating an issue that may impact projects in this region. Follow updates on{' '} status.supabase.com . } className="mt-3" /> )} ) }} />
) }