Skip to content

Commit 3d7d192

Browse files
authored
Auth pages new page components (supabase#40669)
* pages first * fixes * fix
1 parent 02055ae commit 3d7d192

File tree

18 files changed

+751
-544
lines changed

18 files changed

+751
-544
lines changed

apps/studio/components/interfaces/Auth/OAuthApps/OAuthServerSettingsForm.tsx

Lines changed: 124 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,6 @@ import { toast } from 'sonner'
77
import * as z from 'zod'
88

99
import { useParams } from 'common'
10-
import {
11-
ScaffoldSection,
12-
ScaffoldSectionContent,
13-
ScaffoldSectionTitle,
14-
} from 'components/layouts/Scaffold'
1510
import { InlineLink } from 'components/ui/InlineLink'
1611
import NoPermission from 'components/ui/NoPermission'
1712
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
@@ -181,44 +176,126 @@ export const OAuthServerSettingsForm = () => {
181176
}
182177

183178
if (isPermissionsLoaded && !canReadConfig) {
184-
return (
185-
<ScaffoldSection isFullWidth>
186-
<ScaffoldSectionTitle className="mb-4">OAuth Server</ScaffoldSectionTitle>
187-
<div className="mt-8">
188-
<NoPermission resourceText="view OAuth server settings" />
189-
</div>
190-
</ScaffoldSection>
191-
)
179+
return <NoPermission resourceText="view OAuth server settings" />
192180
}
193181

194182
if (isAuthConfigLoading || isLoadingPermissions) {
195-
return (
196-
<div className="pt-12">
197-
<GenericSkeletonLoader />
198-
</div>
199-
)
183+
return <GenericSkeletonLoader />
200184
}
201185

202186
return (
203187
<>
204-
<ScaffoldSection isFullWidth>
205-
<ScaffoldSectionContent>
206-
<Form_Shadcn_ {...form}>
207-
<form onSubmit={form.handleSubmit(onSubmit)} className="pb-10">
208-
<Card>
188+
<Form_Shadcn_ {...form}>
189+
<form onSubmit={form.handleSubmit(onSubmit)} className="pb-10">
190+
<Card>
191+
<CardContent className="flex flex-col py-6 gap-y-4">
192+
<FormField_Shadcn_
193+
control={form.control}
194+
name="OAUTH_SERVER_ENABLED"
195+
render={({ field }) => (
196+
<FormItemLayout
197+
layout="flex-row-reverse"
198+
label="Enable the Supabase OAuth Server"
199+
description={
200+
<>
201+
Enable OAuth server functionality for your project to create and manage
202+
OAuth applications.{' '}
203+
<InlineLink href={`${DOCS_URL}/guides/auth/oauth-server`}>
204+
Learn more
205+
</InlineLink>
206+
</>
207+
}
208+
>
209+
<FormControl_Shadcn_>
210+
<Switch
211+
checked={field.value}
212+
onCheckedChange={handleOAuthServerToggle}
213+
disabled={!canUpdateConfig}
214+
/>
215+
</FormControl_Shadcn_>
216+
</FormItemLayout>
217+
)}
218+
/>
219+
</CardContent>
220+
{/* Site URL and Authorization Path - Only show when OAuth Server is enabled */}
221+
{form.watch('OAUTH_SERVER_ENABLED') && (
222+
<>
209223
<CardContent className="flex flex-col py-6 gap-y-4">
224+
<FormItemLayout
225+
label="Site URL"
226+
description={
227+
<>
228+
The base URL of your application, configured in{' '}
229+
<Link
230+
href={`/project/${projectRef}/auth/url-configuration`}
231+
rel="noreferrer"
232+
className="text-foreground-light underline hover:text-foreground transition"
233+
>
234+
Auth URL Configuration
235+
</Link>{' '}
236+
settings.
237+
</>
238+
}
239+
>
240+
<Input_Shadcn_
241+
value={authConfig?.SITE_URL}
242+
disabled
243+
placeholder="https://example.com"
244+
/>
245+
</FormItemLayout>
246+
247+
<FormField_Shadcn_
248+
control={form.control}
249+
name="OAUTH_SERVER_AUTHORIZATION_PATH"
250+
render={({ field }) => (
251+
<FormItemLayout
252+
label="Authorization Path"
253+
description="Path where you'll implement the OAuth authorization UI (consent screens)."
254+
>
255+
<FormControl_Shadcn_>
256+
<Input_Shadcn_ {...field} placeholder="/auth/authorize" />
257+
</FormControl_Shadcn_>
258+
</FormItemLayout>
259+
)}
260+
/>
261+
{(() => {
262+
const authorizationUrl = `${authConfig?.SITE_URL}${form.watch('OAUTH_SERVER_AUTHORIZATION_PATH') || '/oauth/consent'}`
263+
return (
264+
<Admonition
265+
type="tip"
266+
title="Make sure this path is implemented in your application."
267+
description={
268+
<>
269+
Preview Authorization URL:{' '}
270+
<a
271+
href={authorizationUrl}
272+
target="_blank"
273+
rel="noreferrer"
274+
className="text-foreground-light underline hover:text-foreground transition"
275+
>
276+
{authorizationUrl}
277+
</a>
278+
</>
279+
}
280+
/>
281+
)
282+
})()}
283+
</CardContent>
284+
<CardContent className="py-6">
210285
<FormField_Shadcn_
211286
control={form.control}
212-
name="OAUTH_SERVER_ENABLED"
287+
name="OAUTH_SERVER_ALLOW_DYNAMIC_REGISTRATION"
213288
render={({ field }) => (
214289
<FormItemLayout
215290
layout="flex-row-reverse"
216-
label="Enable the Supabase OAuth Server"
291+
label="Allow Dynamic OAuth Apps"
217292
description={
218293
<>
219-
Enable OAuth server functionality for your project to create and manage
220-
OAuth applications.{' '}
221-
<InlineLink href={`${DOCS_URL}/guides/auth/oauth-server`}>
294+
Enable dynamic OAuth app registration. Apps can be registered
295+
programmatically via APIs.{' '}
296+
<InlineLink
297+
href={`${DOCS_URL}/guides/auth/oauth-server/mcp-authentication#oauth-client-setup`}
298+
>
222299
Learn more
223300
</InlineLink>
224301
</>
@@ -227,130 +304,33 @@ export const OAuthServerSettingsForm = () => {
227304
<FormControl_Shadcn_>
228305
<Switch
229306
checked={field.value}
230-
onCheckedChange={handleOAuthServerToggle}
307+
onCheckedChange={handleDynamicAppsToggle}
231308
disabled={!canUpdateConfig}
232309
/>
233310
</FormControl_Shadcn_>
234311
</FormItemLayout>
235312
)}
236313
/>
237314
</CardContent>
238-
{/* Site URL and Authorization Path - Only show when OAuth Server is enabled */}
239-
{form.watch('OAUTH_SERVER_ENABLED') && (
240-
<>
241-
<CardContent className="flex flex-col py-6 gap-y-4">
242-
<FormItemLayout
243-
label="Site URL"
244-
description={
245-
<>
246-
The base URL of your application, configured in{' '}
247-
<Link
248-
href={`/project/${projectRef}/auth/url-configuration`}
249-
rel="noreferrer"
250-
className="text-foreground-light underline hover:text-foreground transition"
251-
>
252-
Auth URL Configuration
253-
</Link>{' '}
254-
settings.
255-
</>
256-
}
257-
>
258-
<Input_Shadcn_
259-
value={authConfig?.SITE_URL}
260-
disabled
261-
placeholder="https://example.com"
262-
/>
263-
</FormItemLayout>
264-
265-
<FormField_Shadcn_
266-
control={form.control}
267-
name="OAUTH_SERVER_AUTHORIZATION_PATH"
268-
render={({ field }) => (
269-
<FormItemLayout
270-
label="Authorization Path"
271-
description="Path where you'll implement the OAuth authorization UI (consent screens)."
272-
>
273-
<FormControl_Shadcn_>
274-
<Input_Shadcn_ {...field} placeholder="/auth/authorize" />
275-
</FormControl_Shadcn_>
276-
</FormItemLayout>
277-
)}
278-
/>
279-
{(() => {
280-
const authorizationUrl = `${authConfig?.SITE_URL}${form.watch('OAUTH_SERVER_AUTHORIZATION_PATH') || '/oauth/consent'}`
281-
return (
282-
<Admonition
283-
type="tip"
284-
title="Make sure this path is implemented in your application."
285-
description={
286-
<>
287-
Preview Authorization URL:{' '}
288-
<a
289-
href={authorizationUrl}
290-
target="_blank"
291-
rel="noreferrer"
292-
className="text-foreground-light underline hover:text-foreground transition"
293-
>
294-
{authorizationUrl}
295-
</a>
296-
</>
297-
}
298-
/>
299-
)
300-
})()}
301-
</CardContent>
302-
<CardContent className="py-6">
303-
<FormField_Shadcn_
304-
control={form.control}
305-
name="OAUTH_SERVER_ALLOW_DYNAMIC_REGISTRATION"
306-
render={({ field }) => (
307-
<FormItemLayout
308-
layout="flex-row-reverse"
309-
label="Allow Dynamic OAuth Apps"
310-
description={
311-
<>
312-
Enable dynamic OAuth app registration. Apps can be registered
313-
programmatically via APIs.{' '}
314-
<InlineLink
315-
href={`${DOCS_URL}/guides/auth/oauth-server/mcp-authentication#oauth-client-setup`}
316-
>
317-
Learn more
318-
</InlineLink>
319-
</>
320-
}
321-
>
322-
<FormControl_Shadcn_>
323-
<Switch
324-
checked={field.value}
325-
onCheckedChange={handleDynamicAppsToggle}
326-
disabled={!canUpdateConfig}
327-
/>
328-
</FormControl_Shadcn_>
329-
</FormItemLayout>
330-
)}
331-
/>
332-
</CardContent>
333-
</>
334-
)}
315+
</>
316+
)}
335317

336-
<CardFooter className="justify-end space-x-2">
337-
<Button type="default" onClick={() => form.reset()} disabled={isPending}>
338-
Cancel
339-
</Button>
340-
<Button
341-
type="primary"
342-
htmlType="submit"
343-
disabled={!canUpdateConfig || !form.formState.isDirty}
344-
loading={isPending}
345-
>
346-
Save changes
347-
</Button>
348-
</CardFooter>
349-
</Card>
350-
</form>
351-
</Form_Shadcn_>
352-
</ScaffoldSectionContent>
353-
</ScaffoldSection>
318+
<CardFooter className="justify-end space-x-2">
319+
<Button type="default" onClick={() => form.reset()} disabled={isPending}>
320+
Cancel
321+
</Button>
322+
<Button
323+
type="primary"
324+
htmlType="submit"
325+
disabled={!canUpdateConfig || !form.formState.isDirty}
326+
loading={isPending}
327+
>
328+
Save changes
329+
</Button>
330+
</CardFooter>
331+
</Card>
332+
</form>
333+
</Form_Shadcn_>
354334

355335
{/* Dynamic Apps Confirmation Modal */}
356336
<ConfirmationModal

apps/studio/pages/project/[ref]/auth/advanced.tsx

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,21 @@ import { useParams } from 'common'
44
import { AdvancedAuthSettingsForm } from 'components/interfaces/Auth/AdvancedAuthSettingsForm'
55
import AuthLayout from 'components/layouts/AuthLayout/AuthLayout'
66
import DefaultLayout from 'components/layouts/DefaultLayout'
7-
import { PageLayout } from 'components/layouts/PageLayout/PageLayout'
8-
import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold'
97
import NoPermission from 'components/ui/NoPermission'
108
import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
119
import { UnknownInterface } from 'components/ui/UnknownInterface'
1210
import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions'
1311
import { useIsFeatureEnabled } from 'hooks/misc/useIsFeatureEnabled'
1412
import type { NextPageWithLayout } from 'types'
13+
import { PageContainer } from 'ui-patterns/PageContainer'
14+
import {
15+
PageHeader,
16+
PageHeaderDescription,
17+
PageHeaderMeta,
18+
PageHeaderSummary,
19+
PageHeaderTitle,
20+
} from 'ui-patterns/PageHeader'
21+
import { PageSection, PageSectionContent } from 'ui-patterns/PageSection'
1522

1623
const AdvancedPage: NextPageWithLayout = () => {
1724
const { ref } = useParams()
@@ -31,25 +38,35 @@ const AdvancedPage: NextPageWithLayout = () => {
3138
}
3239

3340
return (
34-
<ScaffoldContainer>
35-
{!isPermissionsLoaded ? (
36-
<ScaffoldSection isFullWidth>
37-
<GenericSkeletonLoader />
38-
</ScaffoldSection>
39-
) : (
40-
<AdvancedAuthSettingsForm />
41-
)}
42-
</ScaffoldContainer>
41+
<>
42+
<PageHeader size="default">
43+
<PageHeaderMeta>
44+
<PageHeaderSummary>
45+
<PageHeaderTitle>Advanced</PageHeaderTitle>
46+
<PageHeaderDescription>
47+
Configure advanced authentication server settings
48+
</PageHeaderDescription>
49+
</PageHeaderSummary>
50+
</PageHeaderMeta>
51+
</PageHeader>
52+
<PageContainer size="default">
53+
{!isPermissionsLoaded ? (
54+
<PageSection>
55+
<PageSectionContent>
56+
<GenericSkeletonLoader />
57+
</PageSectionContent>
58+
</PageSection>
59+
) : (
60+
<AdvancedAuthSettingsForm />
61+
)}
62+
</PageContainer>
63+
</>
4364
)
4465
}
4566

4667
AdvancedPage.getLayout = (page) => (
4768
<DefaultLayout>
48-
<AuthLayout>
49-
<PageLayout title="Advanced" subtitle="Configure advanced authentication server settings">
50-
{page}
51-
</PageLayout>
52-
</AuthLayout>
69+
<AuthLayout>{page}</AuthLayout>
5370
</DefaultLayout>
5471
)
5572

0 commit comments

Comments
 (0)