From 71a184738ce03eeb7122901ff537ddfa977b64d2 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Tue, 17 Sep 2024 15:22:18 +0800 Subject: [PATCH] Chore/more disk mgt UI updates (#29333) * Only show new disk billing UI for AWS provider projects * Fix DiskSpaceBar autoscaling should be fixed at 90% * Change all MiB to MB and GiB to GB * Prettier --- .../DiskManagement.constants.tsx | 7 ++++-- .../DiskManagement/DiskManagement.test.ts | 4 ++-- .../DiskManagement/DiskManagement.utils.ts | 10 ++++----- .../DiskManagementPanelForm.tsx | 22 +++++++++---------- .../DiskManagementPanelSchema.ts | 10 ++++----- .../DiskManagementReviewAndSubmitDialog.tsx | 4 ++-- .../DiskManagement/DiskSpaceBar.tsx | 14 +++++------- .../pages/project/[ref]/settings/database.tsx | 6 ++++- 8 files changed, 40 insertions(+), 37 deletions(-) diff --git a/apps/studio/components/interfaces/DiskManagement/DiskManagement.constants.tsx b/apps/studio/components/interfaces/DiskManagement/DiskManagement.constants.tsx index 95e59e9eb71..98a64acc64e 100644 --- a/apps/studio/components/interfaces/DiskManagement/DiskManagement.constants.tsx +++ b/apps/studio/components/interfaces/DiskManagement/DiskManagement.constants.tsx @@ -1,5 +1,8 @@ import { PlanType } from 'data/subscriptions/org-subscription-query' +// Disk Storage expands automatically when the database reaches 90% of the disk size +export const AUTOSCALING_THRESHOLD = 0.9 + export enum DiskType { GP3 = 'gp3', IO2 = 'io2', @@ -16,12 +19,12 @@ export const THROUGHPUT_RANGE = { export const DISK_PRICING = { [DiskType.GP3]: { - storage: 0.125, // per GiB per month + storage: 0.125, // per GB per month iops: 0.024, // per IOPS per month, charged after 3000 IOPS throughput: 0.095, // per MB/s per month, charged after 125 MB/s }, [DiskType.IO2]: { - storage: 0.195, // per GiB per month + storage: 0.195, // per GB per month iops: 0.119, // per IOPS per month }, } diff --git a/apps/studio/components/interfaces/DiskManagement/DiskManagement.test.ts b/apps/studio/components/interfaces/DiskManagement/DiskManagement.test.ts index 89909b4ce6b..76210dcdb97 100644 --- a/apps/studio/components/interfaces/DiskManagement/DiskManagement.test.ts +++ b/apps/studio/components/interfaces/DiskManagement/DiskManagement.test.ts @@ -64,7 +64,7 @@ describe('DiskManagement.utils.ts:calculateIOPSPrice', () => { }) describe('DiskManagement.utils.ts:calculateThroughputPrice', () => { - test('GP3 with 125 MiBps 150 MiBps', () => { + test('GP3 with 125 MB/s 150 MB/s', () => { const result = calculateThroughputPrice({ storageType: DiskType.GP3, oldThroughput: 125, @@ -73,7 +73,7 @@ describe('DiskManagement.utils.ts:calculateThroughputPrice', () => { expect(result.oldPrice).toBe('0.00') expect(result.newPrice).toBe('2.38') }) - test('IO1 with 125 MiBps 150 MiBps', () => { + test('IO1 with 125 MB/s 150 MB/s', () => { const result = calculateThroughputPrice({ storageType: DiskType.IO2, oldThroughput: 125, diff --git a/apps/studio/components/interfaces/DiskManagement/DiskManagement.utils.ts b/apps/studio/components/interfaces/DiskManagement/DiskManagement.utils.ts index 0d0235e41bf..67b4111fd8a 100644 --- a/apps/studio/components/interfaces/DiskManagement/DiskManagement.utils.ts +++ b/apps/studio/components/interfaces/DiskManagement/DiskManagement.utils.ts @@ -13,14 +13,14 @@ export const calculateDiskSizePrice = ({ newSize: number newStorageType: DiskType }) => { - const oldPricePerGiB = DISK_PRICING[oldStorageType]?.storage ?? 0 - const newPricePerGiB = DISK_PRICING[newStorageType]?.storage ?? 0 + const oldPricePerGB = DISK_PRICING[oldStorageType]?.storage ?? 0 + const newPricePerGB = DISK_PRICING[newStorageType]?.storage ?? 0 const { includedDiskGB } = PLAN_DETAILS?.[planId as keyof typeof PLAN_DETAILS] ?? {} - const oldPrice = (Math.max(oldSize - includedDiskGB[oldStorageType], 0) * oldPricePerGiB).toFixed( + const oldPrice = (Math.max(oldSize - includedDiskGB[oldStorageType], 0) * oldPricePerGB).toFixed( 2 ) - const newPrice = (Math.max(newSize - includedDiskGB[newStorageType], 0) * newPricePerGiB).toFixed( + const newPrice = (Math.max(newSize - includedDiskGB[newStorageType], 0) * newPricePerGB).toFixed( 2 ) @@ -62,7 +62,7 @@ export const calculateIOPSPrice = ({ } // This is only applicable for GP3 storage type, no need to consider IO2 at all -// Also assumes that disk size is > 400 GiB (separate requirement to update throughput) +// Also assumes that disk size is > 400 GB (separate requirement to update throughput) export const calculateThroughputPrice = ({ storageType, newThroughput, diff --git a/apps/studio/components/interfaces/DiskManagement/DiskManagementPanelForm.tsx b/apps/studio/components/interfaces/DiskManagement/DiskManagementPanelForm.tsx index 04c65a935d6..30dba5b764b 100644 --- a/apps/studio/components/interfaces/DiskManagement/DiskManagementPanelForm.tsx +++ b/apps/studio/components/interfaces/DiskManagement/DiskManagementPanelForm.tsx @@ -210,7 +210,7 @@ export function DiskManagementPanelForm() { if (watchedStorageType === 'io2') { setValue('throughput', undefined) // Throughput is not configurable for 'io2' } else if (watchedStorageType === 'gp3') { - // Ensure throughput is within the allowed range if it's greater than or equal to 400 GiB + // Ensure throughput is within the allowed range if it's greater than or equal to 400 GB const currentThroughput = form.getValues('throughput') const { min, max } = THROUGHPUT_RANGE[DiskType.GP3] if (!currentThroughput || currentThroughput < min || currentThroughput > max) { @@ -382,7 +382,7 @@ export function DiskManagementPanelForm() { For io2 storage type, min IOPS is at {minIOPS}, while max IOPS is - at 1000 * disk size in GiB or{' '} + at 1000 * disk size in GB or{' '} {IOPS_RANGE[DiskType.IO2].max.toLocaleString()}, whichever is lower @@ -405,7 +405,7 @@ export function DiskManagementPanelForm() { For gp3 storage type, min IOPS is at {minIOPS} while max IOPS is - at 500 * disk size in GiB or{' '} + at 500 * disk size in GB or{' '} {IOPS_RANGE[DiskType.GP3].max.toLocaleString()}, whichever is lower @@ -474,14 +474,14 @@ export function DiskManagementPanelForm() { control={control} render={({ field }) => (
Throughput must be between {minThroughput} and {maxThroughput}{' '} - MiBps based on your IOPS. + MB/s based on your IOPS. @@ -491,8 +491,8 @@ export function DiskManagementPanelForm() { /> - Min throughput is at 125MiBps, while max throughput is at - 0.25MiBps * IOPS or 1000, whichever is lower + Min throughput is at 125MB/s, while max throughput is at + 0.25MB/s * IOPS or 1000, whichever is lower
@@ -503,7 +503,7 @@ export function DiskManagementPanelForm() { {maxThroughputBasedOnCompute.toFixed(0)} {' '} - MiBps based on your current compute size of{' '} + MB/s based on your current compute size of{' '} {currentCompute?.name}

)} @@ -528,7 +528,7 @@ export function DiskManagementPanelForm() {
- MiBps + MB/s
@@ -560,7 +560,7 @@ export function DiskManagementPanelForm() { layout="horizontal" description={ includedDiskGB > 0 && - `Your plan includes ${includedDiskGB} GiB of disk size for ${watchedStorageType}.` + `Your plan includes ${includedDiskGB} GB of disk size for ${watchedStorageType}.` } >
@@ -585,7 +585,7 @@ export function DiskManagementPanelForm() { />
- GiB + GB
diff --git a/apps/studio/components/interfaces/DiskManagement/DiskManagementPanelSchema.ts b/apps/studio/components/interfaces/DiskManagement/DiskManagementPanelSchema.ts index 88916a0bef8..548bfd51db0 100644 --- a/apps/studio/components/interfaces/DiskManagement/DiskManagementPanelSchema.ts +++ b/apps/studio/components/interfaces/DiskManagement/DiskManagementPanelSchema.ts @@ -4,11 +4,11 @@ const baseSchema = z.object({ storageType: z.enum(['io2', 'gp3']).describe('Type of storage: io2 or gp3'), totalSize: z .number() - .min(8, { message: 'Allocated disk size must be at least 8 GiB.' }) - .max(16384, { message: 'Allocated disk size must not exceed 16,384 GiB.' }) - .describe('Allocated disk size in GiB'), + .min(8, { message: 'Allocated disk size must be at least 8 GB.' }) + .max(16384, { message: 'Allocated disk size must not exceed 16,384 GB.' }) + .describe('Allocated disk size in GB'), provisionedIOPS: z.number().describe('Provisioned IOPS for storage type'), - throughput: z.number().optional().describe('Throughput in MiBps for gp3'), + throughput: z.number().optional().describe('Throughput in MB/s for gp3'), }) export const DiskStorageSchema = baseSchema.superRefine((data, ctx) => { @@ -75,7 +75,7 @@ export const DiskStorageSchema = baseSchema.superRefine((data, ctx) => { if (throughput !== undefined && (throughput < 125 || throughput > maxThroughput)) { ctx.addIssue({ code: z.ZodIssueCode.custom, - message: `Throughput must be set between 125 and ${maxThroughput} MiBps.`, + message: `Throughput must be set between 125 and ${maxThroughput} MB/s.`, path: ['throughput'], }) } diff --git a/apps/studio/components/interfaces/DiskManagement/DiskManagementReviewAndSubmitDialog.tsx b/apps/studio/components/interfaces/DiskManagement/DiskManagementReviewAndSubmitDialog.tsx index f9050dbce45..4a4fbce6f9f 100644 --- a/apps/studio/components/interfaces/DiskManagement/DiskManagementReviewAndSubmitDialog.tsx +++ b/apps/studio/components/interfaces/DiskManagement/DiskManagementReviewAndSubmitDialog.tsx @@ -164,7 +164,7 @@ export const DiskManagementReviewAndSubmitDialog = ({ attribute="Disk size" defaultValue={form.formState.defaultValues?.totalSize ?? 0} newValue={form.getValues('totalSize')} - unit="GiB" + unit="GB" beforePrice={Number(diskSizePrice.oldPrice)} afterPrice={Number(diskSizePrice.newPrice)} /> @@ -181,7 +181,7 @@ export const DiskManagementReviewAndSubmitDialog = ({ attribute="Throughput" defaultValue={form.formState.defaultValues?.throughput ?? 0} newValue={form.getValues('throughput') ?? 0} - unit="MiBps" + unit="MB/s" beforePrice={Number(throughputPrice.oldPrice)} afterPrice={Number(throughputPrice.newPrice)} /> diff --git a/apps/studio/components/interfaces/DiskManagement/DiskSpaceBar.tsx b/apps/studio/components/interfaces/DiskManagement/DiskSpaceBar.tsx index d4bd6a0c2c1..1f3ff172e64 100644 --- a/apps/studio/components/interfaces/DiskManagement/DiskSpaceBar.tsx +++ b/apps/studio/components/interfaces/DiskManagement/DiskSpaceBar.tsx @@ -1,6 +1,5 @@ import { AnimatePresence, motion } from 'framer-motion' import MotionNumber from 'motion-number' -import { useState } from 'react' import { badgeVariants, @@ -9,6 +8,7 @@ import { TooltipContent_Shadcn_, TooltipTrigger_Shadcn_, } from 'ui' +import { AUTOSCALING_THRESHOLD } from './DiskManagement.constants' interface DiskSpaceBarProps { showNewBar: boolean @@ -23,21 +23,17 @@ export default function DiskSpaceBar({ usedSize, newTotalSize, }: DiskSpaceBarProps) { - const [resizeThreshold, setResizeThreshold] = useState(0.5) // 500 MB threshold for resize - const usedPercentage = (usedSize / totalSize) * 100 - const resizePoint = totalSize - resizeThreshold - const resizePercentage = (resizePoint / totalSize) * 100 + const resizePercentage = AUTOSCALING_THRESHOLD * 100 const newUsedPercentage = (usedSize / newTotalSize) * 100 - const newResizePoint = newTotalSize - resizeThreshold - const newResizePercentage = (newResizePoint / newTotalSize) * 100 + const newResizePercentage = AUTOSCALING_THRESHOLD * 100 return (
- {usedSize.toFixed(2)} GiB used of{' '} + {usedSize.toFixed(2)} GB used of{' '} {' '} - GiB + GB
diff --git a/apps/studio/pages/project/[ref]/settings/database.tsx b/apps/studio/pages/project/[ref]/settings/database.tsx index 11230ca81c3..2a7b0c0239c 100644 --- a/apps/studio/pages/project/[ref]/settings/database.tsx +++ b/apps/studio/pages/project/[ref]/settings/database.tsx @@ -17,14 +17,18 @@ import DiskSizeConfiguration from 'components/interfaces/Settings/Database/DiskS import { useFlag } from 'hooks/ui/useFlag' import { useSelectedOrganization } from 'hooks/misc/useSelectedOrganization' import { useOrgSubscriptionQuery } from 'data/subscriptions/org-subscription-query' +import { useSelectedProject } from 'hooks/misc/useSelectedProject' const ProjectSettings: NextPageWithLayout = () => { const diskManagementV2 = useFlag('diskManagementV2') + const project = useSelectedProject() const selectedOrg = useSelectedOrganization() const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: selectedOrg?.slug }) const showNewDiskManagementUI = - subscription?.usage_based_billing_project_addons && diskManagementV2 + diskManagementV2 && + project?.cloud_provider === 'AWS' && + subscription?.usage_based_billing_project_addons return ( <>