Swap useCheckPermissions with useAsyncCheckProjectPermissions Part 5 (#38552)

Update auth pages
This commit is contained in:
Joshen Lim authored and GitHub committed 2025-09-09 22:07:55 +08:00
1 parent 8fb604c95b
commit e955f69e2d
20 files changed
+423 -411

No files matched your search

@@ -41,7 +41,7 @@ const schema = object({
SITE_URL: string().required('Must have a Site URL'),
})
const BasicAuthSettingsForm = () => {
export const BasicAuthSettingsForm = () => {
const { ref: projectRef } = useParams()
const showManualLinking = useIsFeatureEnabled('authentication:show_manual_linking')
@@ -333,5 +333,3 @@ const BasicAuthSettingsForm = () => {
</ScaffoldSection>
)
}
export default BasicAuthSettingsForm
@@ -7,7 +7,7 @@ import { TEMPLATES_SCHEMAS } from '../AuthTemplatesValidation'
import EmailRateLimitsAlert from '../EmailRateLimitsAlert'
import TemplateEditor from './TemplateEditor'
const EmailTemplates = () => {
export const EmailTemplates = () => {
const { ref: projectRef } = useParams()
const {
data: authConfig,
@@ -68,5 +68,3 @@ const EmailTemplates = () => {
</div>
)
}
export default EmailTemplates
@@ -3,7 +3,7 @@ import { PermissionAction } from '@supabase/shared-types/out/constants'
import { useEffect, useState } from 'react'
import { useForm } from 'react-hook-form'
import { toast } from 'sonner'
import { number, object, string, boolean } from 'yup'
import { boolean, number, object, string } from 'yup'
import { useParams } from 'common'
import { ScaffoldSection, ScaffoldSectionTitle } from 'components/layouts/Scaffold'
@@ -35,8 +35,8 @@ import {
Switch,
WarningIcon,
} from 'ui'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
function determineMFAStatus(verifyEnabled: boolean, enrollEnabled: boolean) {
return verifyEnabled ? (enrollEnabled ? 'Enabled' : 'Verify Enabled') : 'Disabled'
@@ -84,7 +84,7 @@ const securitySchema = object({
MFA_ALLOW_LOW_AAL: boolean().required(),
})
const MfaAuthSettingsForm = () => {
export const MfaAuthSettingsForm = () => {
const { ref: projectRef } = useParams()
const { data: authConfig, error: authConfigError, isError } = useAuthConfigQuery({ projectRef })
const { mutate: updateAuthConfig } = useAuthConfigUpdateMutation()
@@ -572,5 +572,3 @@ const MfaAuthSettingsForm = () => {
</>
)
}
export default MfaAuthSettingsForm
@@ -67,7 +67,7 @@ const schema = object({
PASSWORD_HIBP_ENABLED: boolean(),
})
const ProtectionAuthSettingsForm = () => {
export const ProtectionAuthSettingsForm = () => {
const { ref: projectRef } = useParams()
const { data: authConfig, error: authConfigError, isError } = useAuthConfigQuery({ projectRef })
const { mutate: updateAuthConfig, isLoading: isUpdatingConfig } = useAuthConfigUpdateMutation({
@@ -287,5 +287,3 @@ const ProtectionAuthSettingsForm = () => {
</ScaffoldSection>
)
}
export default ProtectionAuthSettingsForm
@@ -30,7 +30,7 @@ import {
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
import { isSmtpEnabled } from '../SmtpForm/SmtpForm.utils'
const RateLimits = () => {
export const RateLimits = () => {
const { ref: projectRef } = useParams()
const { can: canUpdateConfig } = useAsyncCheckProjectPermissions(
PermissionAction.UPDATE,
@@ -505,5 +505,3 @@ const RateLimits = () => {
</ScaffoldSection>
)
}
export default RateLimits
@@ -59,7 +59,7 @@ const UserSessionsSchema = z.object({
SESSIONS_SINGLE_PER_USER: z.boolean(),
})
const SessionsAuthSettingsForm = () => {
export const SessionsAuthSettingsForm = () => {
const { ref: projectRef } = useParams()
const { data: authConfig, error: authConfigError, isError } = useAuthConfigQuery({ projectRef })
const { mutate: updateAuthConfig } = useAuthConfigUpdateMutation()
@@ -370,5 +370,3 @@ const SessionsAuthSettingsForm = () => {
</>
)
}
export default SessionsAuthSettingsForm
@@ -8,7 +8,7 @@ import { toast } from 'sonner'
import * as yup from 'yup'
import { useParams } from 'common'
import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold'
import { ScaffoldSection } from 'components/layouts/Scaffold'
import NoPermission from 'components/ui/NoPermission'
import { useAuthConfigQuery } from 'data/auth/auth-config-query'
import { useAuthConfigUpdateMutation } from 'data/auth/auth-config-update-mutation'
@@ -45,7 +45,7 @@ interface SmtpFormValues {
ENABLE_SMTP: boolean
}
const SmtpForm = () => {
export const SmtpForm = () => {
const { ref: projectRef } = useParams()
const { data: authConfig, error: authConfigError, isError } = useAuthConfigQuery({ projectRef })
const { mutate: updateAuthConfig, isLoading: isUpdatingConfig } = useAuthConfigUpdateMutation()
@@ -192,285 +192,280 @@ const SmtpForm = () => {
}
return (
<ScaffoldContainer>
<ScaffoldSection isFullWidth>
<Form_Shadcn_ {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<Card>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="ENABLE_SMTP"
render={({ field }) => (
<FormItemLayout
layout="flex-row-reverse"
label="Enable Custom SMTP"
description={
<p className="max-w-full prose text-sm text-foreground-lighter">
Emails will be sent using your custom SMTP provider. Email rate limits can
be adjusted{' '}
<Link
className="underline"
href={`/project/${projectRef}/auth/rate-limits`}
>
here
</Link>
.
</p>
}
>
<FormControl_Shadcn_>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
disabled={!canUpdateConfig}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
{enableSmtp && !isSmtpEnabled(form.getValues() as any) && (
<div className="mt-4">
<Alert_Shadcn_ variant="warning">
<AlertTriangle strokeWidth={2} />
<AlertTitle_Shadcn_>All fields below must be filled</AlertTitle_Shadcn_>
<AlertDescription_Shadcn_>
The following fields must be filled before custom SMTP can be properly
enabled
</AlertDescription_Shadcn_>
</Alert_Shadcn_>
</div>
<ScaffoldSection isFullWidth>
<Form_Shadcn_ {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<Card>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="ENABLE_SMTP"
render={({ field }) => (
<FormItemLayout
layout="flex-row-reverse"
label="Enable Custom SMTP"
description={
<p className="max-w-full prose text-sm text-foreground-lighter">
Emails will be sent using your custom SMTP provider. Email rate limits can
be adjusted{' '}
<Link
className="underline"
href={`/project/${projectRef}/auth/rate-limits`}
>
here
</Link>
.
</p>
}
>
<FormControl_Shadcn_>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
disabled={!canUpdateConfig}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
</CardContent>
/>
{enableSmtp && (
<>
<CardContent className="py-6">
<div className="grid grid-cols-12 gap-6">
<div className="col-span-4">
<h3 className="text-sm mb-1">Sender details</h3>
<p className="text-sm text-foreground-lighter">
Configure the sender information for your emails.
</p>
</div>
<div className="col-span-8 space-y-4">
<FormField_Shadcn_
control={form.control}
name="SMTP_ADMIN_EMAIL"
render={({ field }) => (
<FormItemLayout
label="Sender email"
description="This is the email address the emails are sent from"
>
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
placeholder="noreply@yourdomain.com"
disabled={!canUpdateConfig}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
{enableSmtp && !isSmtpEnabled(form.getValues() as any) && (
<div className="mt-4">
<Alert_Shadcn_ variant="warning">
<AlertTriangle strokeWidth={2} />
<AlertTitle_Shadcn_>All fields below must be filled</AlertTitle_Shadcn_>
<AlertDescription_Shadcn_>
The following fields must be filled before custom SMTP can be properly enabled
</AlertDescription_Shadcn_>
</Alert_Shadcn_>
</div>
)}
</CardContent>
<FormField_Shadcn_
control={form.control}
name="SMTP_SENDER_NAME"
render={({ field }) => (
<FormItemLayout
label="Sender name"
description="Name displayed in the recipient's inbox"
>
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
placeholder="The name shown on the email"
disabled={!canUpdateConfig}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
</div>
{enableSmtp && (
<>
<CardContent className="py-6">
<div className="grid grid-cols-12 gap-6">
<div className="col-span-4">
<h3 className="text-sm mb-1">Sender details</h3>
<p className="text-sm text-foreground-lighter">
Configure the sender information for your emails.
</p>
</div>
</CardContent>
<CardContent className="py-6">
<div className="grid grid-cols-12 gap-6">
<div className="col-span-4">
<h3 className="text-sm mb-1">SMTP Provider Settings</h3>
<p className="text-sm text-foreground-lighter">
Your SMTP Credentials will always be encrypted in our database.
</p>
</div>
<div className="col-span-8 space-y-4">
{form.watch('SMTP_HOST')?.endsWith('.gmail.com') && (
<Alert_Shadcn_ variant="warning" className="mb-4">
<AlertTriangle strokeWidth={2} />
<AlertTitle_Shadcn_>Check your SMTP provider</AlertTitle_Shadcn_>
<AlertDescription_Shadcn_>
Not all SMTP providers are designed for the email sending required by
Supabase Auth. It looks like the SMTP provider you entered is designed
for sending personal email messages and not for sending transactional
messages. Although you can ignore this warning, email deliverability
may be impacted.
</AlertDescription_Shadcn_>
</Alert_Shadcn_>
<div className="col-span-8 space-y-4">
<FormField_Shadcn_
control={form.control}
name="SMTP_ADMIN_EMAIL"
render={({ field }) => (
<FormItemLayout
label="Sender email"
description="This is the email address the emails are sent from"
>
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
placeholder="noreply@yourdomain.com"
disabled={!canUpdateConfig}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<FormField_Shadcn_
control={form.control}
name="SMTP_HOST"
render={({ field }) => (
<FormItemLayout
label="Host"
description="Hostname or IP address of your SMTP server."
>
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
placeholder="your.smtp.host.com"
disabled={!canUpdateConfig}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<FormField_Shadcn_
control={form.control}
name="SMTP_SENDER_NAME"
render={({ field }) => (
<FormItemLayout
label="Sender name"
description="Name displayed in the recipient's inbox"
>
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
placeholder="The name shown on the email"
disabled={!canUpdateConfig}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
</div>
</div>
</CardContent>
<FormField_Shadcn_
control={form.control}
name="SMTP_PORT"
render={({ field }) => (
<FormItemLayout
label="Port number"
description={
<>
<span className="block">
Port used by your SMTP server. Common ports include 25, 465, and
587.{' '}
</span>
<span className="mt-2 block">
Avoid using port 25 as modern SMTP email clients shouldn't use
this port, it is traditionally blocked by residential ISPs and
Cloud Hosting Providers, to curb the amount of spam.
</span>
</>
}
>
<FormControl_Shadcn_>
<CardContent className="py-6">
<div className="grid grid-cols-12 gap-6">
<div className="col-span-4">
<h3 className="text-sm mb-1">SMTP Provider Settings</h3>
<p className="text-sm text-foreground-lighter">
Your SMTP Credentials will always be encrypted in our database.
</p>
</div>
<div className="col-span-8 space-y-4">
{form.watch('SMTP_HOST')?.endsWith('.gmail.com') && (
<Alert_Shadcn_ variant="warning" className="mb-4">
<AlertTriangle strokeWidth={2} />
<AlertTitle_Shadcn_>Check your SMTP provider</AlertTitle_Shadcn_>
<AlertDescription_Shadcn_>
Not all SMTP providers are designed for the email sending required by
Supabase Auth. It looks like the SMTP provider you entered is designed
for sending personal email messages and not for sending transactional
messages. Although you can ignore this warning, email deliverability may
be impacted.
</AlertDescription_Shadcn_>
</Alert_Shadcn_>
)}
<FormField_Shadcn_
control={form.control}
name="SMTP_HOST"
render={({ field }) => (
<FormItemLayout
label="Host"
description="Hostname or IP address of your SMTP server."
>
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
placeholder="your.smtp.host.com"
disabled={!canUpdateConfig}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<FormField_Shadcn_
control={form.control}
name="SMTP_PORT"
render={({ field }) => (
<FormItemLayout
label="Port number"
description={
<>
<span className="block">
Port used by your SMTP server. Common ports include 25, 465, and
587.{' '}
</span>
<span className="mt-2 block">
Avoid using port 25 as modern SMTP email clients shouldn't use
this port, it is traditionally blocked by residential ISPs and
Cloud Hosting Providers, to curb the amount of spam.
</span>
</>
}
>
<FormControl_Shadcn_>
<Input_Shadcn_
type="number"
value={field.value}
onChange={(e) => field.onChange(Number(e.target.value))}
placeholder="587"
disabled={!canUpdateConfig}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<FormField_Shadcn_
control={form.control}
name="SMTP_MAX_FREQUENCY"
render={({ field }) => (
<FormItemLayout
label="Minimum interval between emails being sent"
description="How long between each email can a new email be sent via your SMTP server."
>
<FormControl_Shadcn_>
<PrePostTab postTab="seconds">
<Input_Shadcn_
type="number"
value={field.value}
onChange={(e) => field.onChange(Number(e.target.value))}
placeholder="587"
disabled={!canUpdateConfig}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
</PrePostTab>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<FormField_Shadcn_
control={form.control}
name="SMTP_MAX_FREQUENCY"
render={({ field }) => (
<FormItemLayout
label="Minimum interval between emails being sent"
description="How long between each email can a new email be sent via your SMTP server."
>
<FormControl_Shadcn_>
<PrePostTab postTab="seconds">
<Input_Shadcn_
type="number"
value={field.value}
onChange={(e) => field.onChange(Number(e.target.value))}
disabled={!canUpdateConfig}
<FormField_Shadcn_
control={form.control}
name="SMTP_USER"
render={({ field }) => (
<FormItemLayout
label="Username"
description="Username for your SMTP server"
>
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
placeholder="SMTP Username"
disabled={!canUpdateConfig}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<FormField_Shadcn_
control={form.control}
name="SMTP_PASS"
render={({ field }) => (
<FormItemLayout
label="Password"
description="For security reasons, the password is write-only. Once saved, it cannot be retrieved or displayed."
>
<FormControl_Shadcn_>
<PrePostTab
postTab={
<Button
type="text"
className="p-0"
onClick={() => setHidden(!hidden)}
icon={hidden ? <Eye /> : <EyeOff />}
/>
</PrePostTab>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<FormField_Shadcn_
control={form.control}
name="SMTP_USER"
render={({ field }) => (
<FormItemLayout
label="Username"
description="Username for your SMTP server"
>
<FormControl_Shadcn_>
}
>
<Input_Shadcn_
{...field}
placeholder="SMTP Username"
type={hidden ? 'password' : 'text'}
placeholder={
authConfig?.SMTP_PASS === null ? 'SMTP Password' : '••••••••'
}
disabled={!canUpdateConfig}
/>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
<FormField_Shadcn_
control={form.control}
name="SMTP_PASS"
render={({ field }) => (
<FormItemLayout
label="Password"
description="For security reasons, the password is write-only. Once saved, it cannot be retrieved or displayed."
>
<FormControl_Shadcn_>
<PrePostTab
postTab={
<Button
type="text"
className="p-0"
onClick={() => setHidden(!hidden)}
icon={hidden ? <Eye /> : <EyeOff />}
/>
}
>
<Input_Shadcn_
{...field}
type={hidden ? 'password' : 'text'}
placeholder={
authConfig?.SMTP_PASS === null ? 'SMTP Password' : '••••••••'
}
disabled={!canUpdateConfig}
/>
</PrePostTab>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
</div>
</PrePostTab>
</FormControl_Shadcn_>
</FormItemLayout>
)}
/>
</div>
</CardContent>
</>
)}
</div>
</CardContent>
</>
)}
<CardFooter className="justify-end space-x-2">
{form.formState.isDirty && (
<Button type="default" onClick={() => form.reset()}>
Cancel
</Button>
)}
<Button
type="primary"
htmlType="submit"
loading={isUpdatingConfig}
disabled={!canUpdateConfig || !form.formState.isDirty}
>
Save changes
<CardFooter className="justify-end space-x-2">
{form.formState.isDirty && (
<Button type="default" onClick={() => form.reset()}>
Cancel
</Button>
</CardFooter>
</Card>
</form>
</Form_Shadcn_>
</ScaffoldSection>
</ScaffoldContainer>
)}
<Button
type="primary"
htmlType="submit"
loading={isUpdatingConfig}
disabled={!canUpdateConfig || !form.formState.isDirty}
>
Save changes
</Button>
</CardFooter>
</Card>
</form>
</Form_Shadcn_>
</ScaffoldSection>
)
}
export default SmtpForm
@@ -1,9 +0,0 @@
export { AdvancedAuthSettingsForm } from './AdvancedAuthSettingsForm'
export { AuthProvidersForm } from './AuthProvidersForm/AuthProvidersForm'
export { default as BasicAuthSettingsForm } from './BasicAuthSettingsForm/BasicAuthSettingsForm'
export { default as EmailTemplates } from './EmailTemplates/EmailTemplates'
export { default as MfaAuthSettingsForm } from './MfaAuthSettingsForm/MfaAuthSettingsForm'
export { default as ProtectionAuthSettingsForm } from './ProtectionAuthSettingsForm/ProtectionAuthSettingsForm'
export { default as SessionsAuthSettingsForm } from './SessionsAuthSettingsForm/SessionsAuthSettingsForm'
export { default as SmtpForm } from './SmtpForm/SmtpForm'
export { ThirdPartyAuthForm } from './ThirdPartyAuthForm'
@@ -9,7 +9,7 @@ import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold'
import NoPermission from 'components/ui/NoPermission'
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { UnknownInterface } from 'components/ui/UnknownInterface'
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
import { useAsyncCheckProjectPermissions } from 'hooks/misc/useCheckPermissions'
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
import type { NextPageWithLayout } from 'types'
@@ -17,35 +17,37 @@ const AdvancedPage: NextPageWithLayout = () => {
const { ref } = useParams()
const showAdvanced = useIsFeatureEnabled('authentication:advanced')
const isPermissionsLoaded = usePermissionsLoaded()
const canReadAuthSettings = useCheckPermissions(PermissionAction.READ, 'custom_config_gotrue')
const { can: canReadAuthSettings, isSuccess: isPermissionsLoaded } =
useAsyncCheckProjectPermissions(PermissionAction.READ, 'custom_config_gotrue')
if (!showAdvanced) {
return <UnknownInterface urlBack={`/project/${ref}/auth/users`} />
}
if (isPermissionsLoaded && !canReadAuthSettings) {
return <NoPermission isFullPage resourceText="access your project's authentication settings" />
}
return (
<PageLayout title="Advanced" subtitle="Configure advanced authentication server settings">
{isPermissionsLoaded && !canReadAuthSettings ? (
<NoPermission isFullPage resourceText="access your project's authentication settings" />
<ScaffoldContainer>
{!isPermissionsLoaded ? (
<ScaffoldSection isFullWidth>
<GenericSkeletonLoader />
</ScaffoldSection>
) : (
<ScaffoldContainer>
{!isPermissionsLoaded ? (
<ScaffoldSection isFullWidth>
<GenericSkeletonLoader />
</ScaffoldSection>
) : (
<AdvancedAuthSettingsForm />
)}
</ScaffoldContainer>
<AdvancedAuthSettingsForm />
)}
</PageLayout>
</ScaffoldContainer>
)
}
AdvancedPage.getLayout = (page) => (
<DefaultLayout>
<AuthLayout>{page}</AuthLayout>
<AuthLayout>
<PageLayout title="Advanced" subtitle="Configure advanced authentication server settings">
{page}
</PageLayout>
</AuthLayout>
</DefaultLayout>
)
+14 -7
View File
@@ -4,15 +4,16 @@ import { HooksListing } from 'components/interfaces/Auth/Hooks/HooksListing'
import AuthLayout from 'components/layouts/AuthLayout/AuthLayout'
import DefaultLayout from 'components/layouts/DefaultLayout'
import { PageLayout } from 'components/layouts/PageLayout/PageLayout'
import { ScaffoldContainer } from 'components/layouts/Scaffold'
import NoPermission from 'components/ui/NoPermission'
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
import type { NextPageWithLayout } from 'types'
import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold'
import { DocsButton } from 'components/ui/DocsButton'
import NoPermission from 'components/ui/NoPermission'
import { useAsyncCheckProjectPermissions } from 'hooks/misc/useCheckPermissions'
import type { NextPageWithLayout } from 'types'
import { GenericSkeletonLoader } from 'ui-patterns'
const Hooks: NextPageWithLayout = () => {
const canReadAuthSettings = useCheckPermissions(PermissionAction.READ, 'custom_config_gotrue')
const isPermissionsLoaded = usePermissionsLoaded()
const { can: canReadAuthSettings, isSuccess: isPermissionsLoaded } =
useAsyncCheckProjectPermissions(PermissionAction.READ, 'custom_config_gotrue')
if (isPermissionsLoaded && !canReadAuthSettings) {
return <NoPermission isFullPage resourceText="access your project's auth hooks" />
@@ -20,7 +21,13 @@ const Hooks: NextPageWithLayout = () => {
return (
<ScaffoldContainer>
<HooksListing />
{!isPermissionsLoaded ? (
<ScaffoldSection isFullWidth>
<GenericSkeletonLoader />
</ScaffoldSection>
) : (
<HooksListing />
)}
</ScaffoldContainer>
)
}
+23 -21
View File
@@ -1,7 +1,7 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { useParams } from 'common'
import { MfaAuthSettingsForm } from 'components/interfaces/Auth'
import { MfaAuthSettingsForm } from 'components/interfaces/Auth/MfaAuthSettingsForm/MfaAuthSettingsForm'
import AuthLayout from 'components/layouts/AuthLayout/AuthLayout'
import DefaultLayout from 'components/layouts/DefaultLayout'
import { PageLayout } from 'components/layouts/PageLayout/PageLayout'
@@ -9,7 +9,7 @@ import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold'
import NoPermission from 'components/ui/NoPermission'
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { UnknownInterface } from 'components/ui/UnknownInterface'
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
import { useAsyncCheckProjectPermissions } from 'hooks/misc/useCheckPermissions'
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
import type { NextPageWithLayout } from 'types'
@@ -17,38 +17,40 @@ const MfaPage: NextPageWithLayout = () => {
const { ref } = useParams()
const showMFA = useIsFeatureEnabled('authentication:multi_factor')
const isPermissionsLoaded = usePermissionsLoaded()
const canReadAuthSettings = useCheckPermissions(PermissionAction.READ, 'custom_config_gotrue')
const { can: canReadAuthSettings, isSuccess: isPermissionsLoaded } =
useAsyncCheckProjectPermissions(PermissionAction.READ, 'custom_config_gotrue')
if (!showMFA) {
return <UnknownInterface urlBack={`/project/${ref}/auth/users`} />
}
if (isPermissionsLoaded && !canReadAuthSettings) {
return <NoPermission isFullPage resourceText="access your project's authentication settings" />
}
return (
<PageLayout
title="Multi-Factor Authentication (MFA)"
subtitle="Requires users to provide additional verification factors to authenticate"
>
{isPermissionsLoaded && !canReadAuthSettings ? (
<NoPermission isFullPage resourceText="access your project's authentication settings" />
<ScaffoldContainer>
{!isPermissionsLoaded ? (
<ScaffoldSection isFullWidth>
<GenericSkeletonLoader />
</ScaffoldSection>
) : (
<ScaffoldContainer>
{!isPermissionsLoaded ? (
<ScaffoldSection isFullWidth>
<GenericSkeletonLoader />
</ScaffoldSection>
) : (
<MfaAuthSettingsForm />
)}
</ScaffoldContainer>
<MfaAuthSettingsForm />
)}
</PageLayout>
</ScaffoldContainer>
)
}
MfaPage.getLayout = (page) => (
<DefaultLayout>
<AuthLayout>{page}</AuthLayout>
<AuthLayout>
<PageLayout
title="Multi-Factor Authentication (MFA)"
subtitle="Requires users to provide additional verification factors to authenticate"
>
{page}
</PageLayout>
</AuthLayout>
</DefaultLayout>
)
@@ -20,7 +20,7 @@ import SchemaSelector from 'components/ui/SchemaSelector'
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { useDatabasePoliciesQuery } from 'data/database-policies/database-policies-query'
import { useTablesQuery } from 'data/tables/tables-query'
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
import { useAsyncCheckProjectPermissions } from 'hooks/misc/useCheckPermissions'
import { useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { useUrlState } from 'hooks/ui/useUrlState'
import { useIsProtectedSchema } from 'hooks/useProtectedSchemas'
@@ -98,8 +98,10 @@ const AuthPoliciesPage: NextPageWithLayout = () => {
})
const filteredTables = onFilterTables(tables ?? [], policies ?? [], searchString)
const canReadPolicies = useCheckPermissions(PermissionAction.TENANT_SQL_ADMIN_READ, 'policies')
const isPermissionsLoaded = usePermissionsLoaded()
const { can: canReadPolicies, isSuccess: isPermissionsLoaded } = useAsyncCheckProjectPermissions(
PermissionAction.TENANT_SQL_ADMIN_READ,
'policies'
)
if (isPermissionsLoaded && !canReadPolicies) {
return <NoPermission isFullPage resourceText="view this project's RLS policies" />
@@ -1,7 +1,7 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { useParams } from 'common'
import { ProtectionAuthSettingsForm } from 'components/interfaces/Auth'
import { ProtectionAuthSettingsForm } from 'components/interfaces/Auth/ProtectionAuthSettingsForm/ProtectionAuthSettingsForm'
import AuthLayout from 'components/layouts/AuthLayout/AuthLayout'
import DefaultLayout from 'components/layouts/DefaultLayout'
import { PageLayout } from 'components/layouts/PageLayout/PageLayout'
@@ -9,7 +9,7 @@ import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold'
import NoPermission from 'components/ui/NoPermission'
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { UnknownInterface } from 'components/ui/UnknownInterface'
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
import { useAsyncCheckProjectPermissions } from 'hooks/misc/useCheckPermissions'
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
import type { NextPageWithLayout } from 'types'
@@ -17,38 +17,40 @@ const ProtectionPage: NextPageWithLayout = () => {
const { ref } = useParams()
const showAttackProtection = useIsFeatureEnabled('authentication:attack_protection')
const isPermissionsLoaded = usePermissionsLoaded()
const canReadAuthSettings = useCheckPermissions(PermissionAction.READ, 'custom_config_gotrue')
const { can: canReadAuthSettings, isSuccess: isPermissionsLoaded } =
useAsyncCheckProjectPermissions(PermissionAction.READ, 'custom_config_gotrue')
if (!showAttackProtection) {
return <UnknownInterface urlBack={`/project/${ref}/auth/users`} />
}
if (isPermissionsLoaded && !canReadAuthSettings) {
return <NoPermission isFullPage resourceText="access your project's auth provider settings" />
}
return (
<PageLayout
title="Attack Protection"
subtitle="Configure security settings to protect your project from attacks"
>
{isPermissionsLoaded && !canReadAuthSettings ? (
<NoPermission isFullPage resourceText="access your project's auth provider settings" />
<ScaffoldContainer>
{!isPermissionsLoaded ? (
<ScaffoldSection isFullWidth>
<GenericSkeletonLoader />
</ScaffoldSection>
) : (
<ScaffoldContainer>
{!isPermissionsLoaded ? (
<ScaffoldSection isFullWidth>
<GenericSkeletonLoader />
</ScaffoldSection>
) : (
<ProtectionAuthSettingsForm />
)}
</ScaffoldContainer>
<ProtectionAuthSettingsForm />
)}
</PageLayout>
</ScaffoldContainer>
)
}
ProtectionPage.getLayout = (page) => (
<DefaultLayout>
<AuthLayout>{page}</AuthLayout>
<AuthLayout>
<PageLayout
title="Attack Protection"
subtitle="Configure security settings to protect your project from attacks"
>
{page}
</PageLayout>
</AuthLayout>
</DefaultLayout>
)
@@ -1,4 +1,5 @@
import { AuthProvidersForm, BasicAuthSettingsForm } from 'components/interfaces/Auth'
import { AuthProvidersForm } from 'components/interfaces/Auth/AuthProvidersForm/AuthProvidersForm'
import { BasicAuthSettingsForm } from 'components/interfaces/Auth/BasicAuthSettingsForm/BasicAuthSettingsForm'
import { AuthProvidersLayout } from 'components/layouts/AuthLayout/AuthProvidersLayout'
import DefaultLayout from 'components/layouts/DefaultLayout'
import { ScaffoldContainer } from 'components/layouts/Scaffold'
@@ -1,7 +1,7 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { useParams } from 'common'
import RateLimits from 'components/interfaces/Auth/RateLimits/RateLimits'
import { RateLimits } from 'components/interfaces/Auth/RateLimits/RateLimits'
import AuthLayout from 'components/layouts/AuthLayout/AuthLayout'
import DefaultLayout from 'components/layouts/DefaultLayout'
import { PageLayout } from 'components/layouts/PageLayout/PageLayout'
@@ -10,7 +10,7 @@ import { DocsButton } from 'components/ui/DocsButton'
import NoPermission from 'components/ui/NoPermission'
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { UnknownInterface } from 'components/ui/UnknownInterface'
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
import { useAsyncCheckProjectPermissions } from 'hooks/misc/useCheckPermissions'
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
import type { NextPageWithLayout } from 'types'
@@ -18,41 +18,43 @@ const RateLimitsPage: NextPageWithLayout = () => {
const { ref } = useParams()
const showRateLimits = useIsFeatureEnabled('authentication:rate_limits')
const isPermissionsLoaded = usePermissionsLoaded()
const canReadAuthSettings = useCheckPermissions(PermissionAction.READ, 'custom_config_gotrue')
const { can: canReadAuthSettings, isSuccess: isPermissionsLoaded } =
useAsyncCheckProjectPermissions(PermissionAction.READ, 'custom_config_gotrue')
if (!showRateLimits) {
return <UnknownInterface urlBack={`/project/${ref}/auth/users`} />
}
if (isPermissionsLoaded && !canReadAuthSettings) {
return <NoPermission isFullPage resourceText="access your project's auth rate limit settings" />
}
return (
<PageLayout
title="Rate Limits"
subtitle="Safeguard against bursts of incoming traffic to prevent abuse and maximize stability"
primaryActions={
<DocsButton href="https://supabase.com/docs/guides/platform/going-into-prod#rate-limiting-resource-allocation--abuse-prevention" />
}
>
{isPermissionsLoaded && !canReadAuthSettings ? (
<NoPermission isFullPage resourceText="access your project's auth rate limit settings" />
<ScaffoldContainer>
{!isPermissionsLoaded ? (
<ScaffoldSection isFullWidth>
<GenericSkeletonLoader />
</ScaffoldSection>
) : (
<ScaffoldContainer>
{!isPermissionsLoaded ? (
<ScaffoldSection isFullWidth>
<GenericSkeletonLoader />
</ScaffoldSection>
) : (
<RateLimits />
)}
</ScaffoldContainer>
<RateLimits />
)}
</PageLayout>
</ScaffoldContainer>
)
}
RateLimitsPage.getLayout = (page) => (
<DefaultLayout>
<AuthLayout>{page}</AuthLayout>
<AuthLayout>
<PageLayout
title="Rate Limits"
subtitle="Safeguard against bursts of incoming traffic to prevent abuse and maximize stability"
primaryActions={
<DocsButton href="https://supabase.com/docs/guides/platform/going-into-prod#rate-limiting-resource-allocation--abuse-prevention" />
}
>
{page}
</PageLayout>
</AuthLayout>
</DefaultLayout>
)
@@ -1,18 +1,18 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { SessionsAuthSettingsForm } from 'components/interfaces/Auth'
import { SessionsAuthSettingsForm } from 'components/interfaces/Auth/SessionsAuthSettingsForm/SessionsAuthSettingsForm'
import AuthLayout from 'components/layouts/AuthLayout/AuthLayout'
import DefaultLayout from 'components/layouts/DefaultLayout'
import { PageLayout } from 'components/layouts/PageLayout/PageLayout'
import { ScaffoldContainer } from 'components/layouts/Scaffold'
import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold'
import NoPermission from 'components/ui/NoPermission'
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
import { useAsyncCheckProjectPermissions } from 'hooks/misc/useCheckPermissions'
import type { NextPageWithLayout } from 'types'
const SessionsPage: NextPageWithLayout = () => {
const isPermissionsLoaded = usePermissionsLoaded()
const canReadAuthSettings = useCheckPermissions(PermissionAction.READ, 'custom_config_gotrue')
const { can: canReadAuthSettings, isSuccess: isPermissionsLoaded } =
useAsyncCheckProjectPermissions(PermissionAction.READ, 'custom_config_gotrue')
if (isPermissionsLoaded && !canReadAuthSettings) {
return <NoPermission isFullPage resourceText="access your project's authentication settings" />
@@ -21,9 +21,9 @@ const SessionsPage: NextPageWithLayout = () => {
return (
<ScaffoldContainer>
{!isPermissionsLoaded ? (
<div className="mt-12">
<ScaffoldSection isFullWidth>
<GenericSkeletonLoader />
</div>
</ScaffoldSection>
) : (
<SessionsAuthSettingsForm />
)}
+17 -5
View File
@@ -1,21 +1,33 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { SmtpForm } from 'components/interfaces/Auth'
import { SmtpForm } from 'components/interfaces/Auth/SmtpForm/SmtpForm'
import { AuthEmailsLayout } from 'components/layouts/AuthLayout/AuthEmailsLayout'
import DefaultLayout from 'components/layouts/DefaultLayout'
import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold'
import NoPermission from 'components/ui/NoPermission'
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
import { useAsyncCheckProjectPermissions } from 'hooks/misc/useCheckPermissions'
import type { NextPageWithLayout } from 'types'
import { GenericSkeletonLoader } from 'ui-patterns'
const SmtpPage: NextPageWithLayout = () => {
const canReadAuthSettings = useCheckPermissions(PermissionAction.READ, 'custom_config_gotrue')
const isPermissionsLoaded = usePermissionsLoaded()
const { can: canReadAuthSettings, isSuccess: isPermissionsLoaded } =
useAsyncCheckProjectPermissions(PermissionAction.READ, 'custom_config_gotrue')
if (isPermissionsLoaded && !canReadAuthSettings) {
return <NoPermission isFullPage resourceText="access your project's email settings" />
}
return <SmtpForm />
return (
<ScaffoldContainer>
{!isPermissionsLoaded ? (
<ScaffoldSection isFullWidth>
<GenericSkeletonLoader />
</ScaffoldSection>
) : (
<SmtpForm />
)}
</ScaffoldContainer>
)
}
SmtpPage.getLayout = (page) => (
@@ -1,15 +1,17 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { EmailTemplates } from 'components/interfaces/Auth'
import { EmailTemplates } from 'components/interfaces/Auth/EmailTemplates/EmailTemplates'
import { AuthEmailsLayout } from 'components/layouts/AuthLayout/AuthEmailsLayout'
import DefaultLayout from 'components/layouts/DefaultLayout'
import { ScaffoldContainer } from 'components/layouts/Scaffold'
import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold'
import NoPermission from 'components/ui/NoPermission'
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
import { useAsyncCheckProjectPermissions } from 'hooks/misc/useCheckPermissions'
import type { NextPageWithLayout } from 'types'
import { GenericSkeletonLoader } from 'ui-patterns'
const TemplatesPage: NextPageWithLayout = () => {
const canReadAuthSettings = useCheckPermissions(PermissionAction.READ, 'custom_config_gotrue')
const isPermissionsLoaded = usePermissionsLoaded()
const { can: canReadAuthSettings, isSuccess: isPermissionsLoaded } =
useAsyncCheckProjectPermissions(PermissionAction.READ, 'custom_config_gotrue')
if (isPermissionsLoaded && !canReadAuthSettings) {
return <NoPermission isFullPage resourceText="access your project's email settings" />
@@ -17,7 +19,13 @@ const TemplatesPage: NextPageWithLayout = () => {
return (
<ScaffoldContainer>
<EmailTemplates />
{!isPermissionsLoaded ? (
<ScaffoldSection isFullWidth>
<GenericSkeletonLoader />
</ScaffoldSection>
) : (
<EmailTemplates />
)}
</ScaffoldContainer>
)
}
@@ -1,21 +1,21 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { useParams } from 'common'
import { ThirdPartyAuthForm } from 'components/interfaces/Auth'
import { ThirdPartyAuthForm } from 'components/interfaces/Auth/ThirdPartyAuthForm'
import AuthLayout from 'components/layouts/AuthLayout/AuthLayout'
import { AuthProvidersLayout } from 'components/layouts/AuthLayout/AuthProvidersLayout'
import DefaultLayout from 'components/layouts/DefaultLayout'
import { ScaffoldContainer } from 'components/layouts/Scaffold'
import NoPermission from 'components/ui/NoPermission'
import { UnknownInterface } from 'components/ui/UnknownInterface'
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
import { useAsyncCheckProjectPermissions } from 'hooks/misc/useCheckPermissions'
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
import type { NextPageWithLayout } from 'types'
const ThirdPartyPage: NextPageWithLayout = () => {
const { ref } = useParams()
const canReadAuthSettings = useCheckPermissions(PermissionAction.READ, 'custom_config_gotrue')
const isPermissionsLoaded = usePermissionsLoaded()
const { can: canReadAuthSettings, isSuccess: isPermissionsLoaded } =
useAsyncCheckProjectPermissions(PermissionAction.READ, 'custom_config_gotrue')
const showThirdPartyAuth = useIsFeatureEnabled('authentication:third_party_auth')
@@ -5,15 +5,15 @@ import SiteUrl from 'components/interfaces/Auth/SiteUrl/SiteUrl'
import AuthLayout from 'components/layouts/AuthLayout/AuthLayout'
import DefaultLayout from 'components/layouts/DefaultLayout'
import { PageLayout } from 'components/layouts/PageLayout/PageLayout'
import { ScaffoldContainer } from 'components/layouts/Scaffold'
import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold'
import NoPermission from 'components/ui/NoPermission'
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
import { useAsyncCheckProjectPermissions } from 'hooks/misc/useCheckPermissions'
import type { NextPageWithLayout } from 'types'
const URLConfiguration: NextPageWithLayout = () => {
const isPermissionsLoaded = usePermissionsLoaded()
const canReadAuthSettings = useCheckPermissions(PermissionAction.READ, 'custom_config_gotrue')
const { can: canReadAuthSettings, isSuccess: isPermissionsLoaded } =
useAsyncCheckProjectPermissions(PermissionAction.READ, 'custom_config_gotrue')
if (isPermissionsLoaded && !canReadAuthSettings) {
return <NoPermission isFullPage resourceText="access your project's authentication settings" />
@@ -22,9 +22,9 @@ const URLConfiguration: NextPageWithLayout = () => {
return (
<ScaffoldContainer>
{!isPermissionsLoaded ? (
<div className="mt-12">
<ScaffoldSection isFullWidth>
<GenericSkeletonLoader />
</div>
</ScaffoldSection>
) : (
<>
<SiteUrl />