PostgresVersionSelector.tsx149 lines · main
| 1 | import { useEffect } from 'react' |
| 2 | import { ControllerRenderProps, UseFormReturn } from 'react-hook-form' |
| 3 | import type { CloudProvider } from 'shared-data' |
| 4 | import { |
| 5 | Badge, |
| 6 | Select, |
| 7 | SelectContent, |
| 8 | SelectGroup, |
| 9 | SelectItem, |
| 10 | SelectTrigger, |
| 11 | SelectValue, |
| 12 | } from 'ui' |
| 13 | import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' |
| 14 | |
| 15 | import { smartRegionToExactRegion } from './ProjectCreation.utils' |
| 16 | import { useProjectCreationPostgresVersionsQuery } from '@/data/config/project-creation-postgres-versions-query' |
| 17 | import { useProjectUnpausePostgresVersionsQuery } from '@/data/config/project-unpause-postgres-versions-query' |
| 18 | import { PostgresEngine, ReleaseChannel } from '@/data/projects/new-project.constants' |
| 19 | import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' |
| 20 | |
| 21 | interface PostgresVersionDetails { |
| 22 | postgresEngine?: Exclude<PostgresEngine, '13' | '14'> |
| 23 | releaseChannel?: ReleaseChannel |
| 24 | } |
| 25 | |
| 26 | interface PostgresVersionSelectorProps { |
| 27 | cloudProvider: CloudProvider |
| 28 | dbRegion: string |
| 29 | organizationSlug?: string |
| 30 | field: ControllerRenderProps<any, 'postgresVersionSelection'> |
| 31 | form: UseFormReturn<any> |
| 32 | type?: 'create' | 'unpause' |
| 33 | layout?: 'vertical' | 'horizontal' |
| 34 | label?: string |
| 35 | } |
| 36 | |
| 37 | const formatValue = ({ |
| 38 | postgres_engine, |
| 39 | release_channel, |
| 40 | }: { |
| 41 | postgres_engine: string |
| 42 | release_channel: string |
| 43 | }) => { |
| 44 | return `${postgres_engine}|${release_channel}` |
| 45 | } |
| 46 | |
| 47 | export const extractPostgresVersionDetails = (value: string): PostgresVersionDetails => { |
| 48 | if (!value) { |
| 49 | return { postgresEngine: undefined, releaseChannel: undefined } |
| 50 | } |
| 51 | |
| 52 | const [postgresEngine, releaseChannel] = value.split('|') |
| 53 | return { postgresEngine, releaseChannel } as PostgresVersionDetails |
| 54 | } |
| 55 | |
| 56 | export const PostgresVersionSelector = ({ |
| 57 | cloudProvider, |
| 58 | dbRegion, |
| 59 | organizationSlug, |
| 60 | field, |
| 61 | form, |
| 62 | type = 'create', |
| 63 | layout = 'horizontal', |
| 64 | label = 'Postgres version', |
| 65 | }: PostgresVersionSelectorProps) => { |
| 66 | const { data: project } = useSelectedProjectQuery() |
| 67 | |
| 68 | const dbRegionExact = smartRegionToExactRegion(dbRegion) |
| 69 | |
| 70 | const { |
| 71 | data: createVersions, |
| 72 | isPending: isLoadingProjectCreateVersions, |
| 73 | isSuccess, |
| 74 | } = useProjectCreationPostgresVersionsQuery( |
| 75 | { |
| 76 | cloudProvider, |
| 77 | dbRegion: dbRegionExact, |
| 78 | organizationSlug, |
| 79 | }, |
| 80 | { enabled: type === 'create' } |
| 81 | ) |
| 82 | |
| 83 | const { data: unpauseVersions, isPending: isLoadingProjectUnpauseVersions } = |
| 84 | useProjectUnpausePostgresVersionsQuery( |
| 85 | { projectRef: project?.ref }, |
| 86 | { enabled: type === 'unpause' } |
| 87 | ) |
| 88 | |
| 89 | const versions = |
| 90 | type === 'create' |
| 91 | ? (createVersions?.available_versions ?? []) |
| 92 | : (unpauseVersions?.available_versions ?? []) |
| 93 | const availableVersions = versions.sort((a, b) => a.version.localeCompare(b.version)).reverse() |
| 94 | const { postgresVersionSelection } = form.watch() |
| 95 | |
| 96 | useEffect(() => { |
| 97 | if (availableVersions.length > 0) { |
| 98 | const gaVersion = availableVersions.find((x) => x.release_channel === 'ga') |
| 99 | const defaultValue = gaVersion ? formatValue(gaVersion) : formatValue(availableVersions[0]) |
| 100 | form.setValue('postgresVersionSelection', defaultValue) |
| 101 | } |
| 102 | }, [isSuccess, availableVersions, form]) |
| 103 | |
| 104 | return ( |
| 105 | <FormItemLayout label={label} layout={layout}> |
| 106 | <Select |
| 107 | value={postgresVersionSelection} |
| 108 | onValueChange={field.onChange} |
| 109 | disabled={ |
| 110 | availableVersions.length === 0 || |
| 111 | (type === 'create' && isLoadingProjectCreateVersions) || |
| 112 | (type === 'unpause' && isLoadingProjectUnpauseVersions) |
| 113 | } |
| 114 | > |
| 115 | <SelectTrigger className="[&>:nth-child(1)]:w-full [&>:nth-child(1)]:flex [&>:nth-child(1)]:items-start"> |
| 116 | <SelectValue placeholder="Select a Postgres version for your project" /> |
| 117 | </SelectTrigger> |
| 118 | <SelectContent> |
| 119 | <SelectGroup> |
| 120 | {availableVersions.map((value) => { |
| 121 | const postgresVersion = value.version |
| 122 | .split('briven-postgres-')[1] |
| 123 | .replace('-orioledb', '') |
| 124 | return ( |
| 125 | <SelectItem |
| 126 | key={formatValue(value)} |
| 127 | value={formatValue(value)} |
| 128 | className="w-full [&>:nth-child(2)]:w-full" |
| 129 | > |
| 130 | <div className="flex flex-row items-center justify-between w-full"> |
| 131 | <span className="text-foreground">{postgresVersion}</span> |
| 132 | <div className="flex flex-row gap-x-2"> |
| 133 | {value.release_channel !== 'ga' && ( |
| 134 | <Badge variant="warning">{value.release_channel}</Badge> |
| 135 | )} |
| 136 | {value.postgres_engine.includes('oriole') && ( |
| 137 | <Badge variant="default">OrioleDB</Badge> |
| 138 | )} |
| 139 | </div> |
| 140 | </div> |
| 141 | </SelectItem> |
| 142 | ) |
| 143 | })} |
| 144 | </SelectGroup> |
| 145 | </SelectContent> |
| 146 | </Select> |
| 147 | </FormItemLayout> |
| 148 | ) |
| 149 | } |