mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 18:05:11 +03:00
## Summary - Move High Availability into the standard project creation settings above Compute, gated by the `instances.high_availability` entitlement. - Mark the option as Alpha and explain that it is free during Alpha for up to two projects. - Enforce the supported HA configuration: `AWS_K8S`, Postgres 17 on the `ga` release channel (no custom version is sent — the API resolves the image), and the environment-specific local/staging region restrictions. - Show eligible locations in a dedicated **High Availability Regions** group. - Preserve the existing Advanced Configuration availability rules and additionally hide the section while HA is enabled. - Restore the previous provider and Postgres settings when HA is switched off. ## How to test 1. Go to create a new project 2. Ensure you have access to high availability (e.g. on local) 3. Toggle high availability on and note how the project form restricts settings listed above <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added High Availability to project creation with Alpha warning labeling and improved switch accessibility. * Constrains region selection to compatible High Availability regions and enforces HA-specific engine/release settings. * Disables/hides custom PostgreSQL version selection when High Availability is enabled (and omits HA custom request payloads). * **Bug Fixes** * Improved persistence of selected PostgreSQL version and region across data reloads and configuration panel reopen/toggle. * Restores region when form state temporarily drops values during remounts. * **Tests** * Expanded end-to-end coverage for HA UI, region grouping, and submit/payload restoration behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com> Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
128 lines
4.8 KiB
TypeScript
128 lines
4.8 KiB
TypeScript
import { useEffect, useRef } from 'react'
|
|
import { UseFormReturn } from 'react-hook-form'
|
|
import { type CloudProvider } from 'shared-data'
|
|
import { Badge, FormControl, FormField, Switch, useWatch } from 'ui'
|
|
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
|
|
|
import { CreateProjectForm } from './ProjectCreation.schema'
|
|
import Panel from '@/components/ui/Panel'
|
|
import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements'
|
|
|
|
interface HighAvailabilityInputProps {
|
|
form: UseFormReturn<CreateProjectForm>
|
|
// Derived from an org-wide regions query owned by the parent form, since fetching it
|
|
// here would mean duplicating that query's slug/cloud-provider/instance-size context.
|
|
highAvailabilityRegionName: string | undefined
|
|
}
|
|
|
|
export const HighAvailabilityInput = ({
|
|
form,
|
|
highAvailabilityRegionName,
|
|
}: HighAvailabilityInputProps) => {
|
|
const { getValues, setValue } = form
|
|
const { hasAccess } = useCheckEntitlements('instances.high_availability')
|
|
const highAvailability = useWatch({ control: form.control, name: 'highAvailability' })
|
|
|
|
// Fields to revert to when toggling off HA, so previously selected values aren't lost.
|
|
const beforeHighAvailability = useRef<{
|
|
cloudProvider: CloudProvider | undefined
|
|
postgresVersionSelection: string | undefined
|
|
dbRegion: string | null
|
|
}>({
|
|
cloudProvider: undefined,
|
|
postgresVersionSelection: undefined,
|
|
dbRegion: null,
|
|
})
|
|
|
|
const handleHighAvailabilityChange = (checked: boolean) => {
|
|
if (checked) {
|
|
const currentCloudProvider = getValues('cloudProvider') as CloudProvider
|
|
if (currentCloudProvider !== 'AWS_K8S') {
|
|
beforeHighAvailability.current.cloudProvider = currentCloudProvider
|
|
setValue('cloudProvider', 'AWS_K8S')
|
|
}
|
|
|
|
beforeHighAvailability.current.postgresVersionSelection = getValues(
|
|
'postgresVersionSelection'
|
|
)
|
|
setValue('useOrioleDb', false)
|
|
|
|
const currentRegion = getValues('dbRegion')
|
|
if (
|
|
highAvailabilityRegionName !== undefined &&
|
|
currentRegion !== highAvailabilityRegionName
|
|
) {
|
|
beforeHighAvailability.current.dbRegion = currentRegion ?? null
|
|
setValue('dbRegion', highAvailabilityRegionName)
|
|
}
|
|
} else {
|
|
if (beforeHighAvailability.current.cloudProvider !== undefined) {
|
|
setValue('cloudProvider', beforeHighAvailability.current.cloudProvider)
|
|
beforeHighAvailability.current.cloudProvider = undefined
|
|
}
|
|
|
|
if (beforeHighAvailability.current.postgresVersionSelection !== undefined) {
|
|
setValue(
|
|
'postgresVersionSelection',
|
|
beforeHighAvailability.current.postgresVersionSelection
|
|
)
|
|
beforeHighAvailability.current.postgresVersionSelection = undefined
|
|
}
|
|
|
|
if (beforeHighAvailability.current.dbRegion !== null) {
|
|
setValue('dbRegion', beforeHighAvailability.current.dbRegion)
|
|
beforeHighAvailability.current.dbRegion = null
|
|
}
|
|
}
|
|
}
|
|
|
|
// Catches the case where highAvailabilityRegionName wasn't loaded yet at the moment the
|
|
// toggle fired above (the org's available-regions query for AWS_K8S may still be in
|
|
// flight). The region auto-fill effect in the parent form skips dirty fields, so a
|
|
// manually chosen region would otherwise keep showing in the trigger — force it over
|
|
// explicitly once the HA region becomes known.
|
|
useEffect(() => {
|
|
if (!highAvailability || highAvailabilityRegionName === undefined) return
|
|
const currentRegion = getValues('dbRegion')
|
|
if (currentRegion === highAvailabilityRegionName) return
|
|
if (beforeHighAvailability.current.dbRegion === null) {
|
|
beforeHighAvailability.current.dbRegion = currentRegion ?? null
|
|
}
|
|
setValue('dbRegion', highAvailabilityRegionName)
|
|
}, [highAvailability, highAvailabilityRegionName, getValues, setValue])
|
|
|
|
if (!hasAccess) return null
|
|
|
|
return (
|
|
<Panel.Content>
|
|
<FormField
|
|
control={form.control}
|
|
name="highAvailability"
|
|
render={({ field }) => (
|
|
<FormItemLayout
|
|
label={
|
|
<div className="flex items-center gap-x-2">
|
|
<span>High availability</span>
|
|
<Badge variant="warning">Alpha</Badge>
|
|
</div>
|
|
}
|
|
description="Horizontally scalable Postgres for highly available deployments. Free during Alpha for up to 2 projects."
|
|
layout="horizontal"
|
|
>
|
|
<FormControl>
|
|
<Switch
|
|
aria-label="Enable high availability"
|
|
checked={field.value}
|
|
onCheckedChange={(checked) => {
|
|
handleHighAvailabilityChange(checked)
|
|
field.onChange(checked)
|
|
}}
|
|
/>
|
|
</FormControl>
|
|
</FormItemLayout>
|
|
)}
|
|
/>
|
|
</Panel.Content>
|
|
)
|
|
}
|