mirror of
https://github.com/supabase/supabase.git
synced 2026-10-17 07:09:07 +03:00
inline errors
This commit is contained in:
1 parent
cd2b4bc6e6
commit
b85dda5e69
10 files changed
+166
-102
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { useParams } from 'common'
|
||||
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
|
||||
import { MAX_WIDTH_CLASSES, PADDING_CLASSES, ScaffoldContainer } from 'components/layouts/Scaffold'
|
||||
@@ -9,14 +10,15 @@ import {
|
||||
} from 'data/config/disk-attributes-query'
|
||||
import { useUpdateDiskAttributesMutation } from 'data/config/disk-attributes-update-mutation'
|
||||
import { useDiskUtilizationQuery } from 'data/config/disk-utilization-query'
|
||||
import { setProjectStatus } from 'data/projects/projects-query'
|
||||
import { useReadReplicasQuery } from 'data/read-replicas/replicas-query'
|
||||
import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query'
|
||||
import { useProjectAddonUpdateMutation } from 'data/subscriptions/project-addon-update-mutation'
|
||||
import { useProjectAddonsQuery } from 'data/subscriptions/project-addons-query'
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
|
||||
import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization'
|
||||
import { useFlag } from 'hooks/ui/useFlag'
|
||||
import { PROJECT_STATUS } from 'lib/constants'
|
||||
import { ChevronRight } from 'lucide-react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
@@ -32,7 +34,7 @@ import {
|
||||
} from 'ui'
|
||||
import { FormFooterChangeBadge } from '../DataWarehouse/FormFooterChangeBadge'
|
||||
import { CreateDiskStorageSchema, DiskStorageSchemaType } from './DiskManagement.schema'
|
||||
import { formatComputeName } from './DiskManagement.utils'
|
||||
import { DiskMangementRestartRequiredSection } from './DiskManagementRestartRequiredSection'
|
||||
import { DiskManagementReviewAndSubmitDialog } from './DiskManagementReviewAndSubmitDialog'
|
||||
import { ComputeSizeField } from './fields/ComputeSizeField'
|
||||
import { DiskSizeField } from './fields/DiskSizeField'
|
||||
@@ -47,10 +49,6 @@ import {
|
||||
} from './ui/DiskManagement.constants'
|
||||
import { DiskManagementPlanUpgradeRequired } from './ui/DiskManagementPlanUpgradeRequired'
|
||||
import { NoticeBar } from './ui/NoticeBar'
|
||||
import { DiskMangementRestartRequiredSection } from './DiskManagementRestartRequiredSection'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { PROJECT_STATUS } from 'lib/constants'
|
||||
import { setProjectStatus } from 'data/projects/projects-query'
|
||||
|
||||
export function DiskManagementForm() {
|
||||
const { project } = useProjectContext()
|
||||
@@ -63,8 +61,12 @@ export function DiskManagementForm() {
|
||||
message: string
|
||||
type: 'error' | 'success'
|
||||
} | null>(null)
|
||||
const [showRestartPending, setShowRestartPendingState] = useState(false)
|
||||
const [advancedSettingsOpen, setAdvancedSettingsOpenState] = useState(false)
|
||||
|
||||
/**
|
||||
* Permissions
|
||||
*/
|
||||
const isPermissionsLoaded = usePermissionsLoaded()
|
||||
const canUpdateDiskConfiguration = useCheckPermissions(PermissionAction.UPDATE, 'projects', {
|
||||
resource: {
|
||||
project_id: project?.id,
|
||||
@@ -208,6 +210,11 @@ export function DiskManagementForm() {
|
||||
}
|
||||
}, [isSuccess])
|
||||
|
||||
const isDirty = !!Object.keys(form.formState.dirtyFields).length
|
||||
const isProjectResizing = project?.status === PROJECT_STATUS.RESIZING
|
||||
const isProjectRequestingDiskChanges = isRequestingChanges && !isProjectResizing
|
||||
const noPermissions = isPermissionsLoaded && !canUpdateDiskConfiguration
|
||||
|
||||
const { mutateAsync: updateDiskConfiguration, isLoading: isUpdatingDisk } =
|
||||
useUpdateDiskAttributesMutation({})
|
||||
const { mutateAsync: updateSubscriptionAddon, isLoading: isUpdatingCompute } =
|
||||
@@ -298,13 +305,9 @@ export function DiskManagementForm() {
|
||||
|
||||
// return <></>
|
||||
|
||||
const isDirty = !!Object.keys(form.formState.dirtyFields).length
|
||||
const isProjectResizing = project?.status === PROJECT_STATUS.RESIZING
|
||||
const isProjectRequestingDiskChanges = isRequestingChanges && !isProjectResizing
|
||||
|
||||
return (
|
||||
<>
|
||||
{isProjectResizing || isProjectRequestingDiskChanges ? (
|
||||
{isProjectResizing || isProjectRequestingDiskChanges || noPermissions ? (
|
||||
<ScaffoldContainer className="relative flex flex-col gap-10" bottomPadding>
|
||||
<DiskMangementRestartRequiredSection
|
||||
visible={isProjectResizing}
|
||||
@@ -316,6 +319,11 @@ export function DiskManagementForm() {
|
||||
title="Disk configuration changes have been requested"
|
||||
description="The requested changes will be applied to your disk shortly"
|
||||
/>
|
||||
<NoticeBar
|
||||
visible={noPermissions}
|
||||
title="You do not have permission to update disk configuration"
|
||||
description="Please contact your organization administrator to update your disk configuration"
|
||||
/>
|
||||
</ScaffoldContainer>
|
||||
) : null}
|
||||
<Form_Shadcn_ {...form}>
|
||||
@@ -331,7 +339,8 @@ export function DiskManagementForm() {
|
||||
<Collapsible_Shadcn_
|
||||
// TO DO: wrap component into pattern
|
||||
className="-space-y-px"
|
||||
open={advancedSettingsOpen}
|
||||
// open={advancedSettingsOpen}
|
||||
defaultOpen
|
||||
onOpenChange={() => setAdvancedSettingsOpenState((prev) => !prev)}
|
||||
>
|
||||
<CollapsibleTrigger_Shadcn_ className="px-8 py-3 w-full border flex items-center gap-6 rounded-t data-[state=closed]:rounded-b group justify-between">
|
||||
@@ -382,6 +391,7 @@ export function DiskManagementForm() {
|
||||
</Button>
|
||||
<DiskManagementReviewAndSubmitDialog
|
||||
loading={isUpdatingConfig}
|
||||
disabled={noPermissions}
|
||||
form={form}
|
||||
numReplicas={readReplicas.length}
|
||||
isDialogOpen={isDialogOpen}
|
||||
|
||||
@@ -686,13 +686,7 @@ export function DiskManagementPanelForm() {
|
||||
{/* Additional content or information can go here */}
|
||||
</div>
|
||||
<div className="col-span-8 space-y-6 mt-6">
|
||||
<DiskSpaceBar
|
||||
form={form}
|
||||
// showNewBar={form.formState.dirtyFields.totalSize !== undefined}
|
||||
// totalSize={size_gb}
|
||||
// usedSize={mainDiskUsed}
|
||||
// newTotalSize={watchedTotalSize}
|
||||
/>
|
||||
<DiskSpaceBar form={form} />
|
||||
<DiskManagementDiskSizeReadReplicas
|
||||
isDirty={form.formState.dirtyFields.totalSize !== undefined}
|
||||
totalSize={size_gb * 1.25}
|
||||
|
||||
@@ -12,6 +12,7 @@ import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
import { BillingChangeBadge } from '../ui/BillingChangeBadge'
|
||||
import { calculateComputeSizePrice, getAvailableComputeOptions } from '../DiskManagement.utils'
|
||||
import { DiskStorageSchemaType } from '../DiskManagement.schema'
|
||||
import FormMessage from '../ui/FormMessage'
|
||||
|
||||
type ComputeOption = {
|
||||
identifier: components['schemas']['AddonVariantId']
|
||||
@@ -37,7 +38,6 @@ export function ComputeSizeField({ form }: ComputeSizeFieldProps) {
|
||||
data: addons,
|
||||
isLoading: isAddonsLoading,
|
||||
error: addonsError,
|
||||
isSuccess: isAddonsSuccess,
|
||||
} = useProjectAddonsQuery({ projectRef: ref })
|
||||
|
||||
const availableAddons = useMemo(() => {
|
||||
@@ -81,7 +81,7 @@ export function ComputeSizeField({ form }: ComputeSizeFieldProps) {
|
||||
}
|
||||
>
|
||||
<RadioGroupCard
|
||||
className="grid grid-cols-2 xl:grid-cols-3 flex-wrap gap-3"
|
||||
className={!addonsError ? 'grid grid-cols-2 xl:grid-cols-3 flex-wrap gap-3' : ''}
|
||||
onValueChange={(value: components['schemas']['AddonVariantId']) => {
|
||||
setValue('computeSize', value, {
|
||||
shouldDirty: true,
|
||||
@@ -99,7 +99,7 @@ export function ComputeSizeField({ form }: ComputeSizeFieldProps) {
|
||||
.fill(0)
|
||||
.map((_, i) => <Skeleton key={i} className="w-full h-[110px] rounded-md" />)
|
||||
) : addonsError ? (
|
||||
<p>Error loading compute options</p>
|
||||
<FormMessage message={addonsError?.message} type="error" />
|
||||
) : (
|
||||
availableOptions.map((compute: ComputeOption) => {
|
||||
// @ts-expect-error
|
||||
|
||||
@@ -16,6 +16,7 @@ import DiskSpaceBar from '../ui/DiskSpaceBar'
|
||||
import { InputPostTab } from '../ui/InputPostTab'
|
||||
import { InputResetButton } from '../ui/InputResetButton'
|
||||
import FormMessage from '../ui/FormMessage'
|
||||
import { useDiskAttributesQuery } from 'data/config/disk-attributes-query'
|
||||
|
||||
type DiskSizeFieldProps = {
|
||||
form: UseFormReturn<DiskStorageSchemaType>
|
||||
@@ -27,10 +28,16 @@ export function DiskSizeField({ form, disableInput }: DiskSizeFieldProps) {
|
||||
const { control, formState, setValue, trigger, getValues, resetField, watch } = form
|
||||
const org = useSelectedOrganization()
|
||||
|
||||
const {
|
||||
isLoading: isLoadingDiskAttributes,
|
||||
error: diskAttributesError,
|
||||
isError: isDiskAttributesError,
|
||||
} = useDiskAttributesQuery({ projectRef })
|
||||
const {
|
||||
data: subscription,
|
||||
isLoading: isSubscriptionLoading,
|
||||
error: subscriptionError,
|
||||
isError: isSubscriptionError,
|
||||
} = useOrgSubscriptionQuery({
|
||||
orgSlug: org?.slug,
|
||||
})
|
||||
@@ -38,12 +45,14 @@ export function DiskSizeField({ form, disableInput }: DiskSizeFieldProps) {
|
||||
data: diskUtil,
|
||||
isLoading: isDiskUtilizationLoading,
|
||||
error: diskUtilError,
|
||||
isError: isDiskUtilizationError,
|
||||
} = useDiskUtilizationQuery({
|
||||
projectRef: projectRef,
|
||||
})
|
||||
|
||||
const isLoading = isSubscriptionLoading || isDiskUtilizationLoading
|
||||
const error = subscriptionError || diskUtilError
|
||||
const isLoading = isSubscriptionLoading || isDiskUtilizationLoading || isLoadingDiskAttributes
|
||||
const error = subscriptionError || diskUtilError || diskAttributesError
|
||||
const isError = isSubscriptionError || isDiskUtilizationError || isDiskAttributesError
|
||||
|
||||
const watchedStorageType = watch('storageType')
|
||||
const watchedTotalSize = watch('totalSize')
|
||||
@@ -73,7 +82,6 @@ export function DiskSizeField({ form, disableInput }: DiskSizeFieldProps) {
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<FormItemLayout label="Disk Size" layout="vertical">
|
||||
{error && <FormMessage message={error?.message} type="error" />}
|
||||
<div className="relative flex gap-2 items-center">
|
||||
<InputPostTab label="GB">
|
||||
{isLoading ? (
|
||||
@@ -90,7 +98,7 @@ export function DiskSizeField({ form, disableInput }: DiskSizeFieldProps) {
|
||||
<Input_Shadcn_
|
||||
type="number"
|
||||
{...field}
|
||||
disabled={disableInput}
|
||||
disabled={disableInput || isError}
|
||||
className="w-32 font-mono rounded-r-none"
|
||||
onWheel={(e) => e.currentTarget.blur()}
|
||||
onChange={(e) => {
|
||||
@@ -136,13 +144,8 @@ export function DiskSizeField({ form, disableInput }: DiskSizeFieldProps) {
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-8">
|
||||
<DiskSpaceBar
|
||||
form={form}
|
||||
// showNewBar={formState.dirtyFields.totalSize !== undefined}
|
||||
// totalSize={formState.defaultValues?.totalSize || 0}
|
||||
// usedSize={mainDiskUsed}
|
||||
// newTotalSize={watchedTotalSize}
|
||||
/>
|
||||
<DiskSpaceBar form={form} />
|
||||
{error && <FormMessage message={error?.message} type="error" />}
|
||||
<DiskManagementDiskSizeReadReplicas
|
||||
isDirty={formState.dirtyFields.totalSize !== undefined}
|
||||
totalSize={(formState.defaultValues?.totalSize || 0) * 1.25}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { components } from 'api-types'
|
||||
import { UseFormReturn } from 'react-hook-form'
|
||||
import { Button, FormControl_Shadcn_, FormField_Shadcn_, Input_Shadcn_ } from 'ui'
|
||||
import { Button, cn, FormControl_Shadcn_, FormField_Shadcn_, Input_Shadcn_, Skeleton } from 'ui'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
import { BillingChangeBadge } from '../ui/BillingChangeBadge'
|
||||
import { ComputeSizeReccomendationSection } from '../ui/ComputeSizeReccomendationSection'
|
||||
@@ -14,6 +14,10 @@ import { calculateComputeSizeRequiredForIops, calculateIOPSPrice } from '../Disk
|
||||
import { DiskStorageSchemaType } from '../DiskManagement.schema'
|
||||
import { DiskManagementIOPSReadReplicas } from '../ui/DiskManagementReadReplicas'
|
||||
import { InputPostTab } from '../ui/InputPostTab'
|
||||
import { useDiskAttributesQuery } from 'data/config/disk-attributes-query'
|
||||
import { useParams } from 'common'
|
||||
import { InputVariants } from '@ui/components/shadcn/ui/input'
|
||||
import FormMessage from '../ui/FormMessage'
|
||||
|
||||
type IOPSFieldProps = {
|
||||
form: UseFormReturn<DiskStorageSchemaType>
|
||||
@@ -21,12 +25,15 @@ type IOPSFieldProps = {
|
||||
}
|
||||
|
||||
export function IOPSField({ form, disableInput }: IOPSFieldProps) {
|
||||
const { ref: projectRef } = useParams()
|
||||
const { control, formState, setValue, trigger, getValues, watch } = form
|
||||
|
||||
const watchedStorageType = watch('storageType')
|
||||
const watchedComputeSize = watch('computeSize')
|
||||
const watchedIOPS = watch('provisionedIOPS') ?? 0
|
||||
|
||||
const { isLoading, error, isError } = useDiskAttributesQuery({ projectRef })
|
||||
|
||||
const iopsPrice = calculateIOPSPrice({
|
||||
oldStorageType: formState.defaultValues?.storageType as DiskType,
|
||||
oldProvisionedIOPS: formState.defaultValues?.provisionedIOPS || 0,
|
||||
@@ -47,8 +54,9 @@ export function IOPSField({ form, disableInput }: IOPSFieldProps) {
|
||||
<FormItemLayout
|
||||
layout="horizontal"
|
||||
label="IOPS"
|
||||
id={field.name}
|
||||
description={
|
||||
<div className="flex flex-col gap-y-2">
|
||||
<span className="flex flex-col gap-y-2">
|
||||
<ComputeSizeReccomendationSection
|
||||
computeSize={watchedComputeSize}
|
||||
iops={watchedIOPS}
|
||||
@@ -76,7 +84,7 @@ export function IOPSField({ form, disableInput }: IOPSFieldProps) {
|
||||
newStorageType={getValues('storageType') as DiskType}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</span>
|
||||
}
|
||||
labelOptional={
|
||||
<>
|
||||
@@ -98,29 +106,37 @@ export function IOPSField({ form, disableInput }: IOPSFieldProps) {
|
||||
}
|
||||
>
|
||||
<InputPostTab label="IOPS">
|
||||
<FormControl_Shadcn_>
|
||||
<Input_Shadcn_
|
||||
id="provisionedIOPS"
|
||||
type="number"
|
||||
className="flex-grow font-mono rounded-r-none max-w-32"
|
||||
{...field}
|
||||
value={
|
||||
disableIopsInput
|
||||
? COMPUTE_BASELINE_IOPS[
|
||||
watchedComputeSize as keyof typeof COMPUTE_BASELINE_IOPS
|
||||
]
|
||||
: field.value
|
||||
}
|
||||
disabled={disableInput || disableIopsInput}
|
||||
onChange={(e) => {
|
||||
setValue('provisionedIOPS', e.target.valueAsNumber, {
|
||||
shouldDirty: true,
|
||||
shouldValidate: true,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</FormControl_Shadcn_>
|
||||
{isLoading ? (
|
||||
<div
|
||||
className={cn(InputVariants({ size: 'small' }), 'w-32 font-mono rounded-r-none')}
|
||||
>
|
||||
<Skeleton className="w-10 h-4" />
|
||||
</div>
|
||||
) : (
|
||||
<FormControl_Shadcn_>
|
||||
<Input_Shadcn_
|
||||
type="number"
|
||||
className="flex-grow font-mono rounded-r-none max-w-32"
|
||||
{...field}
|
||||
value={
|
||||
disableIopsInput
|
||||
? COMPUTE_BASELINE_IOPS[
|
||||
watchedComputeSize as keyof typeof COMPUTE_BASELINE_IOPS
|
||||
]
|
||||
: field.value
|
||||
}
|
||||
disabled={disableInput || disableIopsInput || isError}
|
||||
onChange={(e) => {
|
||||
setValue('provisionedIOPS', e.target.valueAsNumber, {
|
||||
shouldDirty: true,
|
||||
shouldValidate: true,
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</FormControl_Shadcn_>
|
||||
)}
|
||||
</InputPostTab>
|
||||
{error && <FormMessage type="error" message={error.message} />}
|
||||
</FormItemLayout>
|
||||
)
|
||||
}}
|
||||
|
||||
@@ -1,16 +1,23 @@
|
||||
import { FormField_Shadcn_, FormControl_Shadcn_ } from 'ui'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
import { useParams } from 'common'
|
||||
import { useDiskAttributesQuery } from 'data/config/disk-attributes-query'
|
||||
import { UseFormReturn } from 'react-hook-form'
|
||||
import {
|
||||
Badge,
|
||||
FormControl_Shadcn_,
|
||||
FormField_Shadcn_,
|
||||
Select_Shadcn_,
|
||||
SelectTrigger_Shadcn_,
|
||||
SelectValue_Shadcn_,
|
||||
SelectContent_Shadcn_,
|
||||
SelectItem_Shadcn_,
|
||||
SelectTrigger_Shadcn_,
|
||||
SelectValue_Shadcn_,
|
||||
Skeleton,
|
||||
buttonVariants,
|
||||
cn,
|
||||
} from 'ui'
|
||||
import { Badge } from 'ui'
|
||||
import { UseFormReturn } from 'react-hook-form'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
import { DiskStorageSchemaType } from '../DiskManagement.schema'
|
||||
import { DISK_TYPE_OPTIONS } from '../ui/DiskManagement.constants'
|
||||
import FormMessage from '../ui/FormMessage'
|
||||
|
||||
type StorageTypeFieldProps = {
|
||||
form: UseFormReturn<DiskStorageSchemaType>
|
||||
@@ -18,8 +25,11 @@ type StorageTypeFieldProps = {
|
||||
}
|
||||
|
||||
export function StorageTypeField({ form, disableInput }: StorageTypeFieldProps) {
|
||||
const { ref: projectRef } = useParams()
|
||||
const { control, trigger } = form
|
||||
|
||||
const { isLoading, error, isError } = useDiskAttributesQuery({ projectRef })
|
||||
|
||||
return (
|
||||
<FormField_Shadcn_
|
||||
name="storageType"
|
||||
@@ -36,13 +46,22 @@ export function StorageTypeField({ form, disableInput }: StorageTypeFieldProps)
|
||||
trigger('provisionedIOPS')
|
||||
}}
|
||||
defaultValue={field.value}
|
||||
disabled={disableInput}
|
||||
disabled={disableInput || isError}
|
||||
>
|
||||
<FormControl_Shadcn_>
|
||||
<SelectTrigger_Shadcn_ className="h-13 max-w-[420px]">
|
||||
<SelectValue_Shadcn_ />
|
||||
</SelectTrigger_Shadcn_>
|
||||
</FormControl_Shadcn_>
|
||||
{isLoading ? (
|
||||
<Skeleton
|
||||
className={cn(
|
||||
buttonVariants({ size: 'small' }),
|
||||
'h-14 min-w-[420px] duration-[2s]'
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<FormControl_Shadcn_>
|
||||
<SelectTrigger_Shadcn_ className="h-14 max-w-[420px]">
|
||||
<SelectValue_Shadcn_ />
|
||||
</SelectTrigger_Shadcn_>
|
||||
</FormControl_Shadcn_>
|
||||
)}
|
||||
<SelectContent_Shadcn_>
|
||||
<>
|
||||
{DISK_TYPE_OPTIONS.map((item) => (
|
||||
@@ -66,6 +85,7 @@ export function StorageTypeField({ form, disableInput }: StorageTypeFieldProps)
|
||||
</>
|
||||
</SelectContent_Shadcn_>
|
||||
</Select_Shadcn_>
|
||||
{error && <FormMessage type="error" message={error.message} />}
|
||||
</FormItemLayout>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { AnimatePresence, motion } from 'framer-motion'
|
||||
import { UseFormReturn } from 'react-hook-form'
|
||||
import { FormControl_Shadcn_, FormField_Shadcn_, Input_Shadcn_ } from 'ui'
|
||||
import { cn, FormControl_Shadcn_, FormField_Shadcn_, Input_Shadcn_, Skeleton } from 'ui'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
import { BillingChangeBadge } from '../ui/BillingChangeBadge'
|
||||
import {
|
||||
@@ -14,6 +14,10 @@ import { DiskStorageSchemaType } from '../DiskManagement.schema'
|
||||
import { DiskManagementThroughputReadReplicas } from '../ui/DiskManagementReadReplicas'
|
||||
import { InputPostTab } from '../ui/InputPostTab'
|
||||
import { useEffect } from 'react'
|
||||
import FormMessage from '../ui/FormMessage'
|
||||
import { useDiskAttributesQuery } from 'data/config/disk-attributes-query'
|
||||
import { useParams } from 'common'
|
||||
import { InputVariants } from '@ui/components/shadcn/ui/input'
|
||||
|
||||
type ThroughputFieldProps = {
|
||||
form: UseFormReturn<DiskStorageSchemaType>
|
||||
@@ -21,6 +25,8 @@ type ThroughputFieldProps = {
|
||||
}
|
||||
|
||||
export function ThroughputField({ form, disableInput }: ThroughputFieldProps) {
|
||||
const { ref: projectRef } = useParams()
|
||||
|
||||
const { control, formState, setValue, getValues, watch } = form
|
||||
|
||||
const watchedStorageType = watch('storageType')
|
||||
@@ -28,6 +34,8 @@ export function ThroughputField({ form, disableInput }: ThroughputFieldProps) {
|
||||
const watchedComputeSize = watch('computeSize')
|
||||
const throughput_mbps = formState.defaultValues?.throughput
|
||||
|
||||
const { isLoading, error } = useDiskAttributesQuery({ projectRef })
|
||||
|
||||
const throughputPrice = calculateThroughputPrice({
|
||||
storageType: form.getValues('storageType') as DiskType,
|
||||
newThroughput: form.getValues('throughput') || 0,
|
||||
@@ -98,28 +106,40 @@ export function ThroughputField({ form, disableInput }: ThroughputFieldProps) {
|
||||
}
|
||||
>
|
||||
<InputPostTab label="MB/s">
|
||||
<FormControl_Shadcn_>
|
||||
<Input_Shadcn_
|
||||
type="number"
|
||||
{...field}
|
||||
value={
|
||||
disableIopsInput
|
||||
? COMPUTE_BASELINE_THROUGHPUT[
|
||||
watchedComputeSize as keyof typeof COMPUTE_BASELINE_THROUGHPUT
|
||||
]
|
||||
: field.value
|
||||
}
|
||||
onChange={(e) => {
|
||||
setValue('throughput', e.target.valueAsNumber, {
|
||||
shouldDirty: true,
|
||||
shouldValidate: true,
|
||||
})
|
||||
}}
|
||||
className="flex-grow font-mono rounded-r-none max-w-32"
|
||||
disabled={disableInput || disableIopsInput || watchedStorageType === 'io2'}
|
||||
/>
|
||||
</FormControl_Shadcn_>
|
||||
{isLoading ? (
|
||||
<div
|
||||
className={cn(
|
||||
InputVariants({ size: 'small' }),
|
||||
'w-32 font-mono rounded-r-none'
|
||||
)}
|
||||
>
|
||||
<Skeleton className="w-10 h-4" />
|
||||
</div>
|
||||
) : (
|
||||
<FormControl_Shadcn_>
|
||||
<Input_Shadcn_
|
||||
type="number"
|
||||
{...field}
|
||||
value={
|
||||
disableIopsInput
|
||||
? COMPUTE_BASELINE_THROUGHPUT[
|
||||
watchedComputeSize as keyof typeof COMPUTE_BASELINE_THROUGHPUT
|
||||
]
|
||||
: field.value
|
||||
}
|
||||
onChange={(e) => {
|
||||
setValue('throughput', e.target.valueAsNumber, {
|
||||
shouldDirty: true,
|
||||
shouldValidate: true,
|
||||
})
|
||||
}}
|
||||
className="flex-grow font-mono rounded-r-none max-w-32"
|
||||
disabled={disableInput || disableIopsInput || watchedStorageType === 'io2'}
|
||||
/>
|
||||
</FormControl_Shadcn_>
|
||||
)}
|
||||
</InputPostTab>
|
||||
{error && <FormMessage type="error" message={error.message} />}
|
||||
</FormItemLayout>
|
||||
)}
|
||||
/>
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ export function ComputeSizeReccomendationSection({
|
||||
iops > maxIOPSforComputeSize && !RESTRICTED_COMPUTE_FOR_IOPS_ON_GP3.includes(computeSize)
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
<AnimatePresence initial={false}>
|
||||
{isVisible && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, height: 0 }}
|
||||
|
||||
@@ -154,7 +154,7 @@ export const DiskManagementIOPSReadReplicas = ({
|
||||
if (readReplicas.length === 0) return null
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
<AnimatePresence initial={false}>
|
||||
{isDirty && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, height: 0 }}
|
||||
@@ -217,7 +217,7 @@ export const DiskManagementThroughputReadReplicas = ({
|
||||
if (readReplicas.length === 0) return null
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
<AnimatePresence initial={false}>
|
||||
{isDirty && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, height: 0 }}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Alert_Shadcn_, AlertDescription_Shadcn_, InfoIcon, WarningIcon } from 'ui'
|
||||
import { Admonition } from 'ui-patterns'
|
||||
|
||||
interface FormMessageProps {
|
||||
message: string
|
||||
@@ -7,10 +7,11 @@ interface FormMessageProps {
|
||||
|
||||
function FormMessage({ message, type }: FormMessageProps) {
|
||||
return (
|
||||
<Alert_Shadcn_ variant={type === 'error' ? 'destructive' : 'default'} className="mt-2">
|
||||
{type === 'error' ? <WarningIcon /> : <InfoIcon className="h-4 w-4" />}
|
||||
<AlertDescription_Shadcn_>{message}</AlertDescription_Shadcn_>
|
||||
</Alert_Shadcn_>
|
||||
<Admonition
|
||||
type={type === 'error' ? 'destructive' : 'default'}
|
||||
className="mt-2"
|
||||
title={message}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user