Files
Lukas BernertandClaude Fable 5 77ee1ec127 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>
2026-09-17 12:18:48 +02:00

133 lines
4.9 KiB
TypeScript

import { useMemo } from 'react'
import { UseFormReturn } from 'react-hook-form'
import { CloudProvider } from 'shared-data'
import {
cn,
FormField,
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
useWatch,
} from 'ui'
import { ComputeBadge } from 'ui-patterns/ComputeBadge'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import { HIGH_AVAILABILITY_INSTANCE_SIZE, sizes } from './ProjectCreation.constants'
import { CreateProjectForm } from './ProjectCreation.schema'
import { InlineLink } from '@/components/ui/InlineLink'
import Panel from '@/components/ui/Panel'
import { instanceSizeSpecs } from '@/data/projects/new-project.constants'
import { DOCS_URL } from '@/lib/constants'
interface ComputeSizeSelectorProps {
form: UseFormReturn<CreateProjectForm>
}
export const ComputeSizeSelector = ({ form }: ComputeSizeSelectorProps) => {
const cloudProvider = useWatch({ control: form.control, name: 'cloudProvider' }) as CloudProvider
const highAvailability = useWatch({ control: form.control, name: 'highAvailability' })
const sizeOptions = useMemo(
() =>
highAvailability
? [HIGH_AVAILABILITY_INSTANCE_SIZE]
: sizes.filter((option) =>
instanceSizeSpecs[option].cloud_providers.includes(cloudProvider)
),
[highAvailability, cloudProvider]
)
return (
<Panel.Content>
<FormField
control={form.control}
name="instanceSize"
render={({ field }) => (
<FormItemLayout
id="instanceSize"
layout="horizontal"
label="Compute size"
description={
<p>
The size for your dedicated database. You can change this later. Learn more about{' '}
<InlineLink href={`${DOCS_URL}/guides/platform/compute-add-ons`}>
compute add-ons
</InlineLink>{' '}
and{' '}
<InlineLink href={`${DOCS_URL}/guides/platform/manage-your-usage/compute`}>
compute billing
</InlineLink>
.
</p>
}
>
<Select
value={field.value}
onValueChange={(value) => value !== '' && field.onChange(value)}
>
<SelectTrigger
id="instanceSize"
className="[&>span>div>div>[data-field=instance-details]]:hidden"
>
<SelectValue placeholder="Select a compute size" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{sizeOptions.map((option) => {
return (
<SelectItem key={option} value={option}>
<div className="flex flex-row gap-4 items-center">
<div className="w-14 flex items-center">
<ComputeBadge infraComputeSize={option} />
</div>
<div className="text-sm">
<span className="text-foreground">
{instanceSizeSpecs[option].ram} RAM / {instanceSizeSpecs[option].cpu}
</span>
<p
translate="no"
className={cn(
'text-xs',
highAvailability
? 'line-through text-foreground-lighter'
: 'text-foreground-light'
)}
data-field="instance-details"
>
${instanceSizeSpecs[option].priceHourly}/hour (~$
{instanceSizeSpecs[option].priceMonthly}/month)
</p>
{highAvailability && (
<p
className="text-xs text-foreground-light"
data-field="instance-details"
>
Free during Alpha
</p>
)}
</div>
</div>
</SelectItem>
)
})}
{!highAvailability && (
<SelectItem key={'disabled'} value={'disabled'} disabled>
<div className="flex items-center justify-center w-full">
<span>Larger, dedicated compute available after creation</span>
</div>
</SelectItem>
)}
</SelectGroup>
</SelectContent>
</Select>
</FormItemLayout>
)}
/>
</Panel.Content>
)
}