AutoScaleFields.tsx 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. import { useParams } from 'common'
  2. import { UseFormReturn } from 'react-hook-form'
  3. import {
  4. FormControl,
  5. FormField,
  6. FormInputGroupInput,
  7. InputGroup,
  8. InputGroupAddon,
  9. InputGroupText,
  10. } from 'ui'
  11. import { Admonition } from 'ui-patterns'
  12. import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
  13. import { DiskStorageSchemaType } from '../DiskManagement.schema'
  14. import { DISK_AUTOSCALE_CONFIG_DEFAULTS } from '../ui/DiskManagement.constants'
  15. import { useDiskAutoscaleCustomConfigQuery } from '@/data/config/disk-autoscale-config-query'
  16. type AutoScaleFieldProps = {
  17. form: UseFormReturn<DiskStorageSchemaType>
  18. }
  19. export const AutoScaleFields = ({ form }: AutoScaleFieldProps) => {
  20. const { ref: projectRef } = useParams()
  21. const {
  22. control,
  23. setValue,
  24. formState: { errors },
  25. } = form
  26. const { totalSize, growthPercent, maxSizeGb, minIncrementGb } = form.watch()
  27. const { isError } = useDiskAutoscaleCustomConfigQuery({ projectRef })
  28. const _growthPercent = growthPercent ?? DISK_AUTOSCALE_CONFIG_DEFAULTS.growthPercent
  29. const _minIncrementGb = minIncrementGb ?? DISK_AUTOSCALE_CONFIG_DEFAULTS.minIncrementSize
  30. const _maxSizeGb = errors.maxSizeGb
  31. ? DISK_AUTOSCALE_CONFIG_DEFAULTS.maxSizeGb
  32. : (maxSizeGb ?? DISK_AUTOSCALE_CONFIG_DEFAULTS.maxSizeGb)
  33. const growthSize = Math.floor(totalSize * (_growthPercent / 100))
  34. const autoscaleGrowValue = Math.min(
  35. Math.max(Math.floor((totalSize * _growthPercent) / 100), _minIncrementGb),
  36. 200
  37. )
  38. const totalSizeAfterGrowth = Math.max(autoscaleGrowValue + totalSize, 8)
  39. const formattedTotalSizeAfterGrowth =
  40. totalSizeAfterGrowth < _maxSizeGb ? totalSizeAfterGrowth : _maxSizeGb
  41. const formattedGrowValue = formattedTotalSizeAfterGrowth - totalSize
  42. return (
  43. <>
  44. <FormField
  45. name="growthPercent"
  46. control={control}
  47. render={({ field }) => {
  48. return (
  49. <FormItemLayout
  50. layout="horizontal"
  51. label="Autoscale growth percent"
  52. id={field.name}
  53. labelOptional="Percentage of current disk size to grow"
  54. description={
  55. !errors.growthPercent
  56. ? `This amounts to ${growthSize} GB based on the current disk size of ${totalSize} GB`
  57. : undefined
  58. }
  59. className="[&>div>span]:text-foreground-lighter"
  60. >
  61. <FormControl className="max-w-20">
  62. <InputGroup>
  63. <FormInputGroupInput
  64. {...field}
  65. type="number"
  66. value={field.value ?? undefined}
  67. disabled={isError}
  68. onChange={(e) => {
  69. setValue(
  70. 'growthPercent',
  71. e.target.value === '' ? null : e.target.valueAsNumber,
  72. {
  73. shouldDirty: true,
  74. shouldValidate: true,
  75. }
  76. )
  77. }}
  78. placeholder={String(DISK_AUTOSCALE_CONFIG_DEFAULTS.growthPercent)}
  79. />
  80. <InputGroupAddon align="inline-end">
  81. <InputGroupText>%</InputGroupText>
  82. </InputGroupAddon>
  83. </InputGroup>
  84. </FormControl>
  85. </FormItemLayout>
  86. )
  87. }}
  88. />
  89. <FormField
  90. name="minIncrementGb"
  91. control={control}
  92. render={({ field }) => {
  93. return (
  94. <FormItemLayout
  95. layout="horizontal"
  96. label="Minimum increment"
  97. id={field.name}
  98. labelOptional="Minimum value to autoscale disk size by"
  99. description={
  100. !!minIncrementGb && minIncrementGb > growthSize && !errors.minIncrementGb
  101. ? `This value takes precedence as the minimum increment is larger than the growth percent`
  102. : undefined
  103. }
  104. className="[&>div>span]:text-foreground-lighter"
  105. >
  106. <FormControl className="max-w-32">
  107. <InputGroup>
  108. <FormInputGroupInput
  109. {...field}
  110. type="number"
  111. value={field.value ?? undefined}
  112. disabled={isError}
  113. onChange={(e) => {
  114. setValue(
  115. 'minIncrementGb',
  116. e.target.value === '' ? null : e.target.valueAsNumber,
  117. {
  118. shouldDirty: true,
  119. shouldValidate: true,
  120. }
  121. )
  122. }}
  123. placeholder={String(DISK_AUTOSCALE_CONFIG_DEFAULTS.minIncrementSize)}
  124. />
  125. <InputGroupAddon align="inline-end">
  126. <InputGroupText>GB</InputGroupText>
  127. </InputGroupAddon>
  128. </InputGroup>
  129. </FormControl>
  130. </FormItemLayout>
  131. )
  132. }}
  133. />
  134. <FormField
  135. name="maxSizeGb"
  136. control={control}
  137. render={({ field }) => {
  138. return (
  139. <FormItemLayout
  140. layout="horizontal"
  141. label="Maximum disk size"
  142. id={field.name}
  143. labelOptional="Maximum size that the disk can grow to"
  144. className="[&>div>span]:text-foreground-lighter"
  145. >
  146. <FormControl className="max-w-32">
  147. <InputGroup>
  148. <FormInputGroupInput
  149. {...field}
  150. type="number"
  151. value={field.value ?? undefined}
  152. disabled={isError}
  153. onChange={(e) => {
  154. setValue('maxSizeGb', e.target.value === '' ? null : e.target.valueAsNumber, {
  155. shouldDirty: true,
  156. shouldValidate: true,
  157. })
  158. }}
  159. placeholder={String(DISK_AUTOSCALE_CONFIG_DEFAULTS.maxSizeGb)}
  160. />
  161. <InputGroupAddon align="inline-end">
  162. <InputGroupText>GB</InputGroupText>
  163. </InputGroupAddon>
  164. </InputGroup>
  165. </FormControl>
  166. </FormItemLayout>
  167. )
  168. }}
  169. />
  170. {
  171. <Admonition type="default" showIcon={false} className="[&>div]:text-foreground-light">
  172. Disk size will automatically be expanded by{' '}
  173. <span className="text-foreground">
  174. {String(formattedGrowValue).length > 4
  175. ? formattedGrowValue.toFixed(2)
  176. : formattedGrowValue}{' '}
  177. GB
  178. </span>{' '}
  179. to a total of <span className="text-foreground">{formattedTotalSizeAfterGrowth} GB</span>{' '}
  180. when the database reaches 90% of the disk size
  181. </Admonition>
  182. }
  183. </>
  184. )
  185. }