fix!: some custom components were not handled properly if they are RSCs (#6315)
**Breaking:** The following, exported components now need the `payload` object as a prop rather than the `config` object: - `RenderCustomComponent` (optional) - `Logo` - `DefaultTemplate` - `DefaultNav`
This commit is contained in:
@@ -77,6 +77,7 @@ export const Account: React.FC<AdminViewProps> = ({ initPageResult, params, sear
|
||||
}
|
||||
DefaultComponent={EditView}
|
||||
componentProps={viewComponentProps}
|
||||
payload={payload}
|
||||
/>
|
||||
</FormQueryParamsProvider>
|
||||
</DocumentInfoProvider>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import type { Permissions } from 'payload/auth'
|
||||
import type { SanitizedConfig, VisibleEntities } from 'payload/types'
|
||||
import type { Payload, SanitizedConfig, VisibleEntities } from 'payload/types'
|
||||
|
||||
import { Gutter } from '@payloadcms/ui/elements/Gutter'
|
||||
import { SetStepNav } from '@payloadcms/ui/elements/StepNav'
|
||||
import { WithServerSideProps } from '@payloadcms/ui/elements/WithServerSideProps'
|
||||
import { SetViewActions } from '@payloadcms/ui/providers/Actions'
|
||||
import React from 'react'
|
||||
|
||||
@@ -14,6 +15,7 @@ const baseClass = 'dashboard'
|
||||
export type DashboardProps = {
|
||||
Link: React.ComponentType<any>
|
||||
config: SanitizedConfig
|
||||
payload: Payload
|
||||
permissions: Permissions
|
||||
visibleEntities: VisibleEntities
|
||||
}
|
||||
@@ -26,24 +28,36 @@ export const DefaultDashboard: React.FC<DashboardProps> = (props) => {
|
||||
components: { afterDashboard, beforeDashboard },
|
||||
},
|
||||
},
|
||||
payload,
|
||||
permissions,
|
||||
visibleEntities,
|
||||
} = props
|
||||
|
||||
const BeforeDashboards = Array.isArray(beforeDashboard)
|
||||
? beforeDashboard.map((Component, i) => (
|
||||
<WithServerSideProps Component={Component} key={i} payload={payload} />
|
||||
))
|
||||
: null
|
||||
|
||||
const AfterDashboards = Array.isArray(afterDashboard)
|
||||
? afterDashboard.map((Component, i) => (
|
||||
<WithServerSideProps Component={Component} key={i} payload={payload} />
|
||||
))
|
||||
: null
|
||||
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
<SetStepNav nav={[]} />
|
||||
<SetViewActions actions={[]} />
|
||||
<Gutter className={`${baseClass}__wrap`}>
|
||||
{Array.isArray(beforeDashboard) &&
|
||||
beforeDashboard.map((Component, i) => <Component key={i} />)}
|
||||
{Array.isArray(BeforeDashboards) && BeforeDashboards.map((Component) => Component)}
|
||||
|
||||
<DefaultDashboardClient
|
||||
Link={Link}
|
||||
permissions={permissions}
|
||||
visibleEntities={visibleEntities}
|
||||
/>
|
||||
{Array.isArray(afterDashboard) &&
|
||||
afterDashboard.map((Component, i) => <Component key={i} />)}
|
||||
{Array.isArray(AfterDashboards) && AfterDashboards.map((Component) => Component)}
|
||||
</Gutter>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -18,6 +18,7 @@ export const Dashboard: React.FC<AdminViewProps> = ({ initPageResult }) => {
|
||||
permissions,
|
||||
req: {
|
||||
payload: { config },
|
||||
payload,
|
||||
user,
|
||||
},
|
||||
visibleEntities,
|
||||
@@ -25,7 +26,7 @@ export const Dashboard: React.FC<AdminViewProps> = ({ initPageResult }) => {
|
||||
|
||||
const CustomDashboardComponent = config.admin.components?.views?.Dashboard
|
||||
|
||||
const viewComponentProps: DashboardProps = {
|
||||
const viewComponentProps: Omit<DashboardProps, 'payload'> = {
|
||||
Link,
|
||||
config,
|
||||
permissions,
|
||||
@@ -41,6 +42,7 @@ export const Dashboard: React.FC<AdminViewProps> = ({ initPageResult }) => {
|
||||
}
|
||||
DefaultComponent={DefaultDashboard}
|
||||
componentProps={viewComponentProps}
|
||||
payload={payload}
|
||||
/>
|
||||
</Fragment>
|
||||
)
|
||||
|
||||
@@ -220,6 +220,7 @@ export const Document: React.FC<AdminViewProps> = async ({
|
||||
CustomComponent={ViewOverride || CustomView}
|
||||
DefaultComponent={DefaultView}
|
||||
componentProps={viewComponentProps}
|
||||
payload={payload}
|
||||
/>
|
||||
)}
|
||||
</FormQueryParamsProvider>
|
||||
|
||||
@@ -142,6 +142,7 @@ export const ListView: React.FC<AdminViewProps> = async ({ initPageResult, searc
|
||||
CustomComponent={CustomListView}
|
||||
DefaultComponent={DefaultListView}
|
||||
componentProps={viewComponentProps}
|
||||
payload={payload}
|
||||
/>
|
||||
</TableColumnsProvider>
|
||||
</ListQueryProvider>
|
||||
|
||||
@@ -48,7 +48,7 @@ export const LoginView: React.FC<AdminViewProps> = ({ initPageResult, searchPara
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={`${loginBaseClass}__brand`}>
|
||||
<Logo config={config} />
|
||||
<Logo payload={payload} />
|
||||
</div>
|
||||
{Array.isArray(BeforeLogins) && BeforeLogins.map((Component) => Component)}
|
||||
{!collectionConfig?.auth?.disableLocalStrategy && <LoginForm searchParams={searchParams} />}
|
||||
|
||||
@@ -60,7 +60,7 @@ export const NotFoundPage = async ({
|
||||
<Fragment>
|
||||
<HydrateClientUser permissions={initPageResult.permissions} user={initPageResult.req.user} />
|
||||
<DefaultTemplate
|
||||
config={initPageResult.req.payload.config}
|
||||
payload={initPageResult.req.payload}
|
||||
visibleEntities={initPageResult.visibleEntities}
|
||||
>
|
||||
<NotFoundClient />
|
||||
|
||||
@@ -87,7 +87,10 @@ export const RootPage = async ({
|
||||
<MinimalTemplate className={templateClassName}>{RenderedView}</MinimalTemplate>
|
||||
)}
|
||||
{templateType === 'default' && (
|
||||
<DefaultTemplate config={config} visibleEntities={initPageResult.visibleEntities}>
|
||||
<DefaultTemplate
|
||||
payload={initPageResult?.req.payload}
|
||||
visibleEntities={initPageResult.visibleEntities}
|
||||
>
|
||||
{RenderedView}
|
||||
</DefaultTemplate>
|
||||
)}
|
||||
|
||||
@@ -18,6 +18,7 @@ export const Verify: React.FC<AdminViewProps> = async ({ initPageResult, params
|
||||
|
||||
const {
|
||||
payload: { config },
|
||||
payload,
|
||||
} = req
|
||||
|
||||
const {
|
||||
@@ -42,7 +43,7 @@ export const Verify: React.FC<AdminViewProps> = async ({ initPageResult, params
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className={`${verifyBaseClass}__brand`}>
|
||||
<Logo config={config} />
|
||||
<Logo payload={payload} />
|
||||
</div>
|
||||
<h2>{textToRender}</h2>
|
||||
</React.Fragment>
|
||||
|
||||
@@ -121,6 +121,9 @@ type Admin = {
|
||||
Cell?: CustomComponent
|
||||
Description?: DescriptionComponent
|
||||
Field?: CustomComponent
|
||||
/**
|
||||
* The Filter component has to be a client component
|
||||
*/
|
||||
Filter?: React.ComponentType<any>
|
||||
}
|
||||
/**
|
||||
@@ -447,6 +450,9 @@ export type UIField = {
|
||||
components?: {
|
||||
Cell?: CustomComponent
|
||||
Field: CustomComponent
|
||||
/**
|
||||
* The Filter component has to be a client component
|
||||
*/
|
||||
Filter?: React.ComponentType<any>
|
||||
}
|
||||
condition?: Condition
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { SanitizedConfig } from 'payload/types'
|
||||
import type { Payload } from 'payload/types'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
@@ -9,16 +9,18 @@ import './index.scss'
|
||||
|
||||
const baseClass = 'nav'
|
||||
|
||||
import { WithServerSideProps } from '@payloadcms/ui/elements/WithServerSideProps'
|
||||
|
||||
import { DefaultNavClient } from './index.client.js'
|
||||
|
||||
export type NavProps = {
|
||||
config: SanitizedConfig
|
||||
payload: Payload
|
||||
}
|
||||
|
||||
export const DefaultNav: React.FC<NavProps> = (props) => {
|
||||
const { config } = props
|
||||
const { payload } = props
|
||||
|
||||
if (!config) {
|
||||
if (!payload?.config) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -26,15 +28,28 @@ export const DefaultNav: React.FC<NavProps> = (props) => {
|
||||
admin: {
|
||||
components: { afterNavLinks, beforeNavLinks },
|
||||
},
|
||||
} = config
|
||||
} = payload.config
|
||||
|
||||
const BeforeNavLinks = Array.isArray(beforeNavLinks)
|
||||
? beforeNavLinks.map((Component, i) => (
|
||||
<WithServerSideProps Component={Component} key={i} payload={payload} />
|
||||
))
|
||||
: null
|
||||
|
||||
const AfterNavLinks = Array.isArray(afterNavLinks)
|
||||
? afterNavLinks.map((Component, i) => (
|
||||
<WithServerSideProps Component={Component} key={i} payload={payload} />
|
||||
))
|
||||
: null
|
||||
|
||||
return (
|
||||
<NavWrapper baseClass={baseClass}>
|
||||
<nav className={`${baseClass}__wrap`}>
|
||||
{Array.isArray(beforeNavLinks) &&
|
||||
beforeNavLinks.map((Component, i) => <Component key={i} />)}
|
||||
{Array.isArray(BeforeNavLinks) && BeforeNavLinks.map((Component) => Component)}
|
||||
|
||||
<DefaultNavClient />
|
||||
{Array.isArray(afterNavLinks) && afterNavLinks.map((Component, i) => <Component key={i} />)}
|
||||
{Array.isArray(AfterNavLinks) && AfterNavLinks.map((Component) => Component)}
|
||||
|
||||
<div className={`${baseClass}__controls`}>
|
||||
<Logout />
|
||||
</div>
|
||||
|
||||
@@ -1,20 +1,27 @@
|
||||
import type { Payload } from 'payload'
|
||||
|
||||
import { WithServerSideProps } from '@payloadcms/ui/elements/WithServerSideProps'
|
||||
import React from 'react'
|
||||
|
||||
export type RenderCustomComponentProps = {
|
||||
CustomComponent?: React.ComponentType<any>
|
||||
DefaultComponent: React.ComponentType<any>
|
||||
componentProps?: Record<string, any>
|
||||
/**
|
||||
* Payload automatically gets added to the component if it's an RSC
|
||||
*/
|
||||
payload?: Payload
|
||||
}
|
||||
|
||||
export const RenderCustomComponent: React.FC<RenderCustomComponentProps> = (props) => {
|
||||
const { CustomComponent, DefaultComponent, componentProps = {} } = props
|
||||
|
||||
if (CustomComponent) {
|
||||
return <CustomComponent {...componentProps} />
|
||||
return <WithServerSideProps Component={CustomComponent} payload={null} {...componentProps} />
|
||||
}
|
||||
|
||||
if (DefaultComponent) {
|
||||
return <DefaultComponent {...componentProps} />
|
||||
return <WithServerSideProps Component={DefaultComponent} payload={null} {...componentProps} />
|
||||
}
|
||||
|
||||
return null
|
||||
|
||||
@@ -36,8 +36,6 @@ export type Props = {
|
||||
}) => void
|
||||
}
|
||||
|
||||
import type { RelationshipFieldProps } from '@payloadcms/ui/fields/Relationship'
|
||||
|
||||
import { RenderCustomComponent } from '../../../elements/RenderCustomComponent/index.js'
|
||||
import { useDebounce } from '../../../hooks/useDebounce.js'
|
||||
import { Button } from '../../Button/index.js'
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { SanitizedConfig } from 'payload/config'
|
||||
import type { Payload } from 'payload'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
@@ -33,9 +33,9 @@ const PayloadLogo: React.FC = () => (
|
||||
)
|
||||
|
||||
export const Logo: React.FC<{
|
||||
config: SanitizedConfig
|
||||
payload: Payload
|
||||
}> = (props) => {
|
||||
const { config } = props
|
||||
const { payload } = props
|
||||
|
||||
const {
|
||||
admin: {
|
||||
@@ -45,7 +45,13 @@ export const Logo: React.FC<{
|
||||
},
|
||||
} = {},
|
||||
} = {},
|
||||
} = config
|
||||
} = payload.config
|
||||
|
||||
return <RenderCustomComponent CustomComponent={CustomLogo} DefaultComponent={PayloadLogo} />
|
||||
return (
|
||||
<RenderCustomComponent
|
||||
CustomComponent={CustomLogo}
|
||||
DefaultComponent={PayloadLogo}
|
||||
payload={payload}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { SanitizedConfig, VisibleEntities } from 'payload/types'
|
||||
import type { Payload, SanitizedConfig, VisibleEntities } from 'payload/types'
|
||||
|
||||
import { EntityVisibilityProvider } from '@payloadcms/ui/providers/EntityVisibility'
|
||||
import React from 'react'
|
||||
@@ -18,28 +18,26 @@ const baseClass = 'template-default'
|
||||
export type DefaultTemplateProps = {
|
||||
children?: React.ReactNode
|
||||
className?: string
|
||||
config: Promise<SanitizedConfig> | SanitizedConfig
|
||||
payload: Payload
|
||||
visibleEntities?: VisibleEntities
|
||||
}
|
||||
|
||||
export const DefaultTemplate: React.FC<DefaultTemplateProps> = async ({
|
||||
export const DefaultTemplate: React.FC<DefaultTemplateProps> = ({
|
||||
children,
|
||||
className,
|
||||
config: configPromise,
|
||||
payload,
|
||||
visibleEntities,
|
||||
}) => {
|
||||
const config = await configPromise
|
||||
|
||||
const {
|
||||
admin: {
|
||||
components: { Nav: CustomNav } = {
|
||||
Nav: undefined,
|
||||
},
|
||||
} = {},
|
||||
} = config || {}
|
||||
} = payload.config || {}
|
||||
|
||||
const navProps: NavProps = {
|
||||
config,
|
||||
payload,
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -55,6 +53,7 @@ export const DefaultTemplate: React.FC<DefaultTemplateProps> = async ({
|
||||
CustomComponent={CustomNav}
|
||||
DefaultComponent={DefaultNav}
|
||||
componentProps={navProps}
|
||||
payload={payload}
|
||||
/>
|
||||
<div className={`${baseClass}__wrap`}>
|
||||
<AppHeader />
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { AdminViewProps } from 'payload/types'
|
||||
|
||||
import { DefaultTemplate } from '@payloadcms/ui/templates/Default'
|
||||
import LinkImport from 'next/link.js'
|
||||
import { redirect } from 'next/navigation.js'
|
||||
@@ -18,15 +20,15 @@ export const CustomDefaultView: React.FC<AdminViewProps> = ({ initPageResult })
|
||||
const {
|
||||
permissions,
|
||||
req: {
|
||||
i18n,
|
||||
payload,
|
||||
payload: {
|
||||
config,
|
||||
config: {
|
||||
routes: { admin: adminRoute },
|
||||
},
|
||||
},
|
||||
user,
|
||||
},
|
||||
visibleEntities,
|
||||
} = initPageResult
|
||||
|
||||
// If an unauthorized user tries to navigate straight to this page,
|
||||
@@ -36,7 +38,7 @@ export const CustomDefaultView: React.FC<AdminViewProps> = ({ initPageResult })
|
||||
}
|
||||
|
||||
return (
|
||||
<DefaultTemplate config={config} i18n={i18n} permissions={permissions} user={user}>
|
||||
<DefaultTemplate payload={payload} visibleEntities={visibleEntities}>
|
||||
<SetStepNav
|
||||
nav={[
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user