mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 01:15:03 +03:00
chore(studio): describe compute CPU by size tier (#50401)
## What kind of change does this PR introduce? Copy/label update in Studio's compute surfaces. ## Description Compute CPU descriptions now branch on the compute size tier: - Sizes below Large read **"Shared compute"** (no core count) - Large and up read **"Dedicated · N vCPUs"** — the unit is always vCPU Changes: - New `lib/compute-labels.ts` helper (`isSharedComputeSize`, `getComputeCpuLabel`) with unit tests - Compute badge hover card, compute size picker, and project-creation selector use the new labels - `new-project.constants.ts` cpu strings updated accordingly - ">16XL" card: "Custom CPU" → "Custom compute"; upsell copy now says "64 vCPUs" - The synthetic Nano/Micro addon `meta` no longer has `cpu_cores`/`cpu_dedicated`; removed the now-unused cpu fields from the hardcoded instance specs - Project-creation sub-text: "Larger, dedicated compute available after creation" ## Tests - New unit tests for the label helper - Infrastructure settings page test now asserts the rendered labels Fixes PROD-663 Related #49998 #49996 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **User Interface** * Updated compute-size labels to use “Shared compute” and vCPU terminology. * Clarified dedicated compute options and availability messaging. * Updated custom instance and upgrade labels, including “Custom compute” and “64 vCPUs.” * **Consistency** * Standardized compute labels across project creation, infrastructure settings, and compute details. * **Tests** * Added coverage verifying shared and dedicated compute classifications and displayed labels. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1e444589c6
commit
77ee1ec127
10 files changed
+89
-46
No files matched your search
@@ -248,8 +248,6 @@ export function getAvailableComputeOptions(
|
||||
price_interval: 'hourly',
|
||||
price_type: 'usage',
|
||||
meta: {
|
||||
cpu_cores: INSTANCE_MICRO_SPECS.cpu_cores,
|
||||
cpu_dedicated: INSTANCE_MICRO_SPECS.cpu_dedicated,
|
||||
memory_gb: INSTANCE_MICRO_SPECS.memory_gb,
|
||||
baseline_disk_io_mbs: INSTANCE_MICRO_SPECS.baseline_disk_io_mbs,
|
||||
max_disk_io_mbs: INSTANCE_MICRO_SPECS.max_disk_io_mbs,
|
||||
@@ -268,8 +266,6 @@ export function getAvailableComputeOptions(
|
||||
price_type: 'usage',
|
||||
// @ts-ignore API types it as Record<string, never>
|
||||
meta: {
|
||||
cpu_cores: INSTANCE_NANO_SPECS.cpu_cores,
|
||||
cpu_dedicated: INSTANCE_NANO_SPECS.cpu_dedicated,
|
||||
memory_gb: INSTANCE_NANO_SPECS.memory_gb,
|
||||
baseline_disk_io_mbs: INSTANCE_NANO_SPECS.baseline_disk_io_mbs,
|
||||
max_disk_io_mbs: INSTANCE_NANO_SPECS.max_disk_io_mbs,
|
||||
|
||||
@@ -34,6 +34,7 @@ import { useProjectAddonsQuery } from '@/data/subscriptions/project-addons-query
|
||||
import { useHighAvailability } from '@/hooks/misc/useHighAvailability'
|
||||
import { useIsFeatureEnabled } from '@/hooks/misc/useIsFeatureEnabled'
|
||||
import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
|
||||
import { getComputeCpuLabel } from '@/lib/compute-labels'
|
||||
|
||||
const SKELETON_PLACEHOLDER_COUNT = 6
|
||||
|
||||
@@ -175,16 +176,7 @@ export function ComputeSizeField({ form, disabled }: ComputeSizeFieldProps) {
|
||||
)?.price
|
||||
: compute.price
|
||||
|
||||
const cpuLabel = (() => {
|
||||
const cpuCores = compute.meta?.cpu_cores
|
||||
if (typeof cpuCores === 'number') {
|
||||
return `${cpuCores}-core CPU`
|
||||
}
|
||||
if (cpuCores) {
|
||||
return `${cpuCores} CPU`
|
||||
}
|
||||
return 'CPU'
|
||||
})()
|
||||
const cpuLabel = getComputeCpuLabel(compute.identifier, compute.meta?.cpu_cores)
|
||||
|
||||
return (
|
||||
<RadioGroupCardItem
|
||||
@@ -343,7 +335,7 @@ export function ComputeSizeField({ form, disabled }: ComputeSizeFieldProps) {
|
||||
size={14}
|
||||
className="text-foreground-lighter"
|
||||
/>
|
||||
<span>Custom CPU</span>
|
||||
<span>Custom compute</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -86,8 +86,7 @@ export const ComputeSizeSelector = ({ form }: ComputeSizeSelectorProps) => {
|
||||
|
||||
<div className="text-sm">
|
||||
<span className="text-foreground">
|
||||
{instanceSizeSpecs[option].ram} RAM / {instanceSizeSpecs[option].cpu}{' '}
|
||||
CPU
|
||||
{instanceSizeSpecs[option].ram} RAM / {instanceSizeSpecs[option].cpu}
|
||||
</span>
|
||||
<p
|
||||
translate="no"
|
||||
@@ -118,7 +117,7 @@ export const ComputeSizeSelector = ({ form }: ComputeSizeSelectorProps) => {
|
||||
{!highAvailability && (
|
||||
<SelectItem key={'disabled'} value={'disabled'} disabled>
|
||||
<div className="flex items-center justify-center w-full">
|
||||
<span>Larger instance sizes available after creation</span>
|
||||
<span>Larger, dedicated compute available after creation</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
)}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { ProjectDetail } from '@/data/projects/project-detail-query'
|
||||
import { useOrgSubscriptionQuery } from '@/data/subscriptions/org-subscription-query'
|
||||
import { useProjectAddonsQuery } from '@/data/subscriptions/project-addons-query'
|
||||
import { ResourceWarning } from '@/data/usage/resource-warnings-query'
|
||||
import { getComputeCpuLabel } from '@/lib/compute-labels'
|
||||
import { useTrack } from '@/lib/telemetry/track'
|
||||
|
||||
export const ChevronsUpAnimated = () => (
|
||||
@@ -149,14 +150,14 @@ export const ComputeBadgeWrapper = ({
|
||||
<div className="flex flex-col gap-1">
|
||||
{computeSize === 'nano' ? (
|
||||
<>
|
||||
<Row label="CPU" stat="Shared" />
|
||||
<Row label="CPU" stat="Shared compute" />
|
||||
<Row label="Memory" stat="Up to 0.5 GB" />
|
||||
</>
|
||||
) : meta !== undefined ? (
|
||||
<>
|
||||
<Row
|
||||
label="CPU"
|
||||
stat={`${meta.cpu_cores ?? '?'}-core ${meta.cpu_dedicated ? '(Dedicated)' : '(Shared)'}`}
|
||||
stat={getComputeCpuLabel(computeSize ?? '', meta.cpu_cores)}
|
||||
/>
|
||||
<Row label="Memory" stat={`${meta.memory_gb ?? '-'} GB`} />
|
||||
</>
|
||||
@@ -179,7 +180,7 @@ export const ComputeBadgeWrapper = ({
|
||||
<p className="text-foreground-light">
|
||||
{isEligibleForFreeUpgrade
|
||||
? 'Paid plans include a free upgrade to Micro compute.'
|
||||
: 'Scale your project up to 64 cores and 256 GB RAM.'}
|
||||
: 'Scale your project up to 64 vCPUs and 256 GB RAM.'}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -29,7 +29,7 @@ export const instanceSizeSpecs: Record<
|
||||
micro: {
|
||||
label: 'Micro',
|
||||
ram: '1 GB',
|
||||
cpu: '2-core',
|
||||
cpu: 'Shared compute',
|
||||
priceHourly: 0.01344,
|
||||
priceMonthly: 10,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
@@ -37,7 +37,7 @@ export const instanceSizeSpecs: Record<
|
||||
small: {
|
||||
label: 'Small',
|
||||
ram: '2 GB',
|
||||
cpu: '2-core',
|
||||
cpu: 'Shared compute',
|
||||
priceHourly: 0.0206,
|
||||
priceMonthly: 15,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
@@ -45,7 +45,7 @@ export const instanceSizeSpecs: Record<
|
||||
medium: {
|
||||
label: 'Medium',
|
||||
ram: '4 GB',
|
||||
cpu: '2-core',
|
||||
cpu: 'Shared compute',
|
||||
priceHourly: 0.0822,
|
||||
priceMonthly: 60,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
@@ -53,7 +53,7 @@ export const instanceSizeSpecs: Record<
|
||||
large: {
|
||||
label: 'Large',
|
||||
ram: '8 GB',
|
||||
cpu: '2-core',
|
||||
cpu: '2 vCPUs',
|
||||
priceHourly: 0.1517,
|
||||
priceMonthly: 110,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
@@ -61,7 +61,7 @@ export const instanceSizeSpecs: Record<
|
||||
xlarge: {
|
||||
label: 'XL',
|
||||
ram: '16 GB',
|
||||
cpu: '4-core',
|
||||
cpu: '4 vCPUs',
|
||||
priceHourly: 0.2877,
|
||||
priceMonthly: 210,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
@@ -69,7 +69,7 @@ export const instanceSizeSpecs: Record<
|
||||
'2xlarge': {
|
||||
label: '2XL',
|
||||
ram: '32 GB',
|
||||
cpu: '8-core',
|
||||
cpu: '8 vCPUs',
|
||||
priceHourly: 0.562,
|
||||
priceMonthly: 410,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
@@ -77,7 +77,7 @@ export const instanceSizeSpecs: Record<
|
||||
'4xlarge': {
|
||||
label: '4XL',
|
||||
ram: '64 GB',
|
||||
cpu: '16-core',
|
||||
cpu: '16 vCPUs',
|
||||
priceHourly: 1.32,
|
||||
priceMonthly: 960,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
@@ -85,7 +85,7 @@ export const instanceSizeSpecs: Record<
|
||||
'8xlarge': {
|
||||
label: '8XL',
|
||||
ram: '128 GB',
|
||||
cpu: '32-core',
|
||||
cpu: '32 vCPUs',
|
||||
priceHourly: 2.562,
|
||||
priceMonthly: 1870,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
@@ -93,7 +93,7 @@ export const instanceSizeSpecs: Record<
|
||||
'12xlarge': {
|
||||
label: '12XL',
|
||||
ram: '192 GB',
|
||||
cpu: '48-core',
|
||||
cpu: '48 vCPUs',
|
||||
priceHourly: 3.836,
|
||||
priceMonthly: 2800,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
@@ -101,7 +101,7 @@ export const instanceSizeSpecs: Record<
|
||||
'16xlarge': {
|
||||
label: '16XL',
|
||||
ram: '256 GB',
|
||||
cpu: '64-core',
|
||||
cpu: '64 vCPUs',
|
||||
priceHourly: 5.12,
|
||||
priceMonthly: 3730,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
@@ -109,7 +109,7 @@ export const instanceSizeSpecs: Record<
|
||||
'24xlarge': {
|
||||
label: '24XL',
|
||||
ram: '384 GB',
|
||||
cpu: '96-core',
|
||||
cpu: '96 vCPUs',
|
||||
priceHourly: 9.73,
|
||||
priceMonthly: 7100,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
@@ -117,7 +117,7 @@ export const instanceSizeSpecs: Record<
|
||||
'24xlarge_optimized_cpu': {
|
||||
label: '24XL - Optimized CPU',
|
||||
ram: '192 GB',
|
||||
cpu: '96-core',
|
||||
cpu: '96 vCPUs',
|
||||
priceHourly: 8.9,
|
||||
priceMonthly: 6500,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
@@ -125,7 +125,7 @@ export const instanceSizeSpecs: Record<
|
||||
'24xlarge_optimized_memory': {
|
||||
label: '24XL - Optimized Memory',
|
||||
ram: '768 GB',
|
||||
cpu: '96-core',
|
||||
cpu: '96 vCPUs',
|
||||
priceHourly: 13.84,
|
||||
priceMonthly: 10100,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
@@ -133,7 +133,7 @@ export const instanceSizeSpecs: Record<
|
||||
'24xlarge_high_memory': {
|
||||
label: '24XL - High Memory',
|
||||
ram: '1536 GB',
|
||||
cpu: '96-core',
|
||||
cpu: '96 vCPUs',
|
||||
priceHourly: 21.91,
|
||||
priceMonthly: 16000,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
@@ -141,7 +141,7 @@ export const instanceSizeSpecs: Record<
|
||||
'48xlarge': {
|
||||
label: '48XL',
|
||||
ram: '768 GB',
|
||||
cpu: '192-core',
|
||||
cpu: '192 vCPUs',
|
||||
priceHourly: 19.47,
|
||||
priceMonthly: 14200,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
@@ -149,7 +149,7 @@ export const instanceSizeSpecs: Record<
|
||||
'48xlarge_optimized_cpu': {
|
||||
label: '48XL - Optimized CPU',
|
||||
ram: '384 GB',
|
||||
cpu: '192-core',
|
||||
cpu: '192 vCPUs',
|
||||
priceHourly: 17.8,
|
||||
priceMonthly: 13000,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
@@ -157,7 +157,7 @@ export const instanceSizeSpecs: Record<
|
||||
'48xlarge_optimized_memory': {
|
||||
label: '48XL - Optimized Memory',
|
||||
ram: '1536 GB',
|
||||
cpu: '192-core',
|
||||
cpu: '192 vCPUs',
|
||||
priceHourly: 27.68,
|
||||
priceMonthly: 20200,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
@@ -165,7 +165,7 @@ export const instanceSizeSpecs: Record<
|
||||
'48xlarge_high_memory': {
|
||||
label: '48XL - High Memory',
|
||||
ram: '3072 GB',
|
||||
cpu: '192-core',
|
||||
cpu: '192 vCPUs',
|
||||
priceHourly: 43.84,
|
||||
priceMonthly: 32000,
|
||||
cloud_providers: [PROVIDERS.AWS.id, PROVIDERS.AWS_K8S.id, PROVIDERS.AWS_NIMBUS.id],
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { getComputeCpuLabel, isSharedComputeSize } from './compute-labels'
|
||||
|
||||
describe('isSharedComputeSize', () => {
|
||||
it('treats sizes below Large as shared', () => {
|
||||
expect(isSharedComputeSize('pico')).toBe(true)
|
||||
expect(isSharedComputeSize('nano')).toBe(true)
|
||||
expect(isSharedComputeSize('micro')).toBe(true)
|
||||
expect(isSharedComputeSize('small')).toBe(true)
|
||||
expect(isSharedComputeSize('medium')).toBe(true)
|
||||
})
|
||||
|
||||
it('treats Large and up as dedicated', () => {
|
||||
expect(isSharedComputeSize('large')).toBe(false)
|
||||
expect(isSharedComputeSize('xlarge')).toBe(false)
|
||||
expect(isSharedComputeSize('16xlarge')).toBe(false)
|
||||
expect(isSharedComputeSize('48xlarge_high_memory')).toBe(false)
|
||||
})
|
||||
|
||||
it('accepts addon variant identifiers and mixed case', () => {
|
||||
expect(isSharedComputeSize('ci_micro')).toBe(true)
|
||||
expect(isSharedComputeSize('ci_large')).toBe(false)
|
||||
expect(isSharedComputeSize('Medium')).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('getComputeCpuLabel', () => {
|
||||
it('labels shared sizes without a count', () => {
|
||||
expect(getComputeCpuLabel('micro', 2)).toBe('Shared compute')
|
||||
expect(getComputeCpuLabel('medium')).toBe('Shared compute')
|
||||
})
|
||||
|
||||
it('labels dedicated sizes with a vCPU count', () => {
|
||||
expect(getComputeCpuLabel('large', 2)).toBe('Dedicated · 2 vCPUs')
|
||||
expect(getComputeCpuLabel('16xlarge', 64)).toBe('Dedicated · 64 vCPUs')
|
||||
})
|
||||
|
||||
it('falls back to a generic dedicated label without a count', () => {
|
||||
expect(getComputeCpuLabel('large')).toBe('Dedicated compute')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,14 @@
|
||||
/** Compute sizes below Large run on shared compute; Large and up are dedicated. */
|
||||
const SHARED_COMPUTE_SIZES = ['pico', 'nano', 'micro', 'small', 'medium']
|
||||
|
||||
export const isSharedComputeSize = (size: string) =>
|
||||
SHARED_COMPUTE_SIZES.includes(size.toLowerCase().replace(/^ci_/, ''))
|
||||
|
||||
/**
|
||||
* User-facing CPU description for a compute size. Branches on the size itself,
|
||||
* not on `meta.cpu_cores` — the platform is dropping that field.
|
||||
*/
|
||||
export const getComputeCpuLabel = (size: string, vcpuCount?: number) => {
|
||||
if (isSharedComputeSize(size)) return 'Shared compute'
|
||||
return typeof vcpuCount === 'number' ? `Dedicated · ${vcpuCount} vCPUs` : 'Dedicated compute'
|
||||
}
|
||||
@@ -121,8 +121,6 @@ export type InstanceSpecs = {
|
||||
baseline_disk_io_mbs: number
|
||||
connections_direct: number
|
||||
connections_pooler: number
|
||||
cpu_cores: number | 'Shared'
|
||||
cpu_dedicated: boolean
|
||||
max_disk_io_mbs: number
|
||||
memory_gb: number
|
||||
}
|
||||
@@ -131,8 +129,6 @@ export const INSTANCE_NANO_SPECS: InstanceSpecs = {
|
||||
baseline_disk_io_mbs: 43,
|
||||
connections_direct: 30,
|
||||
connections_pooler: 200,
|
||||
cpu_cores: 'Shared',
|
||||
cpu_dedicated: false,
|
||||
max_disk_io_mbs: 2085,
|
||||
memory_gb: 0.5,
|
||||
}
|
||||
@@ -141,8 +137,6 @@ export const INSTANCE_MICRO_SPECS: InstanceSpecs = {
|
||||
baseline_disk_io_mbs: 87,
|
||||
connections_direct: 60,
|
||||
connections_pooler: 200,
|
||||
cpu_cores: 2,
|
||||
cpu_dedicated: false,
|
||||
max_disk_io_mbs: 2085,
|
||||
memory_gb: 1,
|
||||
}
|
||||
@@ -493,7 +493,7 @@ describe('project creation wizard', () => {
|
||||
await generateAndWaitForStrongPassword()
|
||||
|
||||
await user.click(getSelectTriggerByLabel('Compute size'))
|
||||
await user.click(await screen.findByText('4 GB RAM / 2-core CPU'))
|
||||
await user.click(await screen.findByText('4 GB RAM / Shared compute'))
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Create new project' }))
|
||||
|
||||
|
||||
@@ -329,6 +329,11 @@ describe('/project/[ref]/settings/infrastructure', () => {
|
||||
expect(screen.getByTestId('metric-Memory')).toHaveTextContent('50%')
|
||||
expect(screen.getByTestId('metric-Disk')).toHaveTextContent('50%')
|
||||
|
||||
// Compute options describe CPU by size: shared below Large, dedicated with vCPUs from Large up
|
||||
expect(screen.getAllByText('Shared compute')).toHaveLength(3) // Nano, Micro, Small
|
||||
expect(screen.getByText('Dedicated · 2 vCPUs')).toBeInTheDocument() // Large
|
||||
expect(screen.queryByText(/-core/)).not.toBeInTheDocument()
|
||||
|
||||
await user.click(screen.getByText('Small'))
|
||||
expect(screen.getByRole('button', { name: 'Review changes' })).toBeEnabled()
|
||||
|
||||
|
||||
Reference in new issue
Block a user