{hook.method.type === 'postgres' ? (
-
+
) : (
-
+
-
- onSelect()}
- tooltip={{
- content: {
- side: 'bottom',
- text: !canUpdateAuthHook
- ? 'You need additional permissions to configure auth hooks'
- : undefined,
- },
- }}
- >
- Configure hook
-
-
-
+
- {hook.enabled ? (
-
-
-
-
- Enabled
-
- ) : (
-
- Disabled
-
- )}
+
+ {hook.enabled ? (
+
+
+
+
+ Enabled
+
+ ) : (
+
+ Disabled
+
+ )}
+
+
+ }
+ aria-label={`Open actions for ${hook.title}`}
+ />
+
+
+
+
+ Edit hook
+
+
+
+
+ Documentation
+
+
+
+
+
+ Delete hook
+
+
+
+
)
diff --git a/apps/studio/components/interfaces/Auth/Hooks/HooksListing.tsx b/apps/studio/components/interfaces/Auth/Hooks/HooksListing.tsx
index a40b77793d1..d1738c13c62 100644
--- a/apps/studio/components/interfaces/Auth/Hooks/HooksListing.tsx
+++ b/apps/studio/components/interfaces/Auth/Hooks/HooksListing.tsx
@@ -1,11 +1,8 @@
-import { joinSqlFragments } from '@supabase/pg-meta/src/pg-format'
import { useParams } from 'common'
import { parseAsString, useQueryState } from 'nuqs'
import { useEffect, useState } from 'react'
import { toast } from 'sonner'
-import { cn } from 'ui'
import { EmptyStatePresentational, GenericSkeletonLoader } from 'ui-patterns'
-import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
import {
PageSection,
PageSectionAside,
@@ -17,21 +14,18 @@ import {
import { AddHookDropdown } from './AddHookDropdown'
import { CreateHookSheet } from './CreateHookSheet'
+import { DeleteHookConfirmationDialog } from './DeleteHookConfirmationDialog'
import { HookCard } from './HookCard'
import { Hook, HOOKS_DEFINITIONS } from './hooks.constants'
-import { extractMethod, getRevokePermissionStatements, isValidHook } from './hooks.utils'
+import { extractMethod, isValidHook } from './hooks.utils'
import { AlertError } from '@/components/ui/AlertError'
-import { CodeEditor } from '@/components/ui/CodeEditor/CodeEditor'
import { useAuthConfigQuery } from '@/data/auth/auth-config-query'
-import { useAuthHooksUpdateMutation } from '@/data/auth/auth-hooks-update-mutation'
-import { executeSql } from '@/data/sql/execute-sql-mutation'
-import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
import { SHORTCUT_IDS } from '@/state/shortcuts/registry'
import { useShortcut } from '@/state/shortcuts/useShortcut'
export const HooksListing = () => {
const { ref: projectRef } = useParams()
- const { data: project } = useSelectedProjectQuery()
+
const {
data: authConfig,
error: authConfigError,
@@ -41,32 +35,10 @@ export const HooksListing = () => {
const [hook, setHook] = useQueryState('hook', parseAsString)
- const [selectedHookForDeletion, setSelectedHookForDeletion] = useState
(null)
+ const [selectedHookForDeletion, setSelectedHookForDeletion] = useState()
const [addHookAsideOpen, setAddHookAsideOpen] = useState(false)
const [addHookEmptyOpen, setAddHookEmptyOpen] = useState(false)
- const { mutate: updateAuthHooks, isPending: isDeletingAuthHook } = useAuthHooksUpdateMutation({
- onSuccess: async () => {
- if (!selectedHookForDeletion) return
-
- const { method } = selectedHookForDeletion
- if (method.type === 'postgres') {
- const revokeStatements = getRevokePermissionStatements(method.schema, method.functionName)
- await executeSql({
- projectRef,
- connectionString: project!.connectionString,
- sql: joinSqlFragments(revokeStatements, '\n'),
- })
- }
- toast.success(`${selectedHookForDeletion.title} has been deleted.`)
- setSelectedHookForDeletion(null)
- setHook(null)
- },
- onError: (error) => {
- toast.error(`Failed to delete hook: ${error.message}`)
- },
- })
-
const hooks: Hook[] = HOOKS_DEFINITIONS.map((definition) => {
return {
...definition,
@@ -158,7 +130,14 @@ export const HooksListing = () => {
{validHooks.map((hook) => {
- return setHook(hook.id)} />
+ return (
+ setHook(hook.id)}
+ onSelectDelete={() => setSelectedHookForDeletion(hook)}
+ />
+ )
})}
@@ -173,54 +152,16 @@ export const HooksListing = () => {
authConfig={authConfig!}
/>
- setSelectedHookForDeletion(null)}
- onConfirm={() => {
- if (!selectedHookForDeletion) return
- updateAuthHooks({
- projectRef: projectRef!,
- config: {
- [selectedHookForDeletion.enabledKey]: false,
- [selectedHookForDeletion.uriKey]: null,
- [selectedHookForDeletion.secretsKey]: null,
- },
- })
+ {
+ if (!open) setSelectedHookForDeletion(undefined)
}}
- >
-
-
- Are you sure you want to delete the {selectedHookForDeletion?.title}?
-
- {selectedHookForDeletion?.method.type === 'postgres' && (
- <>
-
- The following statements will be executed on the{' '}
- {selectedHookForDeletion?.method.schema}.
- {selectedHookForDeletion?.method.functionName} function:
-
-
-
-
- >
- )}
-
-
+ onDeleteSuccess={() => {
+ setSelectedHookForDeletion(undefined)
+ setHook(null)
+ }}
+ />
)
diff --git a/apps/studio/pages/project/[ref]/auth/templates/[templateId].tsx b/apps/studio/pages/project/[ref]/auth/templates/[templateId].tsx
index ba1d3cc5196..45bc7b61347 100644
--- a/apps/studio/pages/project/[ref]/auth/templates/[templateId].tsx
+++ b/apps/studio/pages/project/[ref]/auth/templates/[templateId].tsx
@@ -50,6 +50,7 @@ import {
isCustomEmailTemplateRestrictionStatusKnown,
slugifyTitle,
} from '@/components/interfaces/Auth/EmailTemplates/EmailTemplates.utils'
+import { SendEmailHookActiveAdmonition } from '@/components/interfaces/Auth/EmailTemplates/SendEmailHookActiveAdmonition'
import { TemplateEditor } from '@/components/interfaces/Auth/EmailTemplates/TemplateEditor'
import AuthLayout from '@/components/layouts/AuthLayout/AuthLayout'
import { DefaultLayout } from '@/components/layouts/DefaultLayout'
@@ -98,6 +99,9 @@ const RedirectToTemplates = () => {
projectInsertedAt: selectedProject?.inserted_at,
})
const isTemplateEditorReadOnly = !isTemplateRestrictionStatusKnown || isTemplateEditBlocked
+ const hasSendEmailHook = !!(
+ authConfig?.HOOK_SEND_EMAIL_ENABLED && authConfig?.HOOK_SEND_EMAIL_URI
+ )
const { mutate: updateAuthConfig, isPending: isUpdatingConfig } = useAuthConfigUpdateMutation({
onError: (error) => {
@@ -280,7 +284,7 @@ const RedirectToTemplates = () => {
)}
- {showConfigurationSection && (
+ {(showConfigurationSection || isTemplateEditBlocked) && (
Content
@@ -288,11 +292,16 @@ const RedirectToTemplates = () => {
)}
- {isTemplateEditBlocked && (
+ {isTemplateEditBlocked && !hasSendEmailHook && (
)}
+ {hasSendEmailHook && (
+
+
+
+ )}