mirror of
https://github.com/supabase/supabase.git
synced 2026-10-16 06:39:09 +03:00
updated scaffolding
This commit is contained in:
1 parent
1c6614743c
commit
4e23985480
16 files changed
+160
-259
No files matched your search
@@ -10,11 +10,11 @@ import {
|
||||
} from 'ui'
|
||||
|
||||
export const AuthAlert = ({
|
||||
ref,
|
||||
projectRef,
|
||||
title,
|
||||
isHookSendSMSEnabled,
|
||||
}: {
|
||||
ref?: string
|
||||
projectRef: string
|
||||
title: string
|
||||
isHookSendSMSEnabled: boolean
|
||||
}) => {
|
||||
@@ -51,7 +51,7 @@ export const AuthAlert = ({
|
||||
<AlertDescription_Shadcn_ className="flex flex-col gap-y-3">
|
||||
<p>The SMS hook will be used in place of the SMS provider configured</p>
|
||||
<Button asChild type="default" className="w-min" icon={<ExternalLink />}>
|
||||
<Link href={`/project/${ref}/auth/hooks`}>View auth hooks</Link>
|
||||
<Link href={`/project/${projectRef}/auth/hooks`}>View auth hooks</Link>
|
||||
</Button>
|
||||
</AlertDescription_Shadcn_>
|
||||
</Alert_Shadcn_>
|
||||
|
||||
@@ -16,6 +16,11 @@ import {
|
||||
import { getPhoneProviderValidationSchema, PROVIDERS_SCHEMAS } from '../AuthProvidersFormValidation'
|
||||
import type { Provider } from './AuthProvidersForm.types'
|
||||
import ProviderForm from './ProviderForm'
|
||||
import {
|
||||
ScaffoldSection,
|
||||
ScaffoldSectionDescription,
|
||||
ScaffoldSectionTitle,
|
||||
} from 'components/layouts/Scaffold'
|
||||
|
||||
export const AuthProvidersForm = () => {
|
||||
const { ref: projectRef } = useParams()
|
||||
@@ -28,11 +33,11 @@ export const AuthProvidersForm = () => {
|
||||
} = useAuthConfigQuery({ projectRef })
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SectionHeader
|
||||
title="Auth Providers"
|
||||
subtitle="Authenticate your users through a suite of providers and login methods"
|
||||
/>
|
||||
<ScaffoldSection isFullWidth>
|
||||
<ScaffoldSectionTitle>Auth Providers</ScaffoldSectionTitle>
|
||||
<ScaffoldSectionDescription className="mb-4">
|
||||
Authenticate your users through a suite of providers and login methods
|
||||
</ScaffoldSectionDescription>
|
||||
|
||||
<div className="-space-y-px">
|
||||
{authConfig?.EXTERNAL_EMAIL_ENABLED && authConfig?.MAILER_OTP_EXP > 3600 && (
|
||||
@@ -102,6 +107,6 @@ export const AuthProvidersForm = () => {
|
||||
)}
|
||||
</ResourceList>
|
||||
</div>
|
||||
</div>
|
||||
</ScaffoldSection>
|
||||
)
|
||||
}
|
||||
@@ -169,7 +169,7 @@ const ProviderForm = ({ config, provider, isActive }: ProviderFormProps) => {
|
||||
<div className="flex-1 overflow-y-auto group py-6 px-4 md:px-6 text-foreground">
|
||||
<div className="mx-auto my-2 md:my-6 max-w-lg space-y-6">
|
||||
<AuthAlert
|
||||
ref={projectRef}
|
||||
projectRef={projectRef}
|
||||
title={provider.title}
|
||||
isHookSendSMSEnabled={config.HOOK_SEND_SMS_ENABLED}
|
||||
/>
|
||||
|
||||
+4
-4
@@ -26,9 +26,9 @@ import {
|
||||
Switch,
|
||||
WarningIcon,
|
||||
} from 'ui'
|
||||
import { SectionHeader } from 'components/layouts/PageLayout'
|
||||
|
||||
import { NO_REQUIRED_CHARACTERS } from '../Auth.constants'
|
||||
import { ScaffoldSection, ScaffoldSectionTitle } from 'components/layouts/Scaffold'
|
||||
|
||||
const schema = object({
|
||||
DISABLE_SIGNUP: boolean().required(),
|
||||
@@ -106,8 +106,8 @@ const BasicAuthSettingsForm = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SectionHeader title="User Signups" />
|
||||
<ScaffoldSection isFullWidth>
|
||||
<ScaffoldSectionTitle className="mb-4">User Signups</ScaffoldSectionTitle>
|
||||
|
||||
<Form_Shadcn_ {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
||||
@@ -252,7 +252,7 @@ const BasicAuthSettingsForm = () => {
|
||||
</Card>
|
||||
</form>
|
||||
</Form_Shadcn_>
|
||||
</div>
|
||||
</ScaffoldSection>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,12 @@ import {
|
||||
getIntegrationTypeLabel,
|
||||
INTEGRATION_TYPES,
|
||||
} from './ThirdPartyAuthForm.utils'
|
||||
|
||||
import {
|
||||
ScaffoldSection,
|
||||
ScaffoldSectionDescription,
|
||||
ScaffoldSectionTitle,
|
||||
} from 'components/layouts/Scaffold'
|
||||
import { DocsButton } from 'components/ui/DocsButton'
|
||||
export const ThirdPartyAuthForm = () => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const {
|
||||
@@ -53,26 +58,27 @@ export const ThirdPartyAuthForm = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="pb-4">
|
||||
<FormHeader
|
||||
title="Third Party Auth"
|
||||
className="mb-1"
|
||||
description="Use third-party authentication (TPA) systems based on JWTs to access your project."
|
||||
actions={
|
||||
integrations.length !== 0 ? (
|
||||
<ScaffoldSection isFullWidth>
|
||||
<div className="flex justify-between gap-4">
|
||||
<div>
|
||||
<ScaffoldSectionTitle>Third Party Auth</ScaffoldSectionTitle>
|
||||
<ScaffoldSectionDescription className="mb-6">
|
||||
Use third-party authentication (TPA) systems based on JWTs to access your project.
|
||||
<br />
|
||||
Billing is based on the number of monthly active users (MAUs) requesting your API
|
||||
throughout the billing period (50 included then you'll be charged{' '}
|
||||
<span className="text-brand">$0.00325</span>
|
||||
<span> per MAU).</span>
|
||||
</ScaffoldSectionDescription>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 ">
|
||||
<DocsButton href="https://supabase.com/docs/guides/auth/third-party/overview" />
|
||||
{integrations.length !== 0 && (
|
||||
<AddIntegrationDropdown onSelectIntegrationType={setSelectedIntegration} />
|
||||
) : null
|
||||
}
|
||||
docsUrl="https://supabase.com/docs/guides/auth/third-party/overview"
|
||||
/>
|
||||
<div className="prose text-sm mb-6 max-w-full">
|
||||
<span>
|
||||
Billing is based on the number of monthly active users (MAUs) requesting your API
|
||||
throughout the billing period (50 included then you'll be charged{' '}
|
||||
</span>
|
||||
<span className="text-brand">$0.00325</span>
|
||||
<span> per MAU).</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isLoading && (
|
||||
<div
|
||||
className={cn(
|
||||
@@ -162,6 +168,6 @@ export const ThirdPartyAuthForm = () => {
|
||||
{`Are you sure you want to delete the ${getIntegrationTypeLabel(getIntegrationType(selectedIntegrationForDeletion))} integration?`}
|
||||
</p>
|
||||
</ConfirmationModal>
|
||||
</div>
|
||||
</ScaffoldSection>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { ReactNode } from 'react'
|
||||
import DefaultLayout from 'components/layouts/DefaultLayout'
|
||||
import AuthLayout from './AuthLayout'
|
||||
import { PageLayout } from 'components/layouts/PageLayout'
|
||||
|
||||
interface AuthProvidersLayoutProps {
|
||||
children: ReactNode
|
||||
projectRef: string
|
||||
}
|
||||
|
||||
const AuthProvidersLayout = ({ children, projectRef }: AuthProvidersLayoutProps) => {
|
||||
const navItems = [
|
||||
{
|
||||
label: 'Supabase Auth',
|
||||
href: `/project/${projectRef}/auth/providers`,
|
||||
},
|
||||
{
|
||||
label: 'Third Party Auth',
|
||||
href: `/project/${projectRef}/auth/third-party`,
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<DefaultLayout>
|
||||
<AuthLayout>
|
||||
<PageLayout
|
||||
title="Sign In / Up"
|
||||
subtitle="Configure authentication providers and login methods for your users"
|
||||
navigationItems={navItems}
|
||||
>
|
||||
{children}
|
||||
</PageLayout>
|
||||
</AuthLayout>
|
||||
</DefaultLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default AuthProvidersLayout
|
||||
@@ -1,39 +0,0 @@
|
||||
import Link from 'next/link'
|
||||
import { ChevronRight } from 'lucide-react'
|
||||
import { cn } from 'ui'
|
||||
|
||||
export interface BreadcrumbItem {
|
||||
label: string
|
||||
href?: string
|
||||
onClick?: () => void
|
||||
}
|
||||
|
||||
interface BreadcrumbsProps {
|
||||
items: BreadcrumbItem[]
|
||||
className?: string
|
||||
}
|
||||
|
||||
const Breadcrumbs = ({ items, className }: BreadcrumbsProps) => {
|
||||
return (
|
||||
<div className={cn('flex items-center space-x-2 text-sm text-foreground-light', className)}>
|
||||
{items.map((item, index) => (
|
||||
<div key={item.label} className="flex items-center">
|
||||
{index > 0 && <ChevronRight size={14} strokeWidth={1.5} className="mx-2" />}
|
||||
{item.href ? (
|
||||
<Link href={item.href} className="hover:text-foreground transition">
|
||||
{item.label}
|
||||
</Link>
|
||||
) : item.onClick ? (
|
||||
<button className="hover:text-foreground transition" onClick={item.onClick}>
|
||||
{item.label}
|
||||
</button>
|
||||
) : (
|
||||
<span>{item.label}</span>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Breadcrumbs
|
||||
@@ -1,16 +0,0 @@
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
import { cn } from 'ui'
|
||||
import { PAGE_SIZE_CLASSES, type PageSize } from 'ui/src/lib/constants'
|
||||
|
||||
interface PageContainerProps {
|
||||
children?: ReactNode
|
||||
className?: string
|
||||
size?: PageSize
|
||||
}
|
||||
|
||||
const PageContainer = ({ children, className, size = 'default' }: PageContainerProps) => {
|
||||
return <div className={cn('mx-auto', PAGE_SIZE_CLASSES[size], className)}>{children}</div>
|
||||
}
|
||||
|
||||
export default PageContainer
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useParams } from 'common'
|
||||
import { useRouter } from 'next/router'
|
||||
import { Fragment, ReactNode } from 'react'
|
||||
import { cn } from 'ui'
|
||||
import {
|
||||
@@ -36,14 +37,17 @@ export const PageHeader = ({
|
||||
}: PageHeaderProps) => {
|
||||
const { ref } = useParams()
|
||||
|
||||
const displayBreadcrumbs = isCompact && title ? [...breadcrumbs, { label: title }] : breadcrumbs
|
||||
|
||||
return (
|
||||
<div className={cn('space-y-4', className)}>
|
||||
{(breadcrumbs.length > 0 || (isCompact && (title || primaryActions || secondaryActions))) && (
|
||||
{(displayBreadcrumbs.length > 0 ||
|
||||
(isCompact && (title || primaryActions || secondaryActions))) && (
|
||||
<div className={cn('flex items-center gap-4', isCompact ? 'justify-between' : 'mb-4')}>
|
||||
{breadcrumbs.length > 0 ? (
|
||||
{displayBreadcrumbs.length > 0 ? (
|
||||
<Breadcrumb className={cn('text-foreground-muted', isCompact && 'text-base')}>
|
||||
<BreadcrumbList className={isCompact ? 'text-base' : 'text-xs'}>
|
||||
{breadcrumbs.map((item, index) => (
|
||||
{displayBreadcrumbs.map((item, index) => (
|
||||
<Fragment key={item.label}>
|
||||
<BreadcrumbItem>
|
||||
{item.href ? (
|
||||
@@ -54,7 +58,7 @@ export const PageHeader = ({
|
||||
<BreadcrumbPageItem>{item.label}</BreadcrumbPageItem>
|
||||
)}
|
||||
</BreadcrumbItem>
|
||||
{index < breadcrumbs.length - 1 && <BreadcrumbSeparator />}
|
||||
{index < displayBreadcrumbs.length - 1 && <BreadcrumbSeparator />}
|
||||
</Fragment>
|
||||
))}
|
||||
</BreadcrumbList>
|
||||
|
||||
@@ -4,8 +4,8 @@ import { ReactNode } from 'react'
|
||||
|
||||
import { useParams } from 'common'
|
||||
import { Button, cn, NavMenu, NavMenuItem } from 'ui'
|
||||
import { PAGE_SIZE_CLASSES, type PageSize } from 'ui/src/lib/constants'
|
||||
import { PageHeader } from '.'
|
||||
import { ScaffoldContainer } from '../Scaffold'
|
||||
|
||||
export interface NavigationItem {
|
||||
id?: string
|
||||
@@ -28,7 +28,7 @@ interface PageLayoutProps {
|
||||
secondaryActions?: ReactNode
|
||||
navigationItems?: NavigationItem[]
|
||||
className?: string
|
||||
size?: PageSize
|
||||
size?: 'default' | 'full'
|
||||
isCompact?: boolean
|
||||
}
|
||||
|
||||
@@ -69,15 +69,14 @@ const PageLayout = ({
|
||||
isCompact = false,
|
||||
}: PageLayoutProps) => {
|
||||
const router = useRouter()
|
||||
const { ref } = useParams()
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div
|
||||
<ScaffoldContainer
|
||||
className={cn(
|
||||
'w-full mx-auto',
|
||||
PAGE_SIZE_CLASSES[size],
|
||||
size === 'full' && (isCompact ? 'px-6 border-b' : 'px-8 border-b'),
|
||||
size === 'full' &&
|
||||
(isCompact ? 'max-w-none !px-6 border-b' : 'max-w-none p!x-8 border-b'),
|
||||
isCompact ? 'pt-4' : 'pt-12',
|
||||
navigationItems.length === 0 && size === 'full' && (isCompact ? 'pb-4' : 'pb-8'),
|
||||
className
|
||||
@@ -100,18 +99,25 @@ const PageLayout = ({
|
||||
{navigationItems.length > 0 && (
|
||||
<NavMenu className={cn('mt-4', size === 'full' && 'border-none')}>
|
||||
{navigationItems.map((item) => (
|
||||
<NavMenuItem key={item.label} active={router.pathname === item.href}>
|
||||
<NavMenuItem key={item.label} active={router.asPath === item.href}>
|
||||
{item.href ? (
|
||||
<Link
|
||||
href={!!ref ? item.href.replace('[ref]', ref) : item.href}
|
||||
className="inline-flex items-center gap-2"
|
||||
href={item.href}
|
||||
className={cn(
|
||||
'inline-flex items-center gap-2',
|
||||
router.asPath === item.href && 'text-foreground'
|
||||
)}
|
||||
onClick={item.onClick}
|
||||
>
|
||||
{item.icon && <span>{item.icon}</span>}
|
||||
{item.label}
|
||||
</Link>
|
||||
) : (
|
||||
<Button type="link" onClick={item.onClick}>
|
||||
<Button
|
||||
type="link"
|
||||
onClick={item.onClick}
|
||||
className={cn(router.pathname === item.href && 'text-foreground font-medium')}
|
||||
>
|
||||
{item.icon && <span className="mr-2">{item.icon}</span>}
|
||||
{item.label}
|
||||
</Button>
|
||||
@@ -120,10 +126,10 @@ const PageLayout = ({
|
||||
))}
|
||||
</NavMenu>
|
||||
)}
|
||||
</div>
|
||||
</ScaffoldContainer>
|
||||
|
||||
{/* Content section */}
|
||||
<main>{children}</main>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
import Link from 'next/link'
|
||||
import { useCurrentPath } from 'hooks/misc/useCurrentPath'
|
||||
import { cn } from 'ui'
|
||||
import { NavMenu, NavMenuItem } from 'ui'
|
||||
|
||||
export interface NavigationItem {
|
||||
label: string
|
||||
href: string
|
||||
}
|
||||
|
||||
interface PageNavigationProps {
|
||||
items: NavigationItem[]
|
||||
className?: string
|
||||
}
|
||||
|
||||
const PageNavigation = ({ items, className }: PageNavigationProps) => {
|
||||
const currentPath = useCurrentPath()
|
||||
|
||||
return (
|
||||
<NavMenu
|
||||
className={cn('border-none max-w-full overflow-y-hidden overflow-x-auto', className)}
|
||||
aria-label="Page navigation"
|
||||
>
|
||||
{items.map((item) => (
|
||||
<NavMenuItem key={item.label} active={currentPath === item.href}>
|
||||
<Link href={item.href}>{item.label}</Link>
|
||||
</NavMenuItem>
|
||||
))}
|
||||
</NavMenu>
|
||||
)
|
||||
}
|
||||
|
||||
export default PageNavigation
|
||||
@@ -1,23 +0,0 @@
|
||||
import React from 'react'
|
||||
import { cn } from 'ui'
|
||||
|
||||
interface SectionHeaderProps {
|
||||
title?: string
|
||||
subtitle?: string
|
||||
actions?: React.ReactNode
|
||||
className?: string
|
||||
}
|
||||
|
||||
const SectionHeader = ({ title, subtitle, actions, className }: SectionHeaderProps) => {
|
||||
return (
|
||||
<div className={cn('flex items-center justify-between gap-4 mt-8 mb-4', className)}>
|
||||
<div className="space-y-1">
|
||||
{title && <h3 className="text-foreground text-xl">{title}</h3>}
|
||||
{subtitle && <p className="text-sm text-foreground-light">{subtitle}</p>}
|
||||
</div>
|
||||
{actions && <div className="flex items-center gap-2">{actions}</div>}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default SectionHeader
|
||||
@@ -1,9 +1,4 @@
|
||||
export { default as PageLayout } from './PageLayout'
|
||||
export { default as PageHeader } from './PageHeader'
|
||||
export { default as PageContainer } from './PageContainer'
|
||||
export { default as SectionHeader } from './SectionHeader'
|
||||
export { default as PageNavigation } from './PageNavigation'
|
||||
export { default as Breadcrumbs } from './Breadcrumbs'
|
||||
|
||||
export type { NavigationItem } from './PageLayout'
|
||||
export type { BreadcrumbItem } from './Breadcrumbs'
|
||||
@@ -59,13 +59,22 @@ const ScaffoldDivider = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HT
|
||||
}
|
||||
)
|
||||
|
||||
const ScaffoldSection = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => {
|
||||
interface ScaffoldSectionProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
isFullWidth?: boolean
|
||||
topPadding?: boolean
|
||||
}
|
||||
|
||||
const ScaffoldSection = React.forwardRef<HTMLDivElement, ScaffoldSectionProps>(
|
||||
({ className, isFullWidth, topPadding, ...props }, ref) => {
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
{...props}
|
||||
className={cn('flex flex-col gap-3 py-6', 'lg:grid md:grid-cols-12 lg:py-12', className)}
|
||||
className={cn(
|
||||
'flex flex-col first:pt-12 py-6',
|
||||
isFullWidth ? 'w-full' : 'gap-3 lg:grid md:grid-cols-12',
|
||||
className
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -145,6 +154,20 @@ const ScaffoldContainerLegacy = React.forwardRef<
|
||||
)
|
||||
})
|
||||
|
||||
const ScaffoldSectionTitle = React.forwardRef<
|
||||
HTMLHeadingElement,
|
||||
React.HTMLAttributes<HTMLHeadingElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
return <h3 ref={ref} {...props} className={cn('text-foreground text-xl', className)} />
|
||||
})
|
||||
|
||||
const ScaffoldSectionDescription = React.forwardRef<
|
||||
HTMLParagraphElement,
|
||||
React.HTMLAttributes<HTMLParagraphElement>
|
||||
>(({ className, ...props }, ref) => {
|
||||
return <p ref={ref} {...props} className={cn('text-sm text-foreground-light', className)} />
|
||||
})
|
||||
|
||||
ScaffoldHeader.displayName = 'ScaffoldHeader'
|
||||
ScaffoldTitle.displayName = 'ScaffoldTitle'
|
||||
ScaffoldDescription.displayName = 'ScaffoldDescription'
|
||||
@@ -158,6 +181,8 @@ ScaffoldFilterAndContent.displayName = 'ScaffoldFilterAndContent'
|
||||
ScaffoldActionsContainer.displayName = 'ScaffoldActionsContainer'
|
||||
ScaffoldActionsGroup.displayName = 'ScaffoldActionsGroup'
|
||||
ScaffoldContainerLegacy.displayName = 'ScaffoldContainerLegacy'
|
||||
ScaffoldSectionTitle.displayName = 'ScaffoldSectionTitle'
|
||||
ScaffoldSectionDescription.displayName = 'ScaffoldSectionDescription'
|
||||
|
||||
export {
|
||||
ScaffoldHeader,
|
||||
@@ -169,6 +194,8 @@ export {
|
||||
ScaffoldColumn,
|
||||
ScaffoldSectionDetail,
|
||||
ScaffoldSectionContent,
|
||||
ScaffoldSectionTitle,
|
||||
ScaffoldSectionDescription,
|
||||
ScaffoldFilterAndContent,
|
||||
ScaffoldActionsContainer,
|
||||
ScaffoldActionsGroup,
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
|
||||
import { AuthProvidersForm, BasicAuthSettingsForm } from 'components/interfaces/Auth'
|
||||
import AuthLayout from 'components/layouts/AuthLayout/AuthLayout'
|
||||
import DefaultLayout from 'components/layouts/DefaultLayout'
|
||||
import { PageContainer, PageLayout } from 'components/layouts/PageLayout'
|
||||
import AuthProvidersLayout from 'components/layouts/AuthLayout/AuthProvidersLayout'
|
||||
import NoPermission from 'components/ui/NoPermission'
|
||||
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
|
||||
import { useParams } from 'common'
|
||||
import type { NextPageWithLayout } from 'types'
|
||||
import { ScaffoldContainer } from 'components/layouts/Scaffold'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
const ProvidersPage: NextPageWithLayout = () => {
|
||||
const canReadAuthSettings = useCheckPermissions(PermissionAction.READ, 'custom_config_gotrue')
|
||||
@@ -17,38 +18,16 @@ const ProvidersPage: NextPageWithLayout = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<PageContainer className="pb-16">
|
||||
<ScaffoldContainer>
|
||||
<BasicAuthSettingsForm />
|
||||
<AuthProvidersForm />
|
||||
</PageContainer>
|
||||
</ScaffoldContainer>
|
||||
)
|
||||
}
|
||||
|
||||
ProvidersPage.getLayout = (page) => {
|
||||
const navigationItems = [
|
||||
{
|
||||
label: 'Supabase Auth',
|
||||
href: `/project/[ref]/auth/providers`,
|
||||
},
|
||||
{
|
||||
label: 'Third Party Auth',
|
||||
href: `/project/[ref]/auth/third-party`,
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<DefaultLayout>
|
||||
<AuthLayout>
|
||||
<PageLayout
|
||||
title="Sign In / Up"
|
||||
subtitle="Configure authentication providers and login methods for your users"
|
||||
navigationItems={navigationItems}
|
||||
>
|
||||
{page}
|
||||
</PageLayout>
|
||||
</AuthLayout>
|
||||
</DefaultLayout>
|
||||
)
|
||||
const { ref: projectRef } = useRouter().query
|
||||
return <AuthProvidersLayout projectRef={projectRef as string}>{page}</AuthProvidersLayout>
|
||||
}
|
||||
|
||||
export default ProvidersPage
|
||||
@@ -1,79 +1,31 @@
|
||||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||||
|
||||
import { ThirdPartyAuthForm } from 'components/interfaces/Auth'
|
||||
import AuthLayout from 'components/layouts/AuthLayout/AuthLayout'
|
||||
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
|
||||
import { useParams } from 'common'
|
||||
import { useCurrentPath } from 'hooks/misc/useCurrentPath'
|
||||
import Link from 'next/link'
|
||||
import { NavMenu, NavMenuItem } from 'ui'
|
||||
import {
|
||||
ScaffoldContainer,
|
||||
ScaffoldDescription,
|
||||
ScaffoldDivider,
|
||||
ScaffoldHeader,
|
||||
ScaffoldTitle,
|
||||
} from 'components/layouts/Scaffold'
|
||||
import AuthProvidersLayout from 'components/layouts/AuthLayout/AuthProvidersLayout'
|
||||
import NoPermission from 'components/ui/NoPermission'
|
||||
import { useCheckPermissions, usePermissionsLoaded } from 'hooks/misc/useCheckPermissions'
|
||||
import type { NextPageWithLayout } from 'types'
|
||||
import DefaultLayout from 'components/layouts/DefaultLayout'
|
||||
import { ScaffoldContainer } from 'components/layouts/Scaffold'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
const PageLayout: NextPageWithLayout = () => {
|
||||
const ThirdPartyPage: NextPageWithLayout = () => {
|
||||
const canReadAuthSettings = useCheckPermissions(PermissionAction.READ, 'custom_config_gotrue')
|
||||
const isPermissionsLoaded = usePermissionsLoaded()
|
||||
const { ref } = useParams()
|
||||
const currentPath = useCurrentPath()
|
||||
|
||||
const navMenuItems = [
|
||||
{
|
||||
label: 'Supabase auth',
|
||||
href: `/project/${ref}/auth/providers`,
|
||||
},
|
||||
{
|
||||
label: 'Third Party auth',
|
||||
href: `/project/${ref}/auth/third-party`,
|
||||
},
|
||||
]
|
||||
|
||||
if (isPermissionsLoaded && !canReadAuthSettings) {
|
||||
return <NoPermission isFullPage resourceText="access your project's auth provider settings" />
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ScaffoldHeader className="pb-0">
|
||||
<ScaffoldContainer id="auth-page-top">
|
||||
<ScaffoldTitle>Sign in / up</ScaffoldTitle>
|
||||
<ScaffoldDescription>
|
||||
Configure authentication providers and login methods for your users
|
||||
</ScaffoldDescription>
|
||||
<NavMenu
|
||||
className="border-none max-w-full overflow-y-hidden overflow-x-auto mt-4"
|
||||
aria-label="Auth provider settings navigation"
|
||||
>
|
||||
{navMenuItems.map((item) => (
|
||||
<NavMenuItem key={item.label} active={currentPath === item.href}>
|
||||
<Link href={item.href}>{item.label}</Link>
|
||||
</NavMenuItem>
|
||||
))}
|
||||
</NavMenu>
|
||||
</ScaffoldContainer>
|
||||
</ScaffoldHeader>
|
||||
|
||||
<ScaffoldDivider />
|
||||
|
||||
<ScaffoldContainer className="my-8">
|
||||
<ThirdPartyAuthForm />
|
||||
</ScaffoldContainer>
|
||||
</>
|
||||
<ScaffoldContainer className="pb-16">
|
||||
<ThirdPartyAuthForm />
|
||||
</ScaffoldContainer>
|
||||
)
|
||||
}
|
||||
|
||||
PageLayout.getLayout = (page) => {
|
||||
return (
|
||||
<DefaultLayout>
|
||||
<AuthLayout>{page}</AuthLayout>
|
||||
</DefaultLayout>
|
||||
)
|
||||
ThirdPartyPage.getLayout = (page) => {
|
||||
const { ref: projectRef } = useRouter().query
|
||||
return <AuthProvidersLayout projectRef={projectRef as string}>{page}</AuthProvidersLayout>
|
||||
}
|
||||
export default PageLayout
|
||||
|
||||
export default ThirdPartyPage
|
||||
Reference in new issue
Block a user