mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
chore(studio): security notification emails announcements (#40366)
* announcement * fix link * Minor clean up --------- Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
This commit is contained in:
1 parent
e08d1f7561
commit
a4928ef049
9 files changed
+86
-20
No files matched your search
@@ -3,8 +3,8 @@ import { LOCAL_STORAGE_KEYS } from 'common'
|
||||
export const FEATURE_PREVIEWS = [
|
||||
{
|
||||
key: LOCAL_STORAGE_KEYS.UI_PREVIEW_SECURITY_NOTIFICATIONS,
|
||||
name: 'Security notification templates',
|
||||
discussionsUrl: undefined,
|
||||
name: 'Security notification emails',
|
||||
discussionsUrl: 'https://github.com/orgs/supabase/discussions/40349',
|
||||
isNew: true,
|
||||
isPlatformOnly: true,
|
||||
},
|
||||
|
||||
+2
-9
@@ -3,11 +3,9 @@ import Image from 'next/image'
|
||||
import { useParams } from 'common'
|
||||
import { InlineLink } from 'components/ui/InlineLink'
|
||||
import { BASE_PATH } from 'lib/constants'
|
||||
import { useIsSecurityNotificationsEnabled } from './FeaturePreviewContext'
|
||||
|
||||
export const SecurityNotificationsPreview = () => {
|
||||
const { ref } = useParams()
|
||||
const isSecurityNotificationsEnabled = useIsSecurityNotificationsEnabled()
|
||||
|
||||
return (
|
||||
<div className="text-sm text-foreground-light">
|
||||
@@ -21,11 +19,7 @@ export const SecurityNotificationsPreview = () => {
|
||||
<div className="space-y-2 !mt-4">
|
||||
<p className=" mb-4">
|
||||
Try out our expanded set of{' '}
|
||||
<InlineLink
|
||||
href={`/project/${ref ?? '_'}/auth/${isSecurityNotificationsEnabled ? 'email' : 'templates'}`}
|
||||
>
|
||||
email templates
|
||||
</InlineLink>{' '}
|
||||
<InlineLink href={`/project/${ref ?? '_'}/auth/templates`}>email templates</InlineLink>{' '}
|
||||
with support for security-related notifications.
|
||||
</p>
|
||||
<p className="text-foreground">Enabling this preview will:</p>
|
||||
@@ -37,8 +31,7 @@ export const SecurityNotificationsPreview = () => {
|
||||
<p>
|
||||
These changes are necessary to support incoming security-related notification templates.
|
||||
Given that the list of our email templates is doubling in size, this change requires some
|
||||
wider interface changes. Ones that we think make for a clearer experience overall. Win
|
||||
win!
|
||||
wider interface changes. Ones that we think make for a clearer experience overall.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import { DOCS_URL } from 'lib/constants'
|
||||
import { Button } from 'ui'
|
||||
import { Admonition } from 'ui-patterns/admonition'
|
||||
|
||||
export function EmailRateLimitsAlert() {
|
||||
export const EmailRateLimitsAlert = () => {
|
||||
const { ref } = useParams()
|
||||
|
||||
return (
|
||||
@@ -1,3 +0,0 @@
|
||||
import { EmailRateLimitsAlert } from './EmailRateLimitsAlert'
|
||||
|
||||
export default EmailRateLimitsAlert
|
||||
@@ -1,21 +1,26 @@
|
||||
import { zodResolver } from '@hookform/resolvers/zod'
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
import { ChevronRight } from 'lucide-react'
|
||||
import { ChevronRight, ExternalLink, X } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { useEffect } from 'react'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { toast } from 'sonner'
|
||||
import { z } from 'zod'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import { FEATURE_PREVIEWS } from 'components/interfaces/App/FeaturePreview/FeaturePreview.constants'
|
||||
import { useIsSecurityNotificationsEnabled } from 'components/interfaces/App/FeaturePreview/FeaturePreviewContext'
|
||||
import { ScaffoldSection, ScaffoldSectionTitle } from 'components/layouts/Scaffold'
|
||||
import AlertError from 'components/ui/AlertError'
|
||||
import { InlineLink } from 'components/ui/InlineLink'
|
||||
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
|
||||
import { useAuthConfigQuery } from 'data/auth/auth-config-query'
|
||||
import { useAuthConfigUpdateMutation } from 'data/auth/auth-config-update-mutation'
|
||||
import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions'
|
||||
import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage'
|
||||
import { DOCS_URL } from 'lib/constants'
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
Card,
|
||||
CardContent,
|
||||
@@ -28,9 +33,13 @@ import {
|
||||
TabsContent_Shadcn_,
|
||||
TabsList_Shadcn_,
|
||||
TabsTrigger_Shadcn_,
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from 'ui'
|
||||
import { Admonition } from 'ui-patterns'
|
||||
import { TEMPLATES_SCHEMAS } from '../AuthTemplatesValidation'
|
||||
import EmailRateLimitsAlert from '../EmailRateLimitsAlert'
|
||||
import { EmailRateLimitsAlert } from '../EmailRateLimitsAlert'
|
||||
import { slugifyTitle } from './EmailTemplates.utils'
|
||||
import { TemplateEditor } from './TemplateEditor'
|
||||
|
||||
@@ -50,6 +59,10 @@ const NotificationsFormSchema = z.object({
|
||||
),
|
||||
})
|
||||
|
||||
const SECURITY_NOTIFICATIONS_DISCUSSIONS_URL = FEATURE_PREVIEWS.find(
|
||||
(f) => f.key === LOCAL_STORAGE_KEYS.UI_PREVIEW_SECURITY_NOTIFICATIONS
|
||||
)?.discussionsUrl
|
||||
|
||||
export const EmailTemplates = () => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const isSecurityNotificationsEnabled = useIsSecurityNotificationsEnabled()
|
||||
@@ -58,6 +71,11 @@ export const EmailTemplates = () => {
|
||||
'custom_config_gotrue'
|
||||
)
|
||||
|
||||
const [acknowledged, setAcknowledged] = useLocalStorageQuery(
|
||||
LOCAL_STORAGE_KEYS.SECURITY_NOTIFICATIONS_ACKNOWLEDGED(projectRef ?? ''),
|
||||
false
|
||||
)
|
||||
|
||||
const {
|
||||
data: authConfig,
|
||||
error: authConfigError,
|
||||
@@ -161,6 +179,60 @@ export const EmailTemplates = () => {
|
||||
|
||||
<div>
|
||||
<ScaffoldSectionTitle className="mb-4">Security</ScaffoldSectionTitle>
|
||||
{!acknowledged && (
|
||||
<Admonition showIcon={false} type="tip" className="relative mb-6">
|
||||
<Tooltip>
|
||||
<TooltipTrigger
|
||||
onClick={() => setAcknowledged(true)}
|
||||
className="absolute top-3 right-3 opacity-30 hover:opacity-100 transition-opacity"
|
||||
>
|
||||
<X size={14} className="text-foreground-light" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">Dismiss</TooltipContent>
|
||||
</Tooltip>
|
||||
<div className="flex flex-col md:flex-row md:items-center gap-y-2 md:gap-x-8 justify-between px-2 py-1">
|
||||
<div className="flex flex-col gap-y-0.5">
|
||||
<div className="flex flex-col gap-y-2 items-start">
|
||||
<Badge variant="success" className="-ml-0.5">
|
||||
NEW
|
||||
</Badge>
|
||||
<p className="text-sm">
|
||||
Notify users about security-sensitive actions on their accounts
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-sm text-foreground-lighter text-balance">
|
||||
We’ve expanded our email templates to handle security-sensitive actions.
|
||||
The list of templates will continue to grow as our feature-set changes
|
||||
{SECURITY_NOTIFICATIONS_DISCUSSIONS_URL && (
|
||||
<>
|
||||
{' '}
|
||||
and as we{' '}
|
||||
<InlineLink
|
||||
href={SECURITY_NOTIFICATIONS_DISCUSSIONS_URL}
|
||||
target="_blank"
|
||||
>
|
||||
gather feedback
|
||||
</InlineLink>{' '}
|
||||
from our community
|
||||
</>
|
||||
)}
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
asChild
|
||||
type="default"
|
||||
icon={<ExternalLink strokeWidth={1.5} />}
|
||||
className="mt-2"
|
||||
>
|
||||
<Link href={`${DOCS_URL}/guides/auth/auth-email-templates`} target="_blank">
|
||||
Docs
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</Admonition>
|
||||
)}
|
||||
|
||||
<Form_Shadcn_ {...notificationsForm}>
|
||||
<form onSubmit={notificationsForm.handleSubmit(onSubmit)} className="space-y-4">
|
||||
<Card>
|
||||
|
||||
@@ -206,7 +206,7 @@ export const ChartConfig = ({
|
||||
<Tooltip>
|
||||
<TooltipTrigger
|
||||
onClick={() => setAcknowledged(true)}
|
||||
className="absolute top-3 right-3 opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
className="absolute top-3 right-3 opacity-30 group-hover:opacity-100 transition-opacity"
|
||||
>
|
||||
<X size={14} className="text-foreground-light" />
|
||||
</TooltipTrigger>
|
||||
|
||||
@@ -234,7 +234,7 @@ const RedirectToTemplates = () => {
|
||||
<ScaffoldSection isFullWidth>
|
||||
{/* Only show title if there is an another section above */}
|
||||
{showConfigurationSection && (
|
||||
<ScaffoldSectionTitle className="mb-4">Contents</ScaffoldSectionTitle>
|
||||
<ScaffoldSectionTitle className="mb-4">Content</ScaffoldSectionTitle>
|
||||
)}
|
||||
<Card>
|
||||
<TemplateEditor template={template} />
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 124 KiB |
@@ -40,6 +40,10 @@ export const LOCAL_STORAGE_KEYS = {
|
||||
SQL_EDITOR_SECTION_STATE: (ref: string) => `sql-editor-section-state-${ref}`,
|
||||
SQL_EDITOR_SORT: (ref: string) => `sql-editor-sort-${ref}`,
|
||||
|
||||
// Key to track if the user has acknowledged the security notifications preview
|
||||
SECURITY_NOTIFICATIONS_ACKNOWLEDGED: (ref: string) =>
|
||||
`security-notifications-acknowledged-${ref}`,
|
||||
|
||||
LOG_EXPLORER_SPLIT_SIZE: 'supabase_log-explorer-split-size',
|
||||
GRAPHIQL_RLS_BYPASS_WARNING: 'graphiql-rls-bypass-warning-dismissed',
|
||||
CLS_DIFF_WARNING: 'cls-diff-warning-dismissed',
|
||||
|
||||
Reference in new issue
Block a user