Realtime page components (#40967)

* realtime page components

* PRettier

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
This commit is contained in:
Saxon FletcherandJoshen Lim authored and GitHub committed 2025-12-02 17:20:09 +08:00
1 parent 4cd7c749a9
commit 4351c3b31b
3 files changed
+471 -461

No files matched your search

@@ -6,7 +6,6 @@ import { toast } from 'sonner'
import * as z from 'zod'
import { useParams } from 'common'
import { ScaffoldSection } from 'components/layouts/Scaffold'
import AlertError from 'components/ui/AlertError'
import { FormSection, FormSectionContent, FormSectionLabel } from 'components/ui/Forms/FormSection'
import { ToggleSpendCapButton } from 'components/ui/ToggleSpendCapButton'
@@ -145,446 +144,422 @@ export const RealtimeSettings = () => {
return (
<>
<ScaffoldSection isFullWidth>
<Form_Shadcn_ {...form}>
<form id={formId} onSubmit={form.handleSubmit(onSubmit)}>
{isError ? (
<AlertError error={error} subject="Failed to retrieve realtime settings" />
) : (
<Card>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="suspend"
render={({ field }) => (
<FormSection
className="!p-0 !pt-2"
header={<FormSectionLabel>Enable Realtime service</FormSectionLabel>}
<Form_Shadcn_ {...form}>
<form id={formId} onSubmit={form.handleSubmit(onSubmit)}>
{isError ? (
<AlertError error={error} subject="Failed to retrieve realtime settings" />
) : (
<Card>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="suspend"
render={({ field }) => (
<FormSection
className="!p-0 !pt-2"
header={<FormSectionLabel>Enable Realtime service</FormSectionLabel>}
>
<FormSectionContent
loaders={1}
loading={isLoading || isLoadingPermissions}
className="!gap-y-2"
>
<FormSectionContent
loaders={1}
loading={isLoading || isLoadingPermissions}
className="!gap-y-2"
<FormItemLayout
layout="flex"
label="Enable Realtime service"
description="If disabled, no clients will be able to connect and new connections will be rejected"
>
<FormItemLayout
layout="flex"
label="Enable Realtime service"
description="If disabled, no clients will be able to connect and new connections will be rejected"
<FormControl_Shadcn_>
<Switch
checked={!field.value}
onCheckedChange={(checked) => field.onChange(!checked)}
disabled={!canUpdateConfig}
/>
</FormControl_Shadcn_>
</FormItemLayout>
<FormMessage_Shadcn_ />
{(isRealtimeDisabled || isDisablingRealtime || isEnablingRealtime) && (
<Admonition
showIcon={false}
type={isDisablingRealtime || isEnablingRealtime ? 'warning' : 'default'}
>
<FormControl_Shadcn_>
<Switch
checked={!field.value}
onCheckedChange={(checked) => field.onChange(!checked)}
disabled={!canUpdateConfig}
/>
</FormControl_Shadcn_>
</FormItemLayout>
<FormMessage_Shadcn_ />
{(isRealtimeDisabled || isDisablingRealtime || isEnablingRealtime) && (
<Admonition
showIcon={false}
type={
isDisablingRealtime || isEnablingRealtime ? 'warning' : 'default'
}
>
<div className="flex items-center gap-x-2">
<div>
<h5 className="text-foreground mb-1">
{isDisablingRealtime
? 'Realtime service will be disabled'
: isEnablingRealtime
? 'Realtime service will be re-enabled'
: isRealtimeDisabled
? 'Realtime service is disabled'
: null}
</h5>
<p className="text-foreground-light">
{isDisablingRealtime
? 'Clients will no longer be able to connect to your project’s realtime service once saved'
: isEnablingRealtime
? "Clients will be able to connect to your project's realtime service again once saved"
: isRealtimeDisabled
? 'You will need to enable it to continue using Realtime'
: null}
</p>
</div>
<div className="flex items-center gap-x-2">
<div>
<h5 className="text-foreground mb-1">
{isDisablingRealtime
? 'Realtime service will be disabled'
: isEnablingRealtime
? 'Realtime service will be re-enabled'
: isRealtimeDisabled
? 'Realtime service is disabled'
: null}
</h5>
<p className="text-foreground-light">
{isDisablingRealtime
? 'Clients will no longer be able to connect to your project’s realtime service once saved'
: isEnablingRealtime
? "Clients will be able to connect to your project's realtime service again once saved"
: isRealtimeDisabled
? 'You will need to enable it to continue using Realtime'
: null}
</p>
</div>
</Admonition>
)}
</FormSectionContent>
</FormSection>
)}
/>
</CardContent>
{!suspend && (
<>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="allow_public"
render={({ field }) => (
<FormSection
className="!p-0 !pt-2"
header={<FormSectionLabel>Channel restrictions</FormSectionLabel>}
>
<FormSectionContent
loaders={1}
loading={isLoading || isLoadingPermissions}
className="!gap-y-2"
>
<FormItemLayout
layout="flex"
label="Allow public access"
description="If disabled, only private channels will be allowed"
>
<FormControl_Shadcn_>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
disabled={!canUpdateConfig}
/>
</FormControl_Shadcn_>
</FormItemLayout>
{isSuccessPolicies &&
!hasRealtimeMessagesPolicies &&
!allow_public &&
!isRealtimeDisabled && (
<Admonition
showIcon={false}
type="warning"
title="No Realtime RLS policies found"
description={
<>
<p className="prose max-w-full text-sm">
Private mode is {isSettingToPrivate ? 'being ' : ''}
enabled, but no RLS policies exists on the{' '}
<code className="text-code-inline">
realtime.messages
</code>{' '}
table. No messages will be received by users.
</p>
<Button asChild type="default" className="mt-2">
<Link href={`/project/${projectRef}/realtime/policies`}>
Create policy
</Link>
</Button>
</>
}
/>
)}
</FormSectionContent>
</FormSection>
</div>
</Admonition>
)}
/>
</CardContent>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="connection_pool"
render={({ field }) => (
<FormSection
className="!p-0 !py-2"
header={
<FormSectionLabel
description={
<p className="text-foreground-lighter text-sm !mt-1">
Realtime Authorization uses this database pool to check client
access
</p>
}
>
Database connection pool size
</FormSectionLabel>
}
</FormSectionContent>
</FormSection>
)}
/>
</CardContent>
{!suspend && (
<>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="allow_public"
render={({ field }) => (
<FormSection
className="!p-0 !pt-2"
header={<FormSectionLabel>Channel restrictions</FormSectionLabel>}
>
<FormSectionContent
loaders={1}
loading={isLoading || isLoadingPermissions}
className="!gap-y-2"
>
<FormSectionContent
loaders={1}
loading={isLoading}
className="!gap-y-2"
<FormItemLayout
layout="flex"
label="Allow public access"
description="If disabled, only private channels will be allowed"
>
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
type="number"
<Switch
checked={field.value}
onCheckedChange={field.onChange}
disabled={!canUpdateConfig}
value={field.value || ''}
/>
</FormControl_Shadcn_>
<FormMessage_Shadcn_ />
{!!maxConn && field.value > maxConn.maxConnections * 0.5 && (
</FormItemLayout>
{isSuccessPolicies &&
!hasRealtimeMessagesPolicies &&
!allow_public &&
!isRealtimeDisabled && (
<Admonition
showIcon={false}
type="warning"
title={`Pool size is greater than 50% of the max connections (${maxConn.maxConnections}) on your database`}
description="This may result in instability and unreliability with your database connections."
/>
)}
</FormSectionContent>
</FormSection>
)}
/>
</CardContent>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="max_concurrent_users"
render={({ field }) => (
<FormSection
className="!p-0 !py-2"
header={
<FormSectionLabel
description={
<p className="text-foreground-lighter text-sm !mt-1">
Sets maximum number of concurrent clients that can connect to
your Realtime service
</p>
}
>
Max concurrent clients
</FormSectionLabel>
}
>
<FormSectionContent
loaders={1}
loading={isLoading}
className="!gap-y-2"
>
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
type="number"
disabled={!canUpdateConfig}
value={field.value || ''}
/>
</FormControl_Shadcn_>
<FormMessage_Shadcn_ />
</FormSectionContent>
</FormSection>
)}
/>
</CardContent>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="max_events_per_second"
render={({ field }) => (
<FormSection
className="!p-0 !py-2"
header={
<FormSectionLabel
description={
<p className="text-foreground-lighter text-sm !mt-1">
Sets maximum number of events per second that can be sent to
your Realtime service
</p>
}
>
Max events per second
</FormSectionLabel>
}
>
<FormSectionContent
loaders={1}
loading={isLoading}
className="!gap-y-2"
>
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
type="number"
disabled={!isUsageBillingEnabled || !canUpdateConfig}
value={field.value || ''}
/>
</FormControl_Shadcn_>
<FormMessage_Shadcn_ />
{isSuccessOrganization && !isUsageBillingEnabled && (
<Admonition showIcon={false} type="default">
<div className="flex items-center gap-x-2">
<div>
<h5 className="text-foreground mb-1">
Spend cap needs to be disabled to configure this value
</h5>
<p className="text-foreground-light">
{isFreePlan
? 'Upgrade to the Pro plan first to disable spend cap'
: 'You may adjust this setting in the organization billing settings'}
title="No Realtime RLS policies found"
description={
<>
<p className="prose max-w-full text-sm">
Private mode is {isSettingToPrivate ? 'being ' : ''}
enabled, but no RLS policies exists on the{' '}
<code className="text-code-inline">
realtime.messages
</code>{' '}
table. No messages will be received by users.
</p>
</div>
<div className="flex-grow flex items-center justify-end">
{isFreePlan ? (
<UpgradePlanButton source="realtimeSettings" plan="Pro" />
) : (
<ToggleSpendCapButton />
)}
</div>
</div>
</Admonition>
)}
</FormSectionContent>
</FormSection>
)}
/>
</CardContent>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="max_presence_events_per_second"
render={({ field }) => (
<FormSection
className="!p-0 !py-2"
header={
<FormSectionLabel
description={
<p className="text-foreground-lighter text-sm !mt-1">
Sets maximum number of presence events per second that can be
sent to your Realtime service
</p>
}
>
Max presence events per second
</FormSectionLabel>
}
>
<FormSectionContent
loaders={1}
loading={isLoading}
className="!gap-y-2"
>
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
type="number"
disabled={!isUsageBillingEnabled || !canUpdateConfig}
value={field.value || ''}
/>
</FormControl_Shadcn_>
<FormMessage_Shadcn_ />
{isSuccessOrganization && !isUsageBillingEnabled && (
<Admonition showIcon={false} type="default">
<div className="flex items-center gap-x-2">
<div>
<h5 className="text-foreground mb-1">
Spend cap needs to be disabled to configure this value
</h5>
<p className="text-foreground-light">
{isFreePlan
? 'Upgrade to the Pro plan first to disable spend cap'
: 'You may adjust this setting in the organization billing settings'}
</p>
</div>
<div className="flex-grow flex items-center justify-end">
{isFreePlan ? (
<UpgradePlanButton source="realtimeSettings" plan="Pro" />
) : (
<ToggleSpendCapButton />
)}
</div>
</div>
</Admonition>
)}
</FormSectionContent>
</FormSection>
)}
/>
</CardContent>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="max_payload_size_in_kb"
render={({ field }) => (
<FormSection
className="!p-0 !py-2"
header={
<FormSectionLabel
description={
<p className="text-foreground-lighter text-sm !mt-1">
Sets maximum number of payload size in KB that can be sent to
your Realtime service
</p>
}
>
Max payload size in KB
</FormSectionLabel>
}
>
<FormSectionContent
loaders={1}
loading={isLoading}
className="!gap-y-2"
>
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
type="number"
disabled={!isUsageBillingEnabled || !canUpdateConfig}
value={field.value || ''}
/>
</FormControl_Shadcn_>
<FormMessage_Shadcn_ />
{isSuccessOrganization && !isUsageBillingEnabled && (
<Admonition showIcon={false} type="default">
<div className="flex items-center gap-x-2">
<div>
<h5 className="text-foreground mb-1">
Spend cap needs to be disabled to configure this value
</h5>
<p className="text-foreground-light">
{isFreePlan
? 'Upgrade to the Pro plan first to disable spend cap'
: 'You may adjust this setting in the organization billing settings'}
</p>
</div>
<div className="flex-grow flex items-center justify-end">
{isFreePlan ? (
<UpgradePlanButton source="realtimeSettings" plan="Pro" />
) : (
<ToggleSpendCapButton />
)}
</div>
</div>
</Admonition>
)}
</FormSectionContent>
</FormSection>
)}
/>
</CardContent>
</>
)}
<CardFooter className="justify-between">
<div>
{isPermissionsLoaded && !canUpdateConfig && (
<p className="text-sm text-foreground-light">
You need additional permissions to update realtime settings
</p>
)}
</div>
<div className="flex items-center gap-x-2">
{form.formState.isDirty && (
<Button type="default" onClick={() => form.reset(data as any)}>
Cancel
</Button>
)}
<Button
type="primary"
htmlType="submit"
form={formId}
disabled={!canUpdateConfig || isUpdatingConfig || !form.formState.isDirty}
loading={isUpdatingConfig}
>
Save changes
<Button asChild type="default" className="mt-2">
<Link href={`/project/${projectRef}/realtime/policies`}>
Create policy
</Link>
</Button>
</>
}
/>
)}
</FormSectionContent>
</FormSection>
)}
/>
</CardContent>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="connection_pool"
render={({ field }) => (
<FormSection
className="!p-0 !py-2"
header={
<FormSectionLabel
description={
<p className="text-foreground-lighter text-sm !mt-1">
Realtime Authorization uses this database pool to check client
access
</p>
}
>
Database connection pool size
</FormSectionLabel>
}
>
<FormSectionContent loaders={1} loading={isLoading} className="!gap-y-2">
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
type="number"
disabled={!canUpdateConfig}
value={field.value || ''}
/>
</FormControl_Shadcn_>
<FormMessage_Shadcn_ />
{!!maxConn && field.value > maxConn.maxConnections * 0.5 && (
<Admonition
showIcon={false}
type="warning"
title={`Pool size is greater than 50% of the max connections (${maxConn.maxConnections}) on your database`}
description="This may result in instability and unreliability with your database connections."
/>
)}
</FormSectionContent>
</FormSection>
)}
/>
</CardContent>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="max_concurrent_users"
render={({ field }) => (
<FormSection
className="!p-0 !py-2"
header={
<FormSectionLabel
description={
<p className="text-foreground-lighter text-sm !mt-1">
Sets maximum number of concurrent clients that can connect to your
Realtime service
</p>
}
>
Max concurrent clients
</FormSectionLabel>
}
>
<FormSectionContent loaders={1} loading={isLoading} className="!gap-y-2">
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
type="number"
disabled={!canUpdateConfig}
value={field.value || ''}
/>
</FormControl_Shadcn_>
<FormMessage_Shadcn_ />
</FormSectionContent>
</FormSection>
)}
/>
</CardContent>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="max_events_per_second"
render={({ field }) => (
<FormSection
className="!p-0 !py-2"
header={
<FormSectionLabel
description={
<p className="text-foreground-lighter text-sm !mt-1">
Sets maximum number of events per second that can be sent to your
Realtime service
</p>
}
>
Max events per second
</FormSectionLabel>
}
>
<FormSectionContent loaders={1} loading={isLoading} className="!gap-y-2">
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
type="number"
disabled={!isUsageBillingEnabled || !canUpdateConfig}
value={field.value || ''}
/>
</FormControl_Shadcn_>
<FormMessage_Shadcn_ />
{isSuccessOrganization && !isUsageBillingEnabled && (
<Admonition showIcon={false} type="default">
<div className="flex items-center gap-x-2">
<div>
<h5 className="text-foreground mb-1">
Spend cap needs to be disabled to configure this value
</h5>
<p className="text-foreground-light">
{isFreePlan
? 'Upgrade to the Pro plan first to disable spend cap'
: 'You may adjust this setting in the organization billing settings'}
</p>
</div>
<div className="flex-grow flex items-center justify-end">
{isFreePlan ? (
<UpgradePlanButton source="realtimeSettings" plan="Pro" />
) : (
<ToggleSpendCapButton />
)}
</div>
</div>
</Admonition>
)}
</FormSectionContent>
</FormSection>
)}
/>
</CardContent>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="max_presence_events_per_second"
render={({ field }) => (
<FormSection
className="!p-0 !py-2"
header={
<FormSectionLabel
description={
<p className="text-foreground-lighter text-sm !mt-1">
Sets maximum number of presence events per second that can be sent
to your Realtime service
</p>
}
>
Max presence events per second
</FormSectionLabel>
}
>
<FormSectionContent loaders={1} loading={isLoading} className="!gap-y-2">
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
type="number"
disabled={!isUsageBillingEnabled || !canUpdateConfig}
value={field.value || ''}
/>
</FormControl_Shadcn_>
<FormMessage_Shadcn_ />
{isSuccessOrganization && !isUsageBillingEnabled && (
<Admonition showIcon={false} type="default">
<div className="flex items-center gap-x-2">
<div>
<h5 className="text-foreground mb-1">
Spend cap needs to be disabled to configure this value
</h5>
<p className="text-foreground-light">
{isFreePlan
? 'Upgrade to the Pro plan first to disable spend cap'
: 'You may adjust this setting in the organization billing settings'}
</p>
</div>
<div className="flex-grow flex items-center justify-end">
{isFreePlan ? (
<UpgradePlanButton source="realtimeSettings" plan="Pro" />
) : (
<ToggleSpendCapButton />
)}
</div>
</div>
</Admonition>
)}
</FormSectionContent>
</FormSection>
)}
/>
</CardContent>
<CardContent>
<FormField_Shadcn_
control={form.control}
name="max_payload_size_in_kb"
render={({ field }) => (
<FormSection
className="!p-0 !py-2"
header={
<FormSectionLabel
description={
<p className="text-foreground-lighter text-sm !mt-1">
Sets maximum number of payload size in KB that can be sent to your
Realtime service
</p>
}
>
Max payload size in KB
</FormSectionLabel>
}
>
<FormSectionContent loaders={1} loading={isLoading} className="!gap-y-2">
<FormControl_Shadcn_>
<Input_Shadcn_
{...field}
type="number"
disabled={!isUsageBillingEnabled || !canUpdateConfig}
value={field.value || ''}
/>
</FormControl_Shadcn_>
<FormMessage_Shadcn_ />
{isSuccessOrganization && !isUsageBillingEnabled && (
<Admonition showIcon={false} type="default">
<div className="flex items-center gap-x-2">
<div>
<h5 className="text-foreground mb-1">
Spend cap needs to be disabled to configure this value
</h5>
<p className="text-foreground-light">
{isFreePlan
? 'Upgrade to the Pro plan first to disable spend cap'
: 'You may adjust this setting in the organization billing settings'}
</p>
</div>
<div className="flex-grow flex items-center justify-end">
{isFreePlan ? (
<UpgradePlanButton source="realtimeSettings" plan="Pro" />
) : (
<ToggleSpendCapButton />
)}
</div>
</div>
</Admonition>
)}
</FormSectionContent>
</FormSection>
)}
/>
</CardContent>
</>
)}
<CardFooter className="justify-between">
<div>
{isPermissionsLoaded && !canUpdateConfig && (
<p className="text-sm text-foreground-light">
You need additional permissions to update realtime settings
</p>
)}
</div>
<div className="flex items-center gap-x-2">
{form.formState.isDirty && (
<Button type="default" onClick={() => form.reset(data as any)}>
Cancel
</Button>
</div>
</CardFooter>
</Card>
)}
</form>
</Form_Shadcn_>
</ScaffoldSection>
)}
<Button
type="primary"
htmlType="submit"
form={formId}
disabled={!canUpdateConfig || isUpdatingConfig || !form.formState.isDirty}
loading={isUpdatingConfig}
>
Save changes
</Button>
</div>
</CardFooter>
</Card>
)}
</form>
</Form_Shadcn_>
<ConfirmationModal
visible={isConfirmNextModalOpen}
@@ -1,35 +1,48 @@
import { RealtimePolicies } from 'components/interfaces/Realtime/Policies'
import type { NextPageWithLayout } from 'types'
import DefaultLayout from 'components/layouts/DefaultLayout'
import { PageLayout } from 'components/layouts/PageLayout/PageLayout'
import RealtimeLayout from 'components/layouts/RealtimeLayout/RealtimeLayout'
import { ScaffoldContainer, ScaffoldSection } from 'components/layouts/Scaffold'
import { DocsButton } from 'components/ui/DocsButton'
import { DOCS_URL } from 'lib/constants'
import type { NextPageWithLayout } from 'types'
import { PageContainer } from 'ui-patterns/PageContainer'
import {
PageHeader,
PageHeaderAside,
PageHeaderDescription,
PageHeaderMeta,
PageHeaderSummary,
PageHeaderTitle,
} from 'ui-patterns/PageHeader'
import { PageSection, PageSectionContent } from 'ui-patterns/PageSection'
const RealtimePoliciesPage: NextPageWithLayout = () => {
return (
<ScaffoldContainer size="full">
<ScaffoldSection isFullWidth>
<RealtimePolicies />
</ScaffoldSection>
</ScaffoldContainer>
<>
<PageHeader size="large">
<PageHeaderMeta>
<PageHeaderSummary>
<PageHeaderTitle>Policies</PageHeaderTitle>
<PageHeaderDescription>Control access to your realtime channels</PageHeaderDescription>
</PageHeaderSummary>
<PageHeaderAside>
<DocsButton href={`${DOCS_URL}/guides/realtime/authorization`} />
</PageHeaderAside>
</PageHeaderMeta>
</PageHeader>
<PageContainer size="large">
<PageSection>
<PageSectionContent>
<RealtimePolicies />
</PageSectionContent>
</PageSection>
</PageContainer>
</>
)
}
RealtimePoliciesPage.getLayout = (page) => (
<DefaultLayout>
<RealtimeLayout title="Policies">
<PageLayout
title="Policies"
subtitle="Control access to your realtime channels"
primaryActions={<DocsButton href={`${DOCS_URL}/guides/realtime/authorization`} />}
size="large"
>
{page}
</PageLayout>
</RealtimeLayout>
<RealtimeLayout title="Policies">{page}</RealtimeLayout>
</DefaultLayout>
)
@@ -1,29 +1,51 @@
import type { NextPageWithLayout } from 'types'
import { RealtimeSettings } from 'components/interfaces/Realtime/RealtimeSettings'
import DefaultLayout from 'components/layouts/DefaultLayout'
import { PageLayout } from 'components/layouts/PageLayout/PageLayout'
import RealtimeLayout from 'components/layouts/RealtimeLayout/RealtimeLayout'
import { ScaffoldContainer } from 'components/layouts/Scaffold'
import { DocsButton } from 'components/ui/DocsButton'
import { DOCS_URL } from 'lib/constants'
import type { NextPageWithLayout } from 'types'
import { RealtimeSettings } from 'components/interfaces/Realtime/RealtimeSettings'
import { PageContainer } from 'ui-patterns/PageContainer'
import {
PageHeader,
PageHeaderAside,
PageHeaderDescription,
PageHeaderMeta,
PageHeaderSummary,
PageHeaderTitle,
} from 'ui-patterns/PageHeader'
import { PageSection, PageSectionContent } from 'ui-patterns/PageSection'
const RealtimePoliciesPage: NextPageWithLayout = () => {
return <RealtimeSettings />
const RealtimeSettingsPage: NextPageWithLayout = () => {
return (
<>
<PageHeader size="large">
<PageHeaderMeta>
<PageHeaderSummary>
<PageHeaderTitle>Realtime Settings</PageHeaderTitle>
<PageHeaderDescription>
Configure your project's Realtime settings
</PageHeaderDescription>
</PageHeaderSummary>
<PageHeaderAside>
<DocsButton href={`${DOCS_URL}/guides/realtime/settings`} />
</PageHeaderAside>
</PageHeaderMeta>
</PageHeader>
<PageContainer size="large">
<PageSection>
<PageSectionContent>
<RealtimeSettings />
</PageSectionContent>
</PageSection>
</PageContainer>
</>
)
}
RealtimePoliciesPage.getLayout = (page) => (
RealtimeSettingsPage.getLayout = (page) => (
<DefaultLayout>
<RealtimeLayout title="Realtime Settings">
<PageLayout
title="Realtime Settings"
subtitle="Configure your project's Realtime settings"
primaryActions={<DocsButton href={`${DOCS_URL}/guides/realtime/settings`} />}
>
<ScaffoldContainer>{page}</ScaffoldContainer>
</PageLayout>
</RealtimeLayout>
<RealtimeLayout title="Realtime Settings">{page}</RealtimeLayout>
</DefaultLayout>
)
export default RealtimePoliciesPage
export default RealtimeSettingsPage