Files
supabase/apps/studio/components/interfaces/APIKeys/CreatePublishableAPIKeyDialog.tsx
Danny White 476d4a5851 refactor(ui): drop redundant Button variant="default" props (#50161)
## What kind of change does this PR introduce?

Mechanical cleanup on top of the Button default-variant change (#50160).

## What is the current behavior?

Many callsites still pass `variant="default"` even though that is now
the component default.

## What is the new behavior?

Removes redundant static `variant="default"` from legacy `Button` and
`ButtonTooltip` callsites. Keeps explicit defaults where they document
the API:

- `button-default.tsx` and `button-sizes.tsx` demos
- `DocsButton`, which pins neutral styling at the wrapper boundary

## To test

Studio:

- [Auth → Rate
Limits](https://studio-staging-2s957kwc4-supabase.vercel.app/dashboard/project/_/auth/rate-limits):
dirty the form so Cancel appears; Cancel stays neutral, Save stays green
- [Project Settings → API
Keys](https://studio-staging-2s957kwc4-supabase.vercel.app/dashboard/project/_/settings/api-keys):
`DocsButton` in the header actions stays neutral

Design system:

- [Design system →
Button](https://design-system-git-dnywh-dc924ac1-supabase.vercel.app/design-system/docs/components/button):
`button-default` / `button-sizes` still show explicit default styling;
Primary (green) is restricted to the Primary section (and `asChild`)

WWW:

- [www → Brand
assets](https://zone-www-dot-com-git-dnywh-dc924ac1-supabase.vercel.app/brand-assets):
Download logo kit / Download button kit stay neutral
2026-09-11 17:05:26 +10:00

160 lines
4.9 KiB
TypeScript

import { zodResolver } from '@hookform/resolvers/zod'
import { Plus } from 'lucide-react'
import { useParams } from 'next/navigation'
import { parseAsString, useQueryState } from 'nuqs'
import { useRef } from 'react'
import { SubmitHandler, useForm } from 'react-hook-form'
import {
Button,
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogSection,
DialogSectionSeparator,
DialogTitle,
Form,
FormControl,
FormField,
Input,
} from 'ui'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import * as z from 'zod'
import { Shortcut } from '@/components/ui/Shortcut'
import { useAPIKeyCreateMutation } from '@/data/api-keys/api-key-create-mutation'
import { SHORTCUT_IDS } from '@/state/shortcuts/registry'
const FORM_ID = 'create-publishable-api-key'
const SCHEMA = z.object({
name: z.string(),
description: z.string().trim(),
})
export interface CreatePublishableAPIKeyDialogProps {
projectRef: string
}
export const CreatePublishableAPIKeyDialog = () => {
const params = useParams()
const projectRef = params?.ref as string
const formRef = useRef<HTMLFormElement>(null)
const [visible, setVisible] = useQueryState('new', parseAsString.withDefault(''))
const onOpenChange = (value: boolean) => {
if (value) setVisible('publishable')
else setVisible('')
}
const openDialog = () => setVisible('publishable')
const defaultValues = { name: '', description: '' }
const form = useForm<z.infer<typeof SCHEMA>>({
resolver: zodResolver(SCHEMA),
defaultValues: {
name: '',
description: '',
},
})
const { mutate: createAPIKey, isPending: isCreatingAPIKey } = useAPIKeyCreateMutation()
const onSubmit: SubmitHandler<z.infer<typeof SCHEMA>> = async (values) => {
createAPIKey(
{
projectRef,
type: 'publishable',
name: values.name,
description: values.description,
},
{
onSuccess: () => {
form.reset(defaultValues)
onOpenChange(false)
},
}
)
}
return (
<Dialog open={visible === 'publishable'} onOpenChange={onOpenChange}>
<Shortcut
id={SHORTCUT_IDS.API_KEYS_NEW_PUBLISHABLE}
onTrigger={openDialog}
side="bottom"
tooltipOpen={visible === 'publishable' ? false : undefined}
>
<Button icon={<Plus />} onClick={openDialog}>
New publishable key
</Button>
</Shortcut>
<DialogContent>
<DialogHeader>
<DialogTitle>Create new publishable API key</DialogTitle>
<DialogDescription>
Publishable API keys are used to authorize requests to your project from the web, mobile
or desktop apps, CLIs or other public components of your application. They are safe to
be published online and embedded in code.
</DialogDescription>
</DialogHeader>
<DialogSectionSeparator />
<DialogSection className="flex flex-col gap-4">
<Form {...form}>
<form
ref={formRef}
className="flex flex-col gap-4"
id={FORM_ID}
onSubmit={form.handleSubmit(onSubmit)}
>
<FormField
key="name"
name="name"
control={form.control}
render={({ field }) => (
<FormItemLayout
label="Name"
description="A short name of lowercase alphanumeric characters and underscore, must start with letter or underscore."
>
<FormControl>
<Input {...field} />
</FormControl>
</FormItemLayout>
)}
/>
<FormField
key="description"
name="description"
control={form.control}
render={({ field }) => (
<FormItemLayout
label="Description"
description="Provide a description about what this key is used for."
>
<FormControl>
<Input {...field} placeholder="(Optional)" />
</FormControl>
</FormItemLayout>
)}
/>
</form>
</Form>
</DialogSection>
<DialogFooter>
<Shortcut
id={SHORTCUT_IDS.API_KEYS_CREATE_PUBLISHABLE}
onTrigger={() => formRef.current?.requestSubmit()}
options={{ enabled: visible === 'publishable' && !isCreatingAPIKey }}
side="top"
>
<Button variant="primary" form={FORM_ID} type="submit" loading={isCreatingAPIKey}>
Create Publishable API key
</Button>
</Shortcut>
</DialogFooter>
</DialogContent>
</Dialog>
)
}