TriggerSheet() — supabase Function Reference
Architecture documentation for the TriggerSheet() function in TriggerSheet.tsx from the supabase codebase.
Entity Profile
Relationship Graph
Source Code
apps/studio/components/interfaces/Database/Triggers/TriggerSheet.tsx lines 85–498
export const TriggerSheet = ({
selectedTrigger,
isDuplicatingTrigger,
open,
onClose,
}: TriggerSheetProps) => {
const { data: project } = useSelectedProjectQuery()
const [showFunctionSelector, setShowFunctionSelector] = useState(false)
const { mutate: createDatabaseTrigger, isPending: isCreating } = useDatabaseTriggerCreateMutation(
{
onSuccess: () => {
toast.success(`Successfully created trigger`)
onClose()
},
onError: (error) => {
toast.error(`Failed to create trigger: ${error.message}`)
},
}
)
const { mutate: updateDatabaseTrigger, isPending: isUpdating } = useDatabaseTriggerUpdateMutation(
{
onSuccess: () => {
toast.success(`Successfully updated trigger`)
onClose()
},
onError: (error) => {
toast.error(`Failed to update trigger: ${error.message}`)
},
}
)
const { data = [], isSuccess: isSuccessTables } = useTablesQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
const { data: protectedSchemas, isSuccess: isSuccessProtectedSchemas } = useProtectedSchemas()
const isSuccess = isSuccessTables && isSuccessProtectedSchemas
const tables = data
.sort((a, b) => a.schema.localeCompare(b.schema))
.filter((a) => !protectedSchemas.find((s) => s.name === a.schema))
const isEditing = !isDuplicatingTrigger && !!selectedTrigger
const form = useForm<z.infer<typeof FormSchema>>({
mode: 'onSubmit',
reValidateMode: 'onSubmit',
resolver: zodResolver(FormSchema),
defaultValues,
})
const { function_name, function_schema } = form.watch()
const { confirmOnClose, modalProps: closeConfirmationModalProps } = useConfirmOnClose({
checkIsDirty: () => form.formState.isDirty,
onClose,
})
const onSubmit: SubmitHandler<z.infer<typeof FormSchema>> = async (values) => {
if (!project) return console.error('Project is required')
const { tableId, ...payload } = values
if (isEditing) {
updateDatabaseTrigger({
projectRef: project?.ref,
connectionString: project?.connectionString,
originalTrigger: selectedTrigger,
payload: { name: payload.name, enabled_mode: payload.enabled_mode },
})
} else {
createDatabaseTrigger({
projectRef: project?.ref,
connectionString: project?.connectionString,
payload,
})
}
}
useEffect(() => {
if (open && isSuccess) {
form.clearErrors()
if (isDuplicatingTrigger && selectedTrigger) {
const initalSelectedTable = tables.find((t) => t.name === selectedTrigger.table)
form.reset({
...selectedTrigger,
tableId: initalSelectedTable?.id.toString(),
table: initalSelectedTable?.name,
schema: initalSelectedTable?.schema,
})
} else if (isEditing) {
form.reset(selectedTrigger)
} else if (tables.length > 0) {
form.reset({
...defaultValues,
tableId: tables[0].id.toString(),
table: tables[0].name,
schema: tables[0].schema,
})
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [open, isSuccess])
return (
<>
<Sheet open={open} onOpenChange={confirmOnClose}>
<SheetContent size="lg" className="flex flex-col gap-0">
<SheetHeader>
<SheetTitle>
{isDuplicatingTrigger
? 'Duplicate trigger'
: isEditing
? `Edit database trigger: ${selectedTrigger.name}`
: 'Create a new database trigger'}
</SheetTitle>
</SheetHeader>
<Form_Shadcn_ {...form}>
<form
id={formId}
className="flex-1 flex flex-col gap-y-6 overflow-auto py-6"
onSubmit={form.handleSubmit(onSubmit)}
>
<FormField_Shadcn_
name="name"
control={form.control}
render={({ field }) => (
<FormItemLayout
className="px-5"
layout="horizontal"
label="Name of trigger"
description="Do not use spaces/whitespace."
>
<FormControl_Shadcn_>
<Input_Shadcn_ {...field} placeholder="Name of trigger" />
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
{isEditing ? (
<FormField_Shadcn_
name="enabled_mode"
control={form.control}
render={({ field }) => (
<FormItemLayout
className="px-5"
layout="horizontal"
label="Enabled mode"
description="Determines if a trigger should or should not fire. Can also be used to disable a trigger, but not delete it."
>
<FormControl_Shadcn_>
<Select_Shadcn_ defaultValue={field.value} onValueChange={field.onChange}>
<SelectTrigger_Shadcn_ className="col-span-8">
{
TRIGGER_ENABLED_MODES.find((option) => option.value === field.value)
?.label
}
</SelectTrigger_Shadcn_>
<SelectContent_Shadcn_>
{TRIGGER_ENABLED_MODES.map((option) => (
<SelectItem_Shadcn_ key={option.value} value={option.value}>
<p className="text-foreground">{option.label}</p>
<p className="text-foreground-lighter">{option.description}</p>
</SelectItem_Shadcn_>
))}
</SelectContent_Shadcn_>
</Select_Shadcn_>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
) : (
<>
<Separator />
<FormField_Shadcn_
name="tableId"
control={form.control}
render={({ field }) => (
<FormItemLayout
className="px-5"
layout="horizontal"
label="Table"
description="Trigger will watch for changes on this table"
>
<FormControl_Shadcn_>
<Select_Shadcn_
defaultValue={field.value}
onValueChange={(val) => {
// mark table ID as dirty to trigger validation
field.onChange(val)
const table = tables.find((x) => x.id.toString() === val)
if (table) {
form.setValue('table', table.name, { shouldDirty: true })
form.setValue('schema', table.schema, { shouldDirty: true })
}
}}
>
<SelectTrigger_Shadcn_ className="col-span-8">
<SelectValue_Shadcn_ />
</SelectTrigger_Shadcn_>
<SelectContent_Shadcn_>
{tables.map((table) => (
<SelectItem_Shadcn_ key={table.id} value={table.id.toString()}>
<span className="text-foreground-light">{table.schema}.</span>
<span className="text-foreground">{table.name}</span>
</SelectItem_Shadcn_>
))}
</SelectContent_Shadcn_>
</Select_Shadcn_>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<FormField_Shadcn_
name="events"
control={form.control}
render={() => (
<FormItemLayout
className="px-5"
layout="horizontal"
label="Events"
description="These are the events that are watched by the trigger, only the events selected above will fire the trigger on the table you've selected."
>
{TRIGGER_EVENTS.map((event) => (
<FormField_Shadcn_
key={event.value}
control={form.control}
name="events"
render={({ field }) => (
<FormItemLayout
hideMessage
layout="flex"
label={event.label}
description={event.description}
>
<FormControl_Shadcn_>
<Checkbox_Shadcn_
className="translate-y-[2px]"
checked={field.value?.includes(event.value)}
onCheckedChange={(checked) => {
return checked
? field.onChange([...field.value, event.value])
: field.onChange(
field.value?.filter((value) => value !== event.value)
)
}}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
))}
</FormItemLayout>
)}
/>
<FormField_Shadcn_
name="activation"
control={form.control}
render={({ field }) => (
<FormItemLayout
className="px-5"
layout="horizontal"
label="Trigger type"
description="Determines when your trigger fires"
>
<FormControl_Shadcn_>
<Select_Shadcn_ defaultValue={field.value} onValueChange={field.onChange}>
<SelectTrigger_Shadcn_ className="col-span-8">
{TRIGGER_TYPES.find((option) => option.value === field.value)?.label}
</SelectTrigger_Shadcn_>
<SelectContent_Shadcn_>
{TRIGGER_TYPES.map((option) => (
<SelectItem_Shadcn_ key={option.value} value={option.value}>
<p className="text-foreground">{option.label}</p>
<p className="text-foreground-lighter">{option.description}</p>
</SelectItem_Shadcn_>
))}
</SelectContent_Shadcn_>
</Select_Shadcn_>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<FormField_Shadcn_
name="orientation"
control={form.control}
render={({ field }) => (
<FormItemLayout
className="px-5"
layout="horizontal"
label="Orientation"
description="Identifies whether the trigger fires once for each processed row or once for each statement"
>
<FormControl_Shadcn_>
<Select_Shadcn_ defaultValue={field.value} onValueChange={field.onChange}>
<SelectTrigger_Shadcn_ className="col-span-8">
{
TRIGGER_ORIENTATIONS.find((option) => option.value === field.value)
?.label
}
</SelectTrigger_Shadcn_>
<SelectContent_Shadcn_>
{TRIGGER_ORIENTATIONS.map((option) => (
<SelectItem_Shadcn_ key={option.value} value={option.value}>
<p className="text-foreground">{option.label}</p>
<p className="text-foreground-lighter">{option.description}</p>
</SelectItem_Shadcn_>
))}
</SelectContent_Shadcn_>
</Select_Shadcn_>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<Separator />
<FormField_Shadcn_
name="function_name"
control={form.control}
render={() => (
<FormItemLayout layout="vertical" className="px-5">
<FormControl_Shadcn_>
<div className="flex flex-col gap-y-2">
<p className="text-sm">Function to trigger</p>
{function_name.length === 0 ? (
<button
type="button"
className={cn(
'relative w-full rounded border border-default',
'bg-surface-200 px-5 py-1 shadow-sm transition-all',
'hover:border-strong hover:bg-overlay-hover'
)}
onClick={() => setShowFunctionSelector(true)}
>
<FormBoxEmpty
icon={<Terminal size={14} strokeWidth={2} />}
text="Choose a function to trigger"
/>
</button>
) : (
<div
className={cn(
'relative w-full flex items-center justify-between',
'space-x-3 px-5 py-4 border border-default',
'rounded shadow-sm transition-shadow'
)}
>
<div className="flex items-center gap-2">
<div className="flex h-6 w-6 items-center justify-center rounded bg-foreground text-background focus-within:bg-opacity-10">
<Terminal size="18" strokeWidth={2} width={14} />
</div>
<p>
<span className="text-sm text-foreground-light">
{function_schema}
</span>
.
<span className="text-sm text-foreground">{function_name}</span>
</p>
</div>
<Button
type="default"
onClick={() => setShowFunctionSelector(true)}
>
Change function
</Button>
</div>
)}
</div>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
</>
)}
</form>
</Form_Shadcn_>
<SheetFooter className="shrink-0">
<Button
type="default"
htmlType="reset"
disabled={isCreating || isUpdating}
onClick={confirmOnClose}
>
Cancel
</Button>
<Button form={formId} htmlType="submit" loading={isCreating || isUpdating}>
{isEditing ? 'Save' : 'Create'} trigger
</Button>
</SheetFooter>
<CloseConfirmationModal {...closeConfirmationModalProps} />
</SheetContent>
</Sheet>
<ChooseFunctionForm
visible={showFunctionSelector}
setVisible={setShowFunctionSelector}
onChange={(fn) => {
form.setValue('function_name', fn.name)
form.setValue('function_schema', fn.schema)
}}
/>
</>
)
}
Domain
Subdomains
Source
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free