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