Files
supabase/apps/studio/components/interfaces/Functions/EdgeFunctionSecrets/EditSecretSheet.tsx
T
Danny WhiteandJoshen Lim 8a5ad58f81 chore(studio): replace CloseConfirmationModal with DiscardChangesConfirmationDialog (#43430)
## What kind of change does this PR introduce?

Form handling improvement.

## What is the current behavior?

https://github.com/supabase/supabase/pull/43201/ standardised our
discard changes behaviour with a shared hook and
`DiscardChangesConfirmationDialog` component. But many forms and sheets
still:

1. Don’t have any Discard-confirm close behaviour, making it too easy to
make accidental discards
2. Use a more complicated, manually-created `CloseConfirmationModal`
approach

## What is the new behavior?

- Replaced all instances of `#2` above that had `CloseConfirmationModal`
with `DiscardChangesConfirmationDialog` and its hook
- Improved design system documentation around dirty form dismissal

| Before | After |
| --- | --- |
| <img width="987" height="569" alt="Mercor Apexroles Foo
Supabase-9A40EC7C-F335-4B26-B567-450FC0845463"
src="https://github.com/user-attachments/assets/363bed82-34d2-4cc8-9164-6d18cfdbdbbc"
/> | <img width="987" height="569" alt="Mercor Apexroles Foo
Supabase-F427F1FA-DECC-4194-B663-A9E5A6F285A1"
src="https://github.com/user-attachments/assets/d49fafdc-a5c2-46df-9b67-ec42bacbe716"
/> |

## To test

Try editing values these sheets in staging, then blurring the sheet or
pressing `esc`:

- CreateQueueSheet.tsx
- CronJobsTab.tsx
- CronJobPage.tsx
- EditWrapperSheet.tsx
- OverviewTab.tsx
- WrappersTab.tsx
- CreateFunction/index.tsx
- EditHookPanel.tsx
- TriggerSheet.tsx
- SidePanelEditor.tsx
- EditSecretSheet.tsx
- PolicyEditorModal/index.tsx
- PolicyEditorPanel/index.tsx

## Still to come

- [ ] Incrementally take on `#1`: implement
`DiscardChangesConfirmationDialog` and its hook in sheets or dialog
forms that have no dirty form dismissal handling

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-03-06 03:17:35 +00:00

160 lines
5.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { zodResolver } from '@hookform/resolvers/zod'
import { useParams } from 'common'
import { DiscardChangesConfirmationDialog } from 'components/ui-patterns/Dialogs/DiscardChangesConfirmationDialog'
import { useSecretsCreateMutation } from 'data/secrets/secrets-create-mutation'
import { ProjectSecret } from 'data/secrets/secrets-query'
import { useConfirmOnClose } from 'hooks/ui/useConfirmOnClose'
import { Eye, EyeOff } from 'lucide-react'
import { useEffect, useState } from 'react'
import { SubmitHandler, useForm } from 'react-hook-form'
import { useLatest } from 'react-use'
import { toast } from 'sonner'
import {
Button,
Form_Shadcn_,
FormControl_Shadcn_,
FormField_Shadcn_,
Input,
Input_Shadcn_,
Sheet,
SheetContent,
SheetFooter,
SheetHeader,
SheetSection,
SheetTitle,
} from 'ui'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import z from 'zod'
const FORM_ID = 'edit-secret-sidepanel'
const FormSchema = z.object({
name: z.string().min(1, 'Please provide a name for your secret'),
value: z.string().min(1, 'Please provide a value for your secret'),
})
type FormSchemaType = z.infer<typeof FormSchema>
interface EditSecretSheetProps {
secret?: ProjectSecret
visible: boolean
onClose: () => void
}
export function EditSecretSheet({ secret, visible, onClose }: EditSecretSheetProps) {
const { ref: projectRef } = useParams()
const secretName = useLatest(secret?.name)
const [showSecretValue, setShowSecretValue] = useState(false)
const form = useForm<FormSchemaType>({
resolver: zodResolver(FormSchema),
})
const isValid = form.formState.isValid
const isDirty = form.formState.isDirty
const { mutate: updateSecret, isPending: isUpdating } = useSecretsCreateMutation({
onSuccess: (_, variables) => {
toast.success(`Successfully updated secret "${variables.secrets[0].name}"`)
onClose()
},
})
const onSubmit: SubmitHandler<FormSchemaType> = async ({ name, value }) => {
updateSecret({
projectRef,
secrets: [{ name, value }],
})
}
const { confirmOnClose, handleOpenChange, modalProps } = useConfirmOnClose({
checkIsDirty: () => isDirty,
onClose,
})
useEffect(() => {
if (visible) {
form.reset({ name: secretName.current ?? '', value: '' })
}
}, [form, secretName, visible])
return (
<Sheet open={visible} onOpenChange={handleOpenChange}>
<SheetContent size="default" className={'!min-w-screen lg:!min-w-[600px] flex flex-col'}>
<SheetHeader className="py-3 flex flex-row gap-3 items-center">
<SheetTitle>Edit secret</SheetTitle>
</SheetHeader>
<SheetSection className="h-full">
<Form_Shadcn_ {...form}>
<form
id={FORM_ID}
className="flex flex-col gap-y-4"
onSubmit={form.handleSubmit(onSubmit)}
>
<FormField_Shadcn_
control={form.control}
name="name"
render={({ field }) => (
<FormItemLayout label="Name" layout="horizontal">
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
readOnly
className="!text-foreground-light cursor-not-allowed"
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<FormField_Shadcn_
control={form.control}
name="value"
render={({ field }) => (
<FormItemLayout
label="Value"
layout="horizontal"
description="Secrets can’t be retrieved once saved. Enter a new value to overwrite the existing value."
>
<FormControl_Shadcn_>
<Input
{...field}
type={showSecretValue ? 'text' : 'password'}
placeholder="my-secret-value"
data-1p-ignore
data-lpignore="true"
data-form-type="other"
data-bwignore
actions={
<div className="mr-1">
<Button
type="text"
className="px-1"
icon={showSecretValue ? <EyeOff /> : <Eye />}
onClick={() => setShowSecretValue(!showSecretValue)}
/>
</div>
}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
</form>
</Form_Shadcn_>
</SheetSection>
<SheetFooter>
<Button disabled={isUpdating} type="default" onClick={confirmOnClose}>
Cancel
</Button>
<Button form={FORM_ID} htmlType="submit" disabled={!isValid} loading={isUpdating}>
Save
</Button>
</SheetFooter>
</SheetContent>
<DiscardChangesConfirmationDialog {...modalProps} />
</Sheet>
)
}