mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 01:45:10 +03:00
chore(studio): add custom instance type input to project creation GENCOMP-76 (#45660)
## Summary - Adds a "Custom instance type" input on the new-project modal, rendered directly below the existing custom Postgres version field and gated behind the same non-prod check. - Wires the value through `custom_supabase_internal_requests.ami.instance_type`, merged with the existing AMI search-tag payload so both can be set independently. <img width="312" height="133" alt="Screenshot 2026-05-07 at 12 32 41 PM" src="https://github.com/user-attachments/assets/d4190a0f-0a54-46e6-ac0b-967548a3903f" /> ## Test plan - [x] On a non-prod build, open the new-project modal and confirm the "Custom instance type" field appears below "Custom Postgres version". - [ ] Submit with only an instance type set and verify the request body includes `custom_supabase_internal_requests.instance_type` and no `ami` block. - [x] Submit with both fields set and verify both `ami.search_tags` and `instance_type` are sent. - [x] Submit with neither set and verify `custom_supabase_internal_requests` is omitted. - [x] Verify the field is hidden in prod builds. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added instance type field to project-creation wizard. * Added an internal-only configuration panel for advanced customization. * **Refactor** * Simplified Advanced Configuration panel layout and behavior. * **Documentation** * Updated documentation links to use internal reference URLs. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
This commit is contained in:
6 files changed
+186
-155
No files matched your search
@@ -26,121 +26,111 @@ import { DOCS_URL } from '@/lib/constants'
|
||||
|
||||
interface AdvancedConfigurationProps {
|
||||
form: UseFormReturn<CreateProjectForm>
|
||||
layout?: 'vertical' | 'horizontal'
|
||||
collapsible?: boolean
|
||||
}
|
||||
|
||||
export const AdvancedConfiguration = ({
|
||||
form,
|
||||
layout = 'horizontal',
|
||||
collapsible = true,
|
||||
}: AdvancedConfigurationProps) => {
|
||||
export const AdvancedConfiguration = ({ form }: AdvancedConfigurationProps) => {
|
||||
const disableOrioleProjectCreation = useFlag('disableOrioleProjectCreation')
|
||||
|
||||
const content = (
|
||||
<>
|
||||
<FormField
|
||||
name="useOrioleDb"
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<>
|
||||
<FormItemLayout
|
||||
layout={layout}
|
||||
label="Postgres Type"
|
||||
className="[&>div>label]:break-normal!"
|
||||
>
|
||||
<FormControl>
|
||||
<RadioGroupStacked
|
||||
// Due to radio group not supporting boolean values
|
||||
// value is converted to boolean
|
||||
onValueChange={(value) => field.onChange(value === 'true')}
|
||||
defaultValue={field.value.toString()}
|
||||
return (
|
||||
<Panel.Content>
|
||||
<Collapsible_Shadcn_>
|
||||
<CollapsibleTrigger_Shadcn_ className="group/advanced-trigger font-mono uppercase tracking-widest text-xs flex items-center gap-1 text-foreground-lighter/75 hover:text-foreground-light transition data-open:text-foreground-light">
|
||||
Advanced Configuration
|
||||
<ChevronRight
|
||||
size={16}
|
||||
strokeWidth={1}
|
||||
className="mr-2 group-data-open/advanced-trigger:rotate-90 group-hover/advanced-trigger:text-foreground-light transition"
|
||||
/>
|
||||
</CollapsibleTrigger_Shadcn_>
|
||||
<CollapsibleContent_Shadcn_
|
||||
className={cn(
|
||||
'pt-2 data-closed:animate-collapsible-up data-open:animate-collapsible-down'
|
||||
)}
|
||||
>
|
||||
<p className="text-xs text-foreground-lighter mb-6">
|
||||
These settings cannot be changed after the project is created
|
||||
</p>
|
||||
<FormField
|
||||
name="useOrioleDb"
|
||||
control={form.control}
|
||||
render={({ field }) => (
|
||||
<>
|
||||
<FormItemLayout
|
||||
layout="horizontal"
|
||||
label="Postgres Type"
|
||||
className="[&>div>label]:break-normal!"
|
||||
>
|
||||
<FormItem asChild>
|
||||
<FormControl>
|
||||
<RadioGroupStackedItem
|
||||
value="false"
|
||||
// @ts-ignore
|
||||
label={
|
||||
<>
|
||||
Postgres
|
||||
<Badge>Default</Badge>
|
||||
</>
|
||||
}
|
||||
description="Recommended for production workloads"
|
||||
className="[&>div>div>p]:text-left [&>div>div>p]:text-xs [&>div>div>label]:flex [&>div>div>label]:items-center [&>div>div>label]:gap-x-2"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
<FormItem asChild>
|
||||
<FormControl>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<FormControl>
|
||||
<RadioGroupStacked
|
||||
// Due to radio group not supporting boolean values
|
||||
// value is converted to boolean
|
||||
onValueChange={(value) => field.onChange(value === 'true')}
|
||||
defaultValue={field.value.toString()}
|
||||
>
|
||||
<FormItem asChild>
|
||||
<FormControl>
|
||||
<RadioGroupStackedItem
|
||||
value="true"
|
||||
value="false"
|
||||
// @ts-ignore
|
||||
label={
|
||||
<>
|
||||
Postgres with OrioleDB
|
||||
<Badge variant="warning">Alpha</Badge>
|
||||
Postgres
|
||||
<Badge>Default</Badge>
|
||||
</>
|
||||
}
|
||||
description="Not recommended for production workloads"
|
||||
className={cn(
|
||||
'[&>div>div>p]:text-left [&>div>div>p]:text-xs [&>div>div>label]:flex [&>div>div>label]:items-center [&>div>div>label]:gap-x-2',
|
||||
form.getValues('useOrioleDb') ? 'rounded-b-none!' : ''
|
||||
)}
|
||||
disabled={disableOrioleProjectCreation}
|
||||
description="Recommended for production workloads"
|
||||
className="[&>div>div>p]:text-left [&>div>div>p]:text-xs [&>div>div>label]:flex [&>div>div>label]:items-center [&>div>div>label]:gap-x-2"
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
{disableOrioleProjectCreation && (
|
||||
<TooltipContent side="right" className="w-60 text-center">
|
||||
OrioleDB is temporarily disabled for new projects. Please try again
|
||||
later.
|
||||
</TooltipContent>
|
||||
)}
|
||||
</Tooltip>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
</RadioGroupStacked>
|
||||
</FormControl>
|
||||
{form.getValues('useOrioleDb') && (
|
||||
<Admonition
|
||||
type="warning"
|
||||
className="rounded-t-none [&>div]:text-xs"
|
||||
title="OrioleDB is not production ready"
|
||||
description="Postgres with OrioleDB extension is currently in Public Alpha and not recommended for production usage yet."
|
||||
>
|
||||
<DocsButton className="mt-2" href={`${DOCS_URL}/guides/database/orioledb`} />
|
||||
</Admonition>
|
||||
)}
|
||||
</FormItemLayout>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
<p className="text-xs text-foreground-lighter mt-3">
|
||||
These settings cannot be changed after the project is created
|
||||
</p>
|
||||
</>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
<FormItem asChild>
|
||||
<FormControl>
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<RadioGroupStackedItem
|
||||
value="true"
|
||||
// @ts-ignore
|
||||
label={
|
||||
<>
|
||||
Postgres with OrioleDB
|
||||
<Badge variant="warning">Alpha</Badge>
|
||||
</>
|
||||
}
|
||||
description="Not recommended for production workloads"
|
||||
className={cn(
|
||||
'[&>div>div>p]:text-left [&>div>div>p]:text-xs [&>div>div>label]:flex [&>div>div>label]:items-center [&>div>div>label]:gap-x-2',
|
||||
form.getValues('useOrioleDb') ? 'rounded-b-none!' : ''
|
||||
)}
|
||||
disabled={disableOrioleProjectCreation}
|
||||
/>
|
||||
</TooltipTrigger>
|
||||
{disableOrioleProjectCreation && (
|
||||
<TooltipContent side="right" className="w-60 text-center">
|
||||
OrioleDB is temporarily disabled for new projects. Please try again
|
||||
later.
|
||||
</TooltipContent>
|
||||
)}
|
||||
</Tooltip>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
</RadioGroupStacked>
|
||||
</FormControl>
|
||||
{form.getValues('useOrioleDb') && (
|
||||
<Admonition
|
||||
type="warning"
|
||||
className="rounded-t-none [&>div]:text-xs"
|
||||
title="OrioleDB is not production ready"
|
||||
description="Postgres with OrioleDB extension is currently in Public Alpha and not recommended for production usage yet."
|
||||
>
|
||||
<DocsButton className="mt-2" href={`${DOCS_URL}/guides/database/orioledb`} />
|
||||
</Admonition>
|
||||
)}
|
||||
</FormItemLayout>
|
||||
</>
|
||||
)}
|
||||
/>
|
||||
</CollapsibleContent_Shadcn_>
|
||||
</Collapsible_Shadcn_>
|
||||
</Panel.Content>
|
||||
)
|
||||
|
||||
const collapsibleContent = (
|
||||
<Collapsible_Shadcn_>
|
||||
<CollapsibleTrigger_Shadcn_ className="group/advanced-trigger font-mono uppercase tracking-widest text-xs flex items-center gap-1 text-foreground-lighter/75 hover:text-foreground-light transition data-open:text-foreground-light">
|
||||
Advanced Configuration
|
||||
<ChevronRight
|
||||
size={16}
|
||||
strokeWidth={1}
|
||||
className="mr-2 group-data-open/advanced-trigger:rotate-90 group-hover/advanced-trigger:text-foreground-light transition"
|
||||
/>
|
||||
</CollapsibleTrigger_Shadcn_>
|
||||
<CollapsibleContent_Shadcn_
|
||||
className={cn('pt-5 data-closed:animate-collapsible-up data-open:animate-collapsible-down')}
|
||||
>
|
||||
{content}
|
||||
</CollapsibleContent_Shadcn_>
|
||||
</Collapsible_Shadcn_>
|
||||
)
|
||||
|
||||
return <Panel.Content>{collapsible ? collapsibleContent : content}</Panel.Content>
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
import { UseFormReturn } from 'react-hook-form'
|
||||
import { FormControl, FormField, Input_Shadcn_ } from 'ui'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
|
||||
import { CreateProjectForm } from './ProjectCreation.schema'
|
||||
import Panel from '@/components/ui/Panel'
|
||||
|
||||
interface CustomPostgresVersionInputProps {
|
||||
form: UseFormReturn<CreateProjectForm>
|
||||
}
|
||||
|
||||
export const CustomPostgresVersionInput = ({ form }: CustomPostgresVersionInputProps) => {
|
||||
return (
|
||||
<Panel.Content>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="postgresVersion"
|
||||
render={({ field }) => (
|
||||
<FormItemLayout
|
||||
label="Custom Postgres version"
|
||||
layout="horizontal"
|
||||
description="Specify a custom version of Postgres (defaults to the latest). This is only applicable for local/staging projects."
|
||||
>
|
||||
<FormControl>
|
||||
<Input_Shadcn_ placeholder="Postgres version" {...field} autoComplete="off" />
|
||||
</FormControl>
|
||||
</FormItemLayout>
|
||||
)}
|
||||
/>
|
||||
</Panel.Content>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { CollapsibleContent, CollapsibleTrigger } from '@ui/components/shadcn/ui/collapsible'
|
||||
import { ChevronRight } from 'lucide-react'
|
||||
import { UseFormReturn } from 'react-hook-form'
|
||||
import { Collapsible, FormControl, FormField, Input_Shadcn_ } from 'ui'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
|
||||
import { CreateProjectForm } from './ProjectCreation.schema'
|
||||
import Panel from '@/components/ui/Panel'
|
||||
|
||||
interface InternalOnlyConfigurationProps {
|
||||
form: UseFormReturn<CreateProjectForm>
|
||||
}
|
||||
|
||||
export const InternalOnlyConfiguration = ({ form }: InternalOnlyConfigurationProps) => {
|
||||
return (
|
||||
<Panel.Content>
|
||||
<Collapsible>
|
||||
<CollapsibleTrigger className="group/advanced-trigger font-mono uppercase tracking-widest text-xs flex items-center gap-1 text-foreground-lighter/75 hover:text-foreground-light transition data-open:text-foreground-light">
|
||||
Internal-only Configuration
|
||||
<ChevronRight
|
||||
size={16}
|
||||
strokeWidth={1}
|
||||
className="mr-2 group-data-open/advanced-trigger:rotate-90 group-hover/advanced-trigger:text-foreground-light transition"
|
||||
/>
|
||||
</CollapsibleTrigger>
|
||||
<CollapsibleContent className="pt-2 data-closed:animate-collapsible-up data-open:animate-collapsible-down">
|
||||
<p className="text-xs text-foreground-lighter mb-6">
|
||||
These settings are only applicable for local/staging projects
|
||||
</p>
|
||||
<div className="flex flex-col gap-y-4">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="postgresVersion"
|
||||
render={({ field }) => (
|
||||
<FormItemLayout
|
||||
label="Custom Postgres version"
|
||||
layout="horizontal"
|
||||
description="Specify a custom version of Postgres (defaults to the latest)."
|
||||
>
|
||||
<FormControl>
|
||||
<Input_Shadcn_ placeholder="e.g 17.6.1.104" {...field} autoComplete="off" />
|
||||
</FormControl>
|
||||
</FormItemLayout>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="instanceType"
|
||||
render={({ field }) => (
|
||||
<FormItemLayout
|
||||
label="Custom instance type"
|
||||
layout="horizontal"
|
||||
description="Specify a custom instance type."
|
||||
>
|
||||
<FormControl>
|
||||
<Input_Shadcn_ placeholder="e.g t3.nano" {...field} autoComplete="off" />
|
||||
</FormControl>
|
||||
</FormItemLayout>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</CollapsibleContent>
|
||||
</Collapsible>
|
||||
</Panel.Content>
|
||||
)
|
||||
}
|
||||
@@ -17,6 +17,7 @@ export const FormSchema = z
|
||||
postgresVersion: z.string({
|
||||
required_error: 'Please enter a Postgres version.',
|
||||
}),
|
||||
instanceType: z.string().optional(),
|
||||
dbRegion: z.string({
|
||||
required_error: 'Please select a region.',
|
||||
}),
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import Link from 'next/link'
|
||||
import { UseFormReturn } from 'react-hook-form'
|
||||
import {
|
||||
Checkbox,
|
||||
@@ -17,8 +16,10 @@ import { Admonition } from 'ui-patterns'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
|
||||
import { CreateProjectForm } from './ProjectCreation.schema'
|
||||
import { InlineLink } from '@/components/ui/InlineLink'
|
||||
import Panel from '@/components/ui/Panel'
|
||||
import { useTrackDefaultPrivilegesExposure } from '@/hooks/misc/useDataApiRevokeOnCreateDefault'
|
||||
import { DOCS_URL } from '@/lib/constants'
|
||||
|
||||
interface SecurityOptionsProps {
|
||||
form: UseFormReturn<CreateProjectForm>
|
||||
@@ -51,13 +52,9 @@ export const SecurityOptions = ({ form, layout = 'horizontal' }: SecurityOptions
|
||||
<FormDescription className="text-foreground-lighter">
|
||||
Autogenerate a RESTful API for your public schema. Recommended if using a client
|
||||
library like{' '}
|
||||
<Link
|
||||
href="https://supabase.com/docs/reference/javascript/introduction"
|
||||
target="_blank"
|
||||
className="text-link"
|
||||
>
|
||||
<InlineLink href={`${DOCS_URL}/reference/javascript/introduction`}>
|
||||
supabase-js
|
||||
</Link>
|
||||
</InlineLink>
|
||||
.
|
||||
</FormDescription>
|
||||
</div>
|
||||
|
||||
@@ -18,11 +18,11 @@ import { AUTO_ENABLE_RLS_EVENT_TRIGGER_SQL } from '@/components/interfaces/Datab
|
||||
import { AdvancedConfiguration } from '@/components/interfaces/ProjectCreation/AdvancedConfiguration'
|
||||
import { CloudProviderSelector } from '@/components/interfaces/ProjectCreation/CloudProviderSelector'
|
||||
import { ComputeSizeSelector } from '@/components/interfaces/ProjectCreation/ComputeSizeSelector'
|
||||
import { CustomPostgresVersionInput } from '@/components/interfaces/ProjectCreation/CustomPostgresVersionInput'
|
||||
import { DatabasePasswordInput } from '@/components/interfaces/ProjectCreation/DatabasePasswordInput'
|
||||
import { DisabledWarningDueToIncident } from '@/components/interfaces/ProjectCreation/DisabledWarningDueToIncident'
|
||||
import { FreeProjectLimitWarning } from '@/components/interfaces/ProjectCreation/FreeProjectLimitWarning'
|
||||
import { HighAvailabilityInput } from '@/components/interfaces/ProjectCreation/HighAvailabilityInput'
|
||||
import { InternalOnlyConfiguration } from '@/components/interfaces/ProjectCreation/InternalOnlyConfiguration'
|
||||
import { OrganizationSelector } from '@/components/interfaces/ProjectCreation/OrganizationSelector'
|
||||
import {
|
||||
extractPostgresVersionDetails,
|
||||
@@ -131,6 +131,7 @@ const Wizard: NextPageWithLayout = () => {
|
||||
projectName: projectName || '',
|
||||
highAvailability: false,
|
||||
postgresVersion: '',
|
||||
instanceType: '',
|
||||
cloudProvider: PROVIDERS[defaultProvider].id,
|
||||
dbPass: '',
|
||||
dbPassStrength: 0,
|
||||
@@ -311,6 +312,7 @@ const Wizard: NextPageWithLayout = () => {
|
||||
dbPass,
|
||||
dbRegion,
|
||||
postgresVersion,
|
||||
instanceType,
|
||||
instanceSize,
|
||||
dataApi,
|
||||
dataApiDefaultPrivileges,
|
||||
@@ -355,15 +357,20 @@ const Wizard: NextPageWithLayout = () => {
|
||||
.join('\n') || undefined,
|
||||
}
|
||||
|
||||
if (postgresVersion) {
|
||||
if (!postgresVersion.match(/1[2-9]\..*/)) {
|
||||
toast.error(
|
||||
`Invalid Postgres version, should start with a number between 12-19, a dot and additional characters, i.e. 15.2 or 15.2.0-3`
|
||||
)
|
||||
}
|
||||
if (postgresVersion && !postgresVersion.match(/1[2-9]\..*/)) {
|
||||
toast.error(
|
||||
`Invalid Postgres version, should start with a number between 12-19, a dot and additional characters, i.e. 15.2 or 15.2.0-3`
|
||||
)
|
||||
}
|
||||
|
||||
if (postgresVersion || instanceType) {
|
||||
data['customSupabaseRequest'] = {
|
||||
ami: { search_tags: { 'tag:postgresVersion': postgresVersion } },
|
||||
ami: {
|
||||
...(postgresVersion && {
|
||||
search_tags: { 'tag:postgresVersion': postgresVersion },
|
||||
}),
|
||||
...(instanceType && { instance_type: instanceType }),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,7 +470,7 @@ const Wizard: NextPageWithLayout = () => {
|
||||
{projectCreationDisabled ? (
|
||||
<DisabledWarningDueToIncident title="Project creation is currently disabled" />
|
||||
) : (
|
||||
<div className="divide-y divide-border-muted">
|
||||
<div className="divide-y divide-border-border">
|
||||
<OrganizationSelector form={form} />
|
||||
|
||||
{canCreateProject && (
|
||||
@@ -502,16 +509,17 @@ const Wizard: NextPageWithLayout = () => {
|
||||
</Panel.Content>
|
||||
)}
|
||||
|
||||
{showNonProdFields && <CustomPostgresVersionInput form={form} />}
|
||||
|
||||
<SecurityOptions form={form} />
|
||||
|
||||
{showAdvancedConfig && !!availableOrioleVersion && (
|
||||
<AdvancedConfiguration form={form} />
|
||||
)}
|
||||
|
||||
{showNonProdFields && <InternalOnlyConfiguration form={form} />}
|
||||
|
||||
{shouldShowFreeProjectInfo ? (
|
||||
<Admonition
|
||||
className="rounded-none border-0 border-t"
|
||||
className="rounded-none border-0"
|
||||
type="note"
|
||||
title="Need a free project?"
|
||||
description={
|
||||
|
||||
Reference in new issue
Block a user