mirror of
https://github.com/supabase/supabase.git
synced 2026-10-15 14:19:11 +03:00
This pull request enhances the project creation flow by introducing support for filtering Postgres versions based on the OrioleDB engine. The main changes involve updating the `PostgresVersionSelector` component to allow filtering for OrioleDB-specific versions, and integrating this logic into the internal-only configuration step of project creation. This provides a clearer and more flexible experience when selecting Postgres versions, especially for internal or advanced users. **Postgres Version Selection Enhancements:** * Added a new `useOrioleDbForCreate` prop to `PostgresVersionSelector`, allowing the component to filter available Postgres versions to only OrioleDB-based options or exclude them, based on user selection. The prop defaults to `undefined` for no filtering. [[1]](diffhunk://#diff-1842d78cb2a4be2c2b6e1581981d8111304fd9aaf0ad45df273d8c001938bcd9R41-R50) [[2]](diffhunk://#diff-1842d78cb2a4be2c2b6e1581981d8111304fd9aaf0ad45df273d8c001938bcd9R82-R85) [[3]](diffhunk://#diff-1842d78cb2a4be2c2b6e1581981d8111304fd9aaf0ad45df273d8c001938bcd9L92-R114) * Added a `description` prop to `PostgresVersionSelector` for improved UI guidance, and passed this prop through the form. [[1]](diffhunk://#diff-1842d78cb2a4be2c2b6e1581981d8111304fd9aaf0ad45df273d8c001938bcd9R41-R50) [[2]](diffhunk://#diff-1842d78cb2a4be2c2b6e1581981d8111304fd9aaf0ad45df273d8c001938bcd9R82-R85) [[3]](diffhunk://#diff-1842d78cb2a4be2c2b6e1581981d8111304fd9aaf0ad45df273d8c001938bcd9L139-R161) **Integration with Project Creation Flow:** * Updated `InternalOnlyConfiguration` to watch the `useOrioleDb` form field and pass its value to `PostgresVersionSelector`, ensuring the version list is filtered appropriately during project creation. Also, conditionally set the description to guide users toward advanced configuration for OrioleDB. [[1]](diffhunk://#diff-f0fa51a1cc67bb1a2c38d2c595eb3cab3a45813a027a04942d684914f2c3de93R33) [[2]](diffhunk://#diff-f0fa51a1cc67bb1a2c38d2c595eb3cab3a45813a027a04942d684914f2c3de93R60-R65) * Adjusted the render order in `ProjectCreationForm` to ensure advanced configuration and internal-only configuration are displayed in a logical sequence. **Other Improvements:** * Imported the `isSuccess` utility from `effect/Result` in `PostgresVersionSelector.tsx` to support the updated logic. --------- Co-authored-by: Alaister Young <alaister@users.noreply.github.com> Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
194 lines
6.6 KiB
TypeScript
194 lines
6.6 KiB
TypeScript
import { useEffect } from 'react'
|
|
import { ControllerRenderProps, UseFormReturn, useWatch } from 'react-hook-form'
|
|
import type { CloudProvider } from 'shared-data'
|
|
import {
|
|
Badge,
|
|
Select,
|
|
SelectContent,
|
|
SelectGroup,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from 'ui'
|
|
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
|
|
|
import { smartRegionToExactRegion } from './ProjectCreation.utils'
|
|
import { useProjectCreationPostgresVersionsQuery } from '@/data/config/project-creation-postgres-versions-query'
|
|
import { useProjectUnpausePostgresVersionsQuery } from '@/data/config/project-unpause-postgres-versions-query'
|
|
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
|
|
|
|
interface PostgresVersionSelectorProps {
|
|
cloudProvider: CloudProvider
|
|
dbRegion: string
|
|
disabled?: boolean
|
|
organizationSlug?: string
|
|
highAvailability?: boolean
|
|
field: ControllerRenderProps<any, 'postgresVersionSelection'>
|
|
form: UseFormReturn<any>
|
|
/**
|
|
* Owned by the form owner (not this component) so the last valid selection
|
|
* survives this selector unmounting, e.g. when its collapsible section
|
|
* closes. Create it with useRef('') alongside the form.
|
|
*/
|
|
lastValidSelectionRef: { current: string }
|
|
/**
|
|
* Used when creating a project. If true, it will filter all versions to only OrioleDB versions (or exclude them if false).
|
|
*
|
|
* Defaults to undefined, which is not filtering.
|
|
*/
|
|
useOrioleDbForCreate?: boolean
|
|
type?: 'create' | 'unpause'
|
|
layout?: 'vertical' | 'horizontal'
|
|
label?: string
|
|
description?: string
|
|
}
|
|
|
|
const formatValue = ({
|
|
postgres_engine,
|
|
release_channel,
|
|
}: {
|
|
postgres_engine: string
|
|
release_channel: string
|
|
}) => {
|
|
return `${postgres_engine}|${release_channel}`
|
|
}
|
|
|
|
export const PostgresVersionSelector = ({
|
|
cloudProvider,
|
|
dbRegion,
|
|
disabled = false,
|
|
organizationSlug,
|
|
highAvailability,
|
|
field,
|
|
form,
|
|
lastValidSelectionRef,
|
|
type = 'create',
|
|
useOrioleDbForCreate = undefined,
|
|
layout = 'horizontal',
|
|
label = 'Postgres version',
|
|
description,
|
|
}: PostgresVersionSelectorProps) => {
|
|
const { data: project } = useSelectedProjectQuery()
|
|
|
|
const dbRegionExact = smartRegionToExactRegion(dbRegion)
|
|
|
|
const {
|
|
data: createVersions,
|
|
isPending: isLoadingProjectCreateVersions,
|
|
isSuccess,
|
|
} = useProjectCreationPostgresVersionsQuery(
|
|
{
|
|
cloudProvider,
|
|
dbRegion: dbRegionExact,
|
|
organizationSlug,
|
|
highAvailability,
|
|
},
|
|
{
|
|
enabled: type === 'create',
|
|
select: (data) => {
|
|
if (useOrioleDbForCreate === undefined) return data
|
|
return {
|
|
available_versions: data?.available_versions.filter((version) =>
|
|
useOrioleDbForCreate
|
|
? version.postgres_engine.endsWith('oriole')
|
|
: !version.postgres_engine.endsWith('oriole')
|
|
),
|
|
}
|
|
},
|
|
}
|
|
)
|
|
|
|
const { data: unpauseVersions, isPending: isLoadingProjectUnpauseVersions } =
|
|
useProjectUnpausePostgresVersionsQuery(
|
|
{ projectRef: project?.ref },
|
|
{ enabled: type === 'unpause' }
|
|
)
|
|
|
|
const versions =
|
|
type === 'create'
|
|
? (createVersions?.available_versions ?? [])
|
|
: (unpauseVersions?.available_versions ?? [])
|
|
const availableVersions = versions.sort((a, b) => a.version.localeCompare(b.version)).reverse()
|
|
const postgresVersionSelection = useWatch({
|
|
control: form.control,
|
|
name: 'postgresVersionSelection',
|
|
})
|
|
|
|
// react-hook-form intermittently drops this field's value when its Controller
|
|
// remounts, so a one-shot "set the default once versions load" effect leaves
|
|
// the select stuck empty. Instead this effect re-asserts off the watched value:
|
|
// a selection present in the current list is kept (and remembered in the
|
|
// owner-held lastValidSelectionRef), and when the value is missing or cleared
|
|
// out from under us it restores the last valid selection, falling back to the
|
|
// GA default.
|
|
useEffect(() => {
|
|
if (availableVersions.length === 0) return
|
|
const isSelectionAvailable = (selection: string) =>
|
|
availableVersions.some((version) => formatValue(version) === selection)
|
|
|
|
if (postgresVersionSelection && isSelectionAvailable(postgresVersionSelection)) {
|
|
lastValidSelectionRef.current = postgresVersionSelection
|
|
return
|
|
}
|
|
|
|
if (isSelectionAvailable(lastValidSelectionRef.current)) {
|
|
form.setValue('postgresVersionSelection', lastValidSelectionRef.current)
|
|
return
|
|
}
|
|
|
|
const gaVersion = availableVersions.find((x) => x.release_channel === 'ga')
|
|
const defaultValue = gaVersion ? formatValue(gaVersion) : formatValue(availableVersions[0])
|
|
form.setValue('postgresVersionSelection', defaultValue)
|
|
}, [isSuccess, availableVersions, postgresVersionSelection, lastValidSelectionRef, form])
|
|
|
|
return (
|
|
<FormItemLayout id={field.name} label={label} layout={layout} description={description}>
|
|
<Select
|
|
value={postgresVersionSelection}
|
|
onValueChange={field.onChange}
|
|
disabled={
|
|
disabled ||
|
|
availableVersions.length === 0 ||
|
|
(type === 'create' && isLoadingProjectCreateVersions) ||
|
|
(type === 'unpause' && isLoadingProjectUnpauseVersions)
|
|
}
|
|
>
|
|
<SelectTrigger
|
|
id={field.name}
|
|
className="[&>:nth-child(1)]:w-full [&>:nth-child(1)]:flex [&>:nth-child(1)]:items-start"
|
|
>
|
|
<SelectValue placeholder="Select a Postgres version for your project" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectGroup>
|
|
{availableVersions.map((value) => {
|
|
const postgresVersion = value.version
|
|
.split('supabase-postgres-')[1]
|
|
.replace('-orioledb', '')
|
|
return (
|
|
<SelectItem
|
|
key={formatValue(value)}
|
|
value={formatValue(value)}
|
|
className="w-full [&>:nth-child(2)]:w-full"
|
|
>
|
|
<div className="flex flex-row items-center justify-between w-full">
|
|
<span className="text-foreground">{postgresVersion}</span>
|
|
<div className="flex flex-row gap-x-2">
|
|
{value.release_channel !== 'ga' && (
|
|
<Badge variant="warning">{value.release_channel}</Badge>
|
|
)}
|
|
{value.postgres_engine.includes('oriole') && (
|
|
<Badge variant="default">OrioleDB</Badge>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</SelectItem>
|
|
)
|
|
})}
|
|
</SelectGroup>
|
|
</SelectContent>
|
|
</Select>
|
|
</FormItemLayout>
|
|
)
|
|
}
|