PostgresVersionSelector.tsx 4.9 KB

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