TriggersList() — supabase Function Reference
Architecture documentation for the TriggersList() function in TriggersList.tsx from the supabase codebase.
Entity Profile
Dependency Diagram
graph TD 80f16831_d05a_3ddc_4b5f_e2ba883198f6["TriggersList()"] e4649650_1257_de82_1d38_de2f1750bc35["generateTriggerCreateSQL()"] 80f16831_d05a_3ddc_4b5f_e2ba883198f6 -->|calls| e4649650_1257_de82_1d38_de2f1750bc35 style 80f16831_d05a_3ddc_4b5f_e2ba883198f6 fill:#6366f1,stroke:#818cf8,color:#fff
Relationship Graph
Source Code
apps/studio/components/interfaces/Database/Triggers/TriggersList/TriggersList.tsx lines 36–296
export const TriggersList = () => {
const [selectedTrigger, setSelectedTrigger] = useState<PostgresTrigger>()
const deletingTriggerIdRef = useRef<string | null>(null)
const { data: project } = useSelectedProjectQuery()
const aiSnap = useAiAssistantStateSnapshot()
const { openSidebar } = useSidebarManagerSnapshot()
const { selectedSchema, setSelectedSchema } = useQuerySchemaState()
const [filterString, setFilterString] = useQueryState(
'search',
parseAsString.withDefault('').withOptions({ history: 'replace', clearOnDefault: true })
)
const isInlineEditorEnabled = useIsInlineEditorEnabled()
const {
templates: editorPanelTemplates,
setValue: setEditorPanelValue,
setTemplates: setEditorPanelTemplates,
setInitialPrompt: setEditorPanelInitialPrompt,
} = useEditorPanelStateSnapshot()
const { data: protectedSchemas } = useProtectedSchemas()
const { isSchemaLocked } = useIsProtectedSchema({ schema: selectedSchema })
const { data = [] } = useTablesQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
const hasTables =
data.filter((a) => !protectedSchemas.find((s) => s.name === a.schema)).length > 0
const {
data: triggers,
error,
isPending,
isError,
} = useDatabaseTriggersQuery({
projectRef: project?.ref,
connectionString: project?.connectionString,
})
const { can: canCreateTriggers } = useAsyncCheckPermissions(
PermissionAction.TENANT_SQL_ADMIN_WRITE,
'triggers'
)
const [showCreateTriggerForm, setShowCreateTriggerForm] = useQueryState(
'new',
parseAsBoolean.withDefault(false).withOptions({ history: 'push', clearOnDefault: true })
)
const { setValue: setTriggerToEdit, value: triggerToEdit } = useQueryStateWithSelect({
urlKey: 'edit',
select: (id: string) => (id ? triggers?.find((fn) => fn.id.toString() === id) : undefined),
enabled: !!triggers,
onError: () => toast.error(`Trigger not found`),
})
const { setValue: setTriggerToDuplicate, value: triggerToDuplicate } = useQueryStateWithSelect({
urlKey: 'duplicate',
select: (id: string) => {
if (!id) return undefined
const original = triggers?.find((trigger) => trigger.id.toString() === id)
return original ? { ...original, name: `${original.name}_duplicate` } : undefined
},
enabled: !!triggers,
onError: () => toast.error(`Trigger not found`),
})
const { setValue: setTriggerToDelete, value: triggerToDelete } = useQueryStateWithSelect({
urlKey: 'delete',
select: (id: string) => (id ? triggers?.find((fn) => fn.id.toString() === id) : undefined),
enabled: !!triggers,
onError: (_error, selectedId) =>
handleErrorOnDelete(deletingTriggerIdRef, selectedId, `Database Trigger not found`),
})
const { mutate: deleteDatabaseTrigger, isPending: isDeletingTrigger } =
useDatabaseTriggerDeleteMutation({
onSuccess: (_, variables) => {
toast.success(`Successfully removed ${variables.trigger.name}`)
setTriggerToDelete(null)
},
onError: () => {
deletingTriggerIdRef.current = null
},
})
const createTrigger = () => {
setTriggerToDuplicate(null)
if (isInlineEditorEnabled) {
setEditorPanelInitialPrompt('Create a new database trigger that...')
setEditorPanelValue(`create trigger trigger_name
after insert or update or delete on table_name
for each row
execute function function_name();`)
if (editorPanelTemplates.length > 0) {
setEditorPanelTemplates([])
}
openSidebar(SIDEBAR_KEYS.EDITOR_PANEL)
} else {
setSelectedTrigger(undefined)
setShowCreateTriggerForm(true)
}
}
const editTrigger = (trigger: PostgresTrigger) => {
setTriggerToDuplicate(null)
if (isInlineEditorEnabled) {
setEditorPanelValue(generateTriggerCreateSQL(trigger))
setEditorPanelTemplates([])
openSidebar(SIDEBAR_KEYS.EDITOR_PANEL)
} else {
setTriggerToEdit(trigger.id.toString())
}
}
const duplicateTrigger = (trigger: PostgresTrigger) => {
if (isInlineEditorEnabled) {
const dupTrigger = {
...trigger,
name: `${trigger.name}_duplicate`,
}
setEditorPanelValue(generateTriggerCreateSQL(dupTrigger))
setEditorPanelTemplates([])
openSidebar(SIDEBAR_KEYS.EDITOR_PANEL)
} else {
setTriggerToDuplicate(trigger.id.toString())
}
}
const deleteTrigger = (trigger: PostgresTrigger) => {
setTriggerToDelete(trigger.id.toString())
}
if (isPending) {
return <GenericSkeletonLoader />
}
if (isError) {
return <AlertError error={error} subject="Failed to retrieve database triggers" />
}
const schemaTriggers = triggers.filter((x) => x.schema === selectedSchema)
return (
<>
<div className="space-y-4">
<div className="flex flex-col lg:flex-row lg:items-center justify-between gap-2 flex-wrap">
<div className="flex flex-col lg:flex-row lg:items-center gap-2 flex-wrap">
<SchemaSelector
className="w-full lg:w-[180px]"
size="tiny"
showError={false}
selectedSchemaName={selectedSchema}
onSelectSchema={setSelectedSchema}
/>
<Input
placeholder="Search for a trigger"
size="tiny"
icon={<Search />}
value={filterString}
className="w-full lg:w-52"
onChange={(e) => setFilterString(e.target.value)}
/>
</div>
<div className="flex items-center gap-2">
<DocsButton href={`${DOCS_URL}/guides/database/postgres/triggers`} />
{!isSchemaLocked && (
<CreateTriggerButtons
hasTables={hasTables}
canCreateTriggers={canCreateTriggers}
selectedSchema={selectedSchema}
onCreateTrigger={createTrigger}
showPlusIcon={true}
/>
)}
</div>
</div>
{isSchemaLocked && <ProtectedSchemaWarning schema={selectedSchema} entity="triggers" />}
{!isSchemaLocked && (schemaTriggers ?? []).length === 0 ? (
<EmptyStatePresentational
icon={DatabaseZap}
title="Add your first trigger"
description="Make your database reactive. Send updates in realtime, call edge functions, or validate data as it comes in."
>
<CreateTriggerButtons
hasTables={hasTables}
canCreateTriggers={canCreateTriggers}
selectedSchema={selectedSchema}
onCreateTrigger={createTrigger}
showPlusIcon={false}
buttonType="default"
/>
</EmptyStatePresentational>
) : (
<div className="w-full overflow-hidden overflow-x-auto">
<Card>
<Table>
<TableHeader>
<TableRow>
<TableHead key="name">Name</TableHead>
<TableHead key="table">Table</TableHead>
<TableHead key="function">Function</TableHead>
<TableHead key="events">Events</TableHead>
<TableHead key="orientation">Orientation</TableHead>
<TableHead key="enabled" className="w-20">
Enabled
</TableHead>
<TableHead key="buttons" className="w-1/12"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TriggerList
schema={selectedSchema}
filterString={filterString}
isLocked={isSchemaLocked}
editTrigger={editTrigger}
duplicateTrigger={duplicateTrigger}
deleteTrigger={deleteTrigger}
/>
</TableBody>
</Table>
</Card>
</div>
)}
</div>
<TriggerSheet
selectedTrigger={selectedTrigger}
open={showCreateTriggerForm}
onClose={() => {
setShowCreateTriggerForm(false)
}}
isDuplicatingTrigger={false}
/>
<TriggerSheet
selectedTrigger={triggerToEdit || triggerToDuplicate}
open={!!triggerToEdit || !!triggerToDuplicate}
onClose={() => {
setTriggerToEdit(null)
setTriggerToDuplicate(null)
}}
isDuplicatingTrigger={!!triggerToDuplicate}
/>
<DeleteTrigger
trigger={triggerToDelete}
visible={!!triggerToDelete}
setVisible={setTriggerToDelete}
onDelete={(params: Parameters<typeof deleteDatabaseTrigger>[0]) => {
deletingTriggerIdRef.current = params.trigger.id.toString()
deleteDatabaseTrigger(params)
}}
isLoading={isDeletingTrigger}
/>
</>
)
}
Domain
Subdomains
Source
Frequently Asked Questions
What does TriggersList() do?
TriggersList() is a function in the supabase codebase.
What does TriggersList() call?
TriggersList() calls 1 function(s): generateTriggerCreateSQL.
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free