diff --git a/apps/docs/content/guides/auth/auth-email-templates.mdx b/apps/docs/content/guides/auth/auth-email-templates.mdx index 8f23b52a28414..7731d4f990a3c 100644 --- a/apps/docs/content/guides/auth/auth-email-templates.mdx +++ b/apps/docs/content/guides/auth/auth-email-templates.mdx @@ -71,20 +71,34 @@ For mobile applications, you might need to link or redirect to a specific page w Certain email providers may have spam detection or other security features that prefetch URL links from incoming emails (e.g. [Safe Links in Microsoft Defender for Office 365](https://learn.microsoft.com/en-us/microsoft-365/security/office-365-security/safe-links-about?view=o365-worldwide)). In this scenario, the `{{ .ConfirmationURL }}` sent will be consumed instantly which leads to a "Token has expired or is invalid" error. -To guard against this: +To guard against this there are the options below: -- Use an email OTP instead by including `{{ .Token }}` in the email template. -- Create your own custom email link to redirect the user to a page where they can click on a button to confirm the action. - For example, you can include the following in your email template: +**Option 1** - ```html - Confirm your signup - - ``` +- Use an email OTP instead by including `{{ .Token }}` in the email template +- Create your own custom email link to redirect the user to a page where they can enter with their email and token to login - The user should be brought to a page on your site where they can confirm the action by clicking a button. - The button should contain the actual confirmation link which can be obtained from parsing the `confirmation_url={{ .ConfirmationURL }}` query parameter in the URL. +```html +Confirm your signup +``` + +- Log them in by verifying the OTP token value with their email e.g. with [`supabase.auth.verifyOtp`](/docs/reference/javascript/auth-verifyotp) show below + +```ts +const { data, error } = await supabase.auth.verifyOtp({ email, token, type: 'email' }) +``` + +**Option 2** + +- Create your own custom email link to redirect the user to a page where they can click on a button to confirm the action + +```html +Confirm your signup +``` + +- The button should contain the actual confirmation link which can be obtained from parsing the `confirmation_url={{ .ConfirmationURL }}` query parameter in the URL. ### Email tracking diff --git a/apps/studio/components/interfaces/Database/Triggers/TriggersList/TriggerList.tsx b/apps/studio/components/interfaces/Database/Triggers/TriggersList/TriggerList.tsx index 0374a3758ee49..fa8681560a601 100644 --- a/apps/studio/components/interfaces/Database/Triggers/TriggersList/TriggerList.tsx +++ b/apps/studio/components/interfaces/Database/Triggers/TriggersList/TriggerList.tsx @@ -1,9 +1,12 @@ +import { PostgresTrigger } from '@supabase/postgres-meta' import { PermissionAction } from '@supabase/shared-types/out/constants' import { includes, sortBy } from 'lodash' import { Check, Copy, Edit, Edit2, MoreVertical, Trash, X } from 'lucide-react' -import { ButtonTooltip } from 'components/ui/ButtonTooltip' +import { useParams } from 'common' import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider' +import { ButtonTooltip } from 'components/ui/ButtonTooltip' +import { InlineLink } from 'components/ui/InlineLink' import { useDatabaseTriggersQuery } from 'data/database-triggers/database-triggers-query' import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions' import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject' @@ -24,7 +27,6 @@ import { TooltipTrigger, } from 'ui' import { generateTriggerCreateSQL } from './TriggerList.utils' -import { PostgresTrigger } from '@supabase/postgres-meta' interface TriggerListProps { schema: string @@ -35,7 +37,7 @@ interface TriggerListProps { deleteTrigger: (trigger: PostgresTrigger) => void } -const TriggerList = ({ +export const TriggerList = ({ schema, filterString, isLocked, @@ -43,10 +45,16 @@ const TriggerList = ({ duplicateTrigger, deleteTrigger, }: TriggerListProps) => { + const { ref: projectRef } = useParams() const { data: project } = useSelectedProjectQuery() const aiSnap = useAiAssistantStateSnapshot() const { openSidebar } = useSidebarManagerSnapshot() + const { can: canUpdateTriggers } = useAsyncCheckPermissions( + PermissionAction.TENANT_SQL_ADMIN_WRITE, + 'triggers' + ) + const { data: triggers } = useDatabaseTriggersQuery({ projectRef: project?.ref, connectionString: project?.connectionString, @@ -56,15 +64,10 @@ const TriggerList = ({ includes(x.name.toLowerCase(), filterString.toLowerCase()) || (x.function_name && includes(x.function_name.toLowerCase(), filterString.toLowerCase())) ) - const _triggers = sortBy( filteredTriggers.filter((x) => x.schema == schema), (trigger) => trigger.name.toLocaleLowerCase() ) - const { can: canUpdateTriggers } = useAsyncCheckPermissions( - PermissionAction.TENANT_SQL_ADMIN_WRITE, - 'triggers' - ) if (_triggers.length === 0 && filterString.length === 0) { return ( @@ -94,7 +97,7 @@ const TriggerList = ({ return ( <> - {_triggers.map((x: any) => ( + {_triggers.map((x) => ( @@ -111,15 +114,33 @@ const TriggerList = ({ -

- {x.table} -

+ {x.table_id ? ( + + {x.table} + + ) : ( +

+ {x.table} +

+ )}
-

- {x.function_name} -

+ {x.function_name ? ( + + {x.function_name} + + ) : ( +

-

+ )}
@@ -176,7 +197,7 @@ const TriggerList = ({ const sql = generateTriggerCreateSQL(x) openSidebar(SIDEBAR_KEYS.AI_ASSISTANT) aiSnap.newChat({ - name: `Update trigger ${X.name}`, + name: `Update trigger ${x.name}`, initialInput: `Update this trigger which exists on the ${x.schema}.${x.table} table to...`, suggestions: { title: @@ -237,5 +258,3 @@ const TriggerList = ({ ) } - -export default TriggerList diff --git a/apps/studio/components/interfaces/Database/Triggers/TriggersList/TriggersList.tsx b/apps/studio/components/interfaces/Database/Triggers/TriggersList/TriggersList.tsx index 072948b452d56..5d42c25fd4144 100644 --- a/apps/studio/components/interfaces/Database/Triggers/TriggersList/TriggersList.tsx +++ b/apps/studio/components/interfaces/Database/Triggers/TriggersList/TriggersList.tsx @@ -4,13 +4,11 @@ import { noop } from 'lodash' import { DatabaseZap, FunctionSquare, Plus, Search, Shield } from 'lucide-react' import { parseAsString, useQueryState } from 'nuqs' -import AlphaPreview from 'components/to-be-cleaned/AlphaPreview' -import ProductEmptyState from 'components/to-be-cleaned/ProductEmptyState' +import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider' import AlertError from 'components/ui/AlertError' import { ButtonTooltip } from 'components/ui/ButtonTooltip' import SchemaSelector from 'components/ui/SchemaSelector' import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader' -import { SIDEBAR_KEYS } from 'components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider' import { useDatabaseTriggersQuery } from 'data/database-triggers/database-triggers-query' import { useTablesQuery } from 'data/tables/tables-query' import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions' @@ -21,10 +19,7 @@ import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state' import { useSidebarManagerSnapshot } from 'state/sidebar-manager-state' import { AiIconAnimation, - Button, Card, - CardContent, - cn, Input, Table, TableBody, @@ -33,8 +28,7 @@ import { TableRow, } from 'ui' import { ProtectedSchemaWarning } from '../../ProtectedSchemaWarning' -import TriggerList from './TriggerList' -import Link from 'next/link' +import { TriggerList } from './TriggerList' interface TriggersListProps { createTrigger: () => void @@ -43,7 +37,7 @@ interface TriggersListProps { deleteTrigger: (trigger: PostgresTrigger) => void } -const TriggersList = ({ +export const TriggersList = ({ createTrigger = noop, editTrigger = noop, duplicateTrigger = noop, @@ -248,5 +242,3 @@ const TriggersList = ({ ) } - -export default TriggersList diff --git a/apps/studio/components/ui/AIAssistantPanel/ModelSelector.tsx b/apps/studio/components/ui/AIAssistantPanel/ModelSelector.tsx index 1a2a73a3608d5..aa050cb9c96a6 100644 --- a/apps/studio/components/ui/AIAssistantPanel/ModelSelector.tsx +++ b/apps/studio/components/ui/AIAssistantPanel/ModelSelector.tsx @@ -50,7 +50,7 @@ export const ModelSelector = ({ selectedModel, onSelectModel }: ModelSelectorPro