perf: significantly reduce HTML we send to the client. Up to 4x smaller (#9321)
The biggest difference comes from calling `RenderServerComponent` as a function, instead of rendering it by using `<RenderServerComponent`. This gets rid of wasteful blocks of codes sent to the client that look like this:  HTML size comparison: ## Admin test suite | View | Before | After | |------|---------|--------| | Dashboard | 331 kB | 83 kB | | collections/custom-views-one Edit | 285 kB | 76.6 kB | ## Fields test suite | View | Before | After | |------|---------|--------| | collections/lexical Edit | 189 kB | 94.4 kB | | collections/lexical List | 152 kB | 62.9 kB | ## Community test suite | View | Before | After | |------|---------|--------| | Dashboard | 78.9 kB | 43.1 kB |
This commit is contained in:
@@ -75,16 +75,16 @@ export const DocumentTab: React.FC<
|
|||||||
{Pill || Pill_Component ? (
|
{Pill || Pill_Component ? (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
|
||||||
<RenderServerComponent
|
{RenderServerComponent({
|
||||||
Component={Pill}
|
Component: Pill,
|
||||||
Fallback={Pill_Component}
|
Fallback: Pill_Component,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
serverProps={{
|
serverProps: {
|
||||||
i18n,
|
i18n,
|
||||||
payload,
|
payload,
|
||||||
permissions,
|
permissions,
|
||||||
}}
|
},
|
||||||
/>
|
})}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
) : null}
|
) : null}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -80,23 +80,21 @@ export const DocumentTabs: React.FC<{
|
|||||||
const { path, tab } = CustomView
|
const { path, tab } = CustomView
|
||||||
|
|
||||||
if (tab.Component) {
|
if (tab.Component) {
|
||||||
return (
|
return RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps: {
|
||||||
clientProps={{
|
path,
|
||||||
path,
|
},
|
||||||
}}
|
Component: tab.Component,
|
||||||
Component={tab.Component}
|
importMap: payload.importMap,
|
||||||
importMap={payload.importMap}
|
key: `tab-custom-${index}`,
|
||||||
key={`tab-custom-${index}`}
|
serverProps: {
|
||||||
serverProps={{
|
collectionConfig,
|
||||||
collectionConfig,
|
globalConfig,
|
||||||
globalConfig,
|
i18n,
|
||||||
i18n,
|
payload,
|
||||||
payload,
|
permissions,
|
||||||
permissions,
|
},
|
||||||
}}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { ServerProps } from 'payload'
|
import type { ServerProps } from 'payload'
|
||||||
|
import type React from 'react'
|
||||||
|
|
||||||
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
|
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
|
||||||
import { PayloadLogo } from '@payloadcms/ui/shared'
|
import { PayloadLogo } from '@payloadcms/ui/shared'
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
export const Logo: React.FC<ServerProps> = (props) => {
|
export const Logo: React.FC<ServerProps> = (props) => {
|
||||||
const { i18n, locale, params, payload, permissions, searchParams, user } = props
|
const { i18n, locale, params, payload, permissions, searchParams, user } = props
|
||||||
@@ -17,20 +17,18 @@ export const Logo: React.FC<ServerProps> = (props) => {
|
|||||||
} = {},
|
} = {},
|
||||||
} = payload.config
|
} = payload.config
|
||||||
|
|
||||||
return (
|
return RenderServerComponent({
|
||||||
<RenderServerComponent
|
Component: CustomLogo,
|
||||||
Component={CustomLogo}
|
Fallback: PayloadLogo,
|
||||||
Fallback={PayloadLogo}
|
importMap: payload.importMap,
|
||||||
importMap={payload.importMap}
|
serverProps: {
|
||||||
serverProps={{
|
i18n,
|
||||||
i18n,
|
locale,
|
||||||
locale,
|
params,
|
||||||
params,
|
payload,
|
||||||
payload,
|
permissions,
|
||||||
permissions,
|
searchParams,
|
||||||
searchParams,
|
user,
|
||||||
user,
|
},
|
||||||
}}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,13 +59,28 @@ export const DefaultNav: React.FC<NavProps> = async (props) => {
|
|||||||
|
|
||||||
const navPreferences = await getNavPrefs({ payload, user })
|
const navPreferences = await getNavPrefs({ payload, user })
|
||||||
|
|
||||||
|
const LogoutComponent = RenderServerComponent({
|
||||||
|
Component: logout?.Button,
|
||||||
|
Fallback: Logout,
|
||||||
|
importMap: payload.importMap,
|
||||||
|
serverProps: {
|
||||||
|
i18n,
|
||||||
|
locale,
|
||||||
|
params,
|
||||||
|
payload,
|
||||||
|
permissions,
|
||||||
|
searchParams,
|
||||||
|
user,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NavWrapper baseClass={baseClass}>
|
<NavWrapper baseClass={baseClass}>
|
||||||
<nav className={`${baseClass}__wrap`}>
|
<nav className={`${baseClass}__wrap`}>
|
||||||
<RenderServerComponent
|
{RenderServerComponent({
|
||||||
Component={beforeNavLinks}
|
Component: beforeNavLinks,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
serverProps={{
|
serverProps: {
|
||||||
i18n,
|
i18n,
|
||||||
locale,
|
locale,
|
||||||
params,
|
params,
|
||||||
@@ -73,13 +88,13 @@ export const DefaultNav: React.FC<NavProps> = async (props) => {
|
|||||||
permissions,
|
permissions,
|
||||||
searchParams,
|
searchParams,
|
||||||
user,
|
user,
|
||||||
}}
|
},
|
||||||
/>
|
})}
|
||||||
<DefaultNavClient groups={groups} navPreferences={navPreferences} />
|
<DefaultNavClient groups={groups} navPreferences={navPreferences} />
|
||||||
<RenderServerComponent
|
{RenderServerComponent({
|
||||||
Component={afterNavLinks}
|
Component: afterNavLinks,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
serverProps={{
|
serverProps: {
|
||||||
i18n,
|
i18n,
|
||||||
locale,
|
locale,
|
||||||
params,
|
params,
|
||||||
@@ -87,24 +102,9 @@ export const DefaultNav: React.FC<NavProps> = async (props) => {
|
|||||||
permissions,
|
permissions,
|
||||||
searchParams,
|
searchParams,
|
||||||
user,
|
user,
|
||||||
}}
|
},
|
||||||
/>
|
})}
|
||||||
<div className={`${baseClass}__controls`}>
|
<div className={`${baseClass}__controls`}>{LogoutComponent}</div>
|
||||||
<RenderServerComponent
|
|
||||||
Component={logout?.Button}
|
|
||||||
Fallback={Logout}
|
|
||||||
importMap={payload.importMap}
|
|
||||||
serverProps={{
|
|
||||||
i18n,
|
|
||||||
locale,
|
|
||||||
params,
|
|
||||||
payload,
|
|
||||||
permissions,
|
|
||||||
searchParams,
|
|
||||||
user,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</nav>
|
</nav>
|
||||||
<div className={`${baseClass}__header`}>
|
<div className={`${baseClass}__header`}>
|
||||||
<div className={`${baseClass}__header-content`}>
|
<div className={`${baseClass}__header-content`}>
|
||||||
|
|||||||
@@ -11,20 +11,18 @@ type Args = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function NestProviders({ children, importMap, providers }: Args): React.ReactNode {
|
export function NestProviders({ children, importMap, providers }: Args): React.ReactNode {
|
||||||
return (
|
return RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps: {
|
||||||
clientProps={{
|
children:
|
||||||
children:
|
providers.length > 1 ? (
|
||||||
providers.length > 1 ? (
|
<NestProviders importMap={importMap} providers={providers.slice(1)}>
|
||||||
<NestProviders importMap={importMap} providers={providers.slice(1)}>
|
{children}
|
||||||
{children}
|
</NestProviders>
|
||||||
</NestProviders>
|
) : (
|
||||||
) : (
|
children
|
||||||
children
|
),
|
||||||
),
|
},
|
||||||
}}
|
Component: providers[0],
|
||||||
Component={providers[0]}
|
importMap,
|
||||||
importMap={importMap}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,14 @@ export const OGImage: React.FC<{
|
|||||||
leader,
|
leader,
|
||||||
title,
|
title,
|
||||||
}) => {
|
}) => {
|
||||||
|
const IconComponent = RenderServerComponent({
|
||||||
|
clientProps: {
|
||||||
|
fill: 'white',
|
||||||
|
},
|
||||||
|
Component: Icon,
|
||||||
|
Fallback,
|
||||||
|
importMap,
|
||||||
|
})
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -95,14 +103,7 @@ export const OGImage: React.FC<{
|
|||||||
width: '38px',
|
width: '38px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RenderServerComponent
|
{IconComponent}
|
||||||
clientProps={{
|
|
||||||
fill: 'white',
|
|
||||||
}}
|
|
||||||
Component={Icon}
|
|
||||||
Fallback={Fallback}
|
|
||||||
importMap={importMap}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -56,13 +56,15 @@ export const DefaultTemplate: React.FC<DefaultTemplateProps> = ({
|
|||||||
? viewActions.reduce((acc, action) => {
|
? viewActions.reduce((acc, action) => {
|
||||||
if (action) {
|
if (action) {
|
||||||
if (typeof action === 'object') {
|
if (typeof action === 'object') {
|
||||||
acc[action.path] = (
|
acc[action.path] = RenderServerComponent({
|
||||||
<RenderServerComponent Component={action} importMap={payload.importMap} />
|
Component: action,
|
||||||
)
|
importMap: payload.importMap,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
acc[action] = (
|
acc[action] = RenderServerComponent({
|
||||||
<RenderServerComponent Component={action} importMap={payload.importMap} />
|
Component: action,
|
||||||
)
|
importMap: payload.importMap,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,15 +74,32 @@ export const DefaultTemplate: React.FC<DefaultTemplateProps> = ({
|
|||||||
}
|
}
|
||||||
}, [viewActions, payload])
|
}, [viewActions, payload])
|
||||||
|
|
||||||
|
const NavComponent = RenderServerComponent({
|
||||||
|
clientProps: { clientProps: { visibleEntities } },
|
||||||
|
Component: CustomNav,
|
||||||
|
Fallback: DefaultNav,
|
||||||
|
importMap: payload.importMap,
|
||||||
|
serverProps: {
|
||||||
|
i18n,
|
||||||
|
locale,
|
||||||
|
params,
|
||||||
|
payload,
|
||||||
|
permissions,
|
||||||
|
searchParams,
|
||||||
|
user,
|
||||||
|
visibleEntities,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<EntityVisibilityProvider visibleEntities={visibleEntities}>
|
<EntityVisibilityProvider visibleEntities={visibleEntities}>
|
||||||
<BulkUploadProvider>
|
<BulkUploadProvider>
|
||||||
<ActionsProvider Actions={Actions}>
|
<ActionsProvider Actions={Actions}>
|
||||||
<RenderServerComponent
|
{RenderServerComponent({
|
||||||
clientProps={{ clientProps: { visibleEntities } }}
|
clientProps: { clientProps: { visibleEntities } },
|
||||||
Component={CustomHeader}
|
Component: CustomHeader,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
serverProps={{
|
serverProps: {
|
||||||
i18n,
|
i18n,
|
||||||
locale,
|
locale,
|
||||||
params,
|
params,
|
||||||
@@ -89,8 +108,8 @@ export const DefaultTemplate: React.FC<DefaultTemplateProps> = ({
|
|||||||
searchParams,
|
searchParams,
|
||||||
user,
|
user,
|
||||||
visibleEntities,
|
visibleEntities,
|
||||||
}}
|
},
|
||||||
/>
|
})}
|
||||||
<div style={{ position: 'relative' }}>
|
<div style={{ position: 'relative' }}>
|
||||||
<div className={`${baseClass}__nav-toggler-wrapper`} id="nav-toggler">
|
<div className={`${baseClass}__nav-toggler-wrapper`} id="nav-toggler">
|
||||||
<div className={`${baseClass}__nav-toggler-container`} id="nav-toggler">
|
<div className={`${baseClass}__nav-toggler-container`} id="nav-toggler">
|
||||||
@@ -100,39 +119,24 @@ export const DefaultTemplate: React.FC<DefaultTemplateProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Wrapper baseClass={baseClass} className={className}>
|
<Wrapper baseClass={baseClass} className={className}>
|
||||||
<RenderServerComponent
|
{NavComponent}
|
||||||
clientProps={{ clientProps: { visibleEntities } }}
|
|
||||||
Component={CustomNav}
|
|
||||||
Fallback={DefaultNav}
|
|
||||||
importMap={payload.importMap}
|
|
||||||
serverProps={{
|
|
||||||
i18n,
|
|
||||||
locale,
|
|
||||||
params,
|
|
||||||
payload,
|
|
||||||
permissions,
|
|
||||||
searchParams,
|
|
||||||
user,
|
|
||||||
visibleEntities,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<div className={`${baseClass}__wrap`}>
|
<div className={`${baseClass}__wrap`}>
|
||||||
<AppHeader
|
<AppHeader
|
||||||
CustomAvatar={
|
CustomAvatar={
|
||||||
avatar !== 'gravatar' && avatar !== 'default' ? (
|
avatar !== 'gravatar' && avatar !== 'default'
|
||||||
<RenderServerComponent
|
? RenderServerComponent({
|
||||||
Component={avatar.Component}
|
Component: avatar.Component,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
/>
|
})
|
||||||
) : undefined
|
: undefined
|
||||||
}
|
}
|
||||||
CustomIcon={
|
CustomIcon={
|
||||||
components?.graphics?.Icon ? (
|
components?.graphics?.Icon
|
||||||
<RenderServerComponent
|
? RenderServerComponent({
|
||||||
Component={components.graphics.Icon}
|
Component: components.graphics.Icon,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
/>
|
})
|
||||||
) : undefined
|
: undefined
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -137,11 +137,11 @@ export const Account: React.FC<AdminViewProps> = async ({
|
|||||||
permissions={permissions}
|
permissions={permissions}
|
||||||
/>
|
/>
|
||||||
<HydrateAuthProvider permissions={permissions} />
|
<HydrateAuthProvider permissions={permissions} />
|
||||||
<RenderServerComponent
|
{RenderServerComponent({
|
||||||
Component={config.admin?.components?.views?.account?.Component}
|
Component: config.admin?.components?.views?.account?.Component,
|
||||||
Fallback={EditView}
|
Fallback: EditView,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
serverProps={{
|
serverProps: {
|
||||||
i18n,
|
i18n,
|
||||||
initPageResult,
|
initPageResult,
|
||||||
locale,
|
locale,
|
||||||
@@ -151,8 +151,8 @@ export const Account: React.FC<AdminViewProps> = async ({
|
|||||||
routeSegments: [],
|
routeSegments: [],
|
||||||
searchParams,
|
searchParams,
|
||||||
user,
|
user,
|
||||||
}}
|
},
|
||||||
/>
|
})}
|
||||||
<AccountClient />
|
<AccountClient />
|
||||||
</EditDepthProvider>
|
</EditDepthProvider>
|
||||||
</DocumentInfoProvider>
|
</DocumentInfoProvider>
|
||||||
|
|||||||
@@ -49,11 +49,11 @@ export const DefaultDashboard: React.FC<DashboardProps> = (props) => {
|
|||||||
return (
|
return (
|
||||||
<div className={baseClass}>
|
<div className={baseClass}>
|
||||||
<Gutter className={`${baseClass}__wrap`}>
|
<Gutter className={`${baseClass}__wrap`}>
|
||||||
{beforeDashboard && (
|
{beforeDashboard &&
|
||||||
<RenderServerComponent
|
RenderServerComponent({
|
||||||
Component={beforeDashboard}
|
Component: beforeDashboard,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
serverProps={{
|
serverProps: {
|
||||||
i18n,
|
i18n,
|
||||||
locale,
|
locale,
|
||||||
params,
|
params,
|
||||||
@@ -61,9 +61,9 @@ export const DefaultDashboard: React.FC<DashboardProps> = (props) => {
|
|||||||
permissions,
|
permissions,
|
||||||
searchParams,
|
searchParams,
|
||||||
user,
|
user,
|
||||||
}}
|
},
|
||||||
/>
|
})}
|
||||||
)}
|
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{!navGroups || navGroups?.length === 0 ? (
|
{!navGroups || navGroups?.length === 0 ? (
|
||||||
<p>no nav groups....</p>
|
<p>no nav groups....</p>
|
||||||
@@ -168,11 +168,11 @@ export const DefaultDashboard: React.FC<DashboardProps> = (props) => {
|
|||||||
})
|
})
|
||||||
)}
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
{afterDashboard && (
|
{afterDashboard &&
|
||||||
<RenderServerComponent
|
RenderServerComponent({
|
||||||
Component={afterDashboard}
|
Component: afterDashboard,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
serverProps={{
|
serverProps: {
|
||||||
i18n,
|
i18n,
|
||||||
locale,
|
locale,
|
||||||
params,
|
params,
|
||||||
@@ -180,9 +180,8 @@ export const DefaultDashboard: React.FC<DashboardProps> = (props) => {
|
|||||||
permissions,
|
permissions,
|
||||||
searchParams,
|
searchParams,
|
||||||
user,
|
user,
|
||||||
}}
|
},
|
||||||
/>
|
})}
|
||||||
)}
|
|
||||||
</Gutter>
|
</Gutter>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -108,15 +108,15 @@ export const Dashboard: React.FC<AdminViewProps> = async ({
|
|||||||
<Fragment>
|
<Fragment>
|
||||||
<HydrateAuthProvider permissions={permissions} />
|
<HydrateAuthProvider permissions={permissions} />
|
||||||
<SetStepNav nav={[]} />
|
<SetStepNav nav={[]} />
|
||||||
<RenderServerComponent
|
{RenderServerComponent({
|
||||||
clientProps={{
|
clientProps: {
|
||||||
Link,
|
Link,
|
||||||
locale,
|
locale,
|
||||||
}}
|
},
|
||||||
Component={config.admin?.components?.views?.dashboard?.Component}
|
Component: config.admin?.components?.views?.dashboard?.Component,
|
||||||
Fallback={DefaultDashboard}
|
Fallback: DefaultDashboard,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
serverProps={{
|
serverProps: {
|
||||||
globalData,
|
globalData,
|
||||||
i18n,
|
i18n,
|
||||||
Link,
|
Link,
|
||||||
@@ -128,8 +128,8 @@ export const Dashboard: React.FC<AdminViewProps> = async ({
|
|||||||
searchParams,
|
searchParams,
|
||||||
user,
|
user,
|
||||||
visibleEntities,
|
visibleEntities,
|
||||||
}}
|
},
|
||||||
/>
|
})}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -345,27 +345,23 @@ export const renderDocument = async ({
|
|||||||
)}
|
)}
|
||||||
<HydrateAuthProvider permissions={permissions} />
|
<HydrateAuthProvider permissions={permissions} />
|
||||||
<EditDepthProvider>
|
<EditDepthProvider>
|
||||||
{ErrorView ? (
|
{ErrorView
|
||||||
<RenderServerComponent
|
? RenderServerComponent({
|
||||||
clientProps={clientProps}
|
clientProps,
|
||||||
Component={ErrorView.ComponentConfig || ErrorView.Component}
|
Component: ErrorView.ComponentConfig || ErrorView.Component,
|
||||||
importMap={importMap}
|
importMap,
|
||||||
serverProps={serverProps}
|
serverProps,
|
||||||
/>
|
})
|
||||||
) : (
|
: RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps,
|
||||||
clientProps={clientProps}
|
Component: RootViewOverride
|
||||||
Component={
|
|
||||||
RootViewOverride
|
|
||||||
? RootViewOverride
|
? RootViewOverride
|
||||||
: CustomView?.ComponentConfig || CustomView?.Component
|
: CustomView?.ComponentConfig || CustomView?.Component
|
||||||
? CustomView?.ComponentConfig || CustomView?.Component
|
? CustomView?.ComponentConfig || CustomView?.Component
|
||||||
: DefaultView?.ComponentConfig || DefaultView?.Component
|
: DefaultView?.ComponentConfig || DefaultView?.Component,
|
||||||
}
|
importMap,
|
||||||
importMap={importMap}
|
serverProps,
|
||||||
serverProps={serverProps}
|
})}
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</EditDepthProvider>
|
</EditDepthProvider>
|
||||||
</DocumentInfoProvider>
|
</DocumentInfoProvider>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -34,9 +34,10 @@ export const renderDocumentSlots: (args: {
|
|||||||
globalConfig?.admin?.components?.elements?.PreviewButton
|
globalConfig?.admin?.components?.elements?.PreviewButton
|
||||||
|
|
||||||
if (isPreviewEnabled && CustomPreviewButton) {
|
if (isPreviewEnabled && CustomPreviewButton) {
|
||||||
components.PreviewButton = (
|
components.PreviewButton = RenderServerComponent({
|
||||||
<RenderServerComponent Component={CustomPreviewButton} importMap={req.payload.importMap} />
|
Component: CustomPreviewButton,
|
||||||
)
|
importMap: req.payload.importMap,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const descriptionFromConfig =
|
const descriptionFromConfig =
|
||||||
@@ -54,14 +55,12 @@ export const renderDocumentSlots: (args: {
|
|||||||
const hasDescription = CustomDescription || staticDescription
|
const hasDescription = CustomDescription || staticDescription
|
||||||
|
|
||||||
if (hasDescription) {
|
if (hasDescription) {
|
||||||
components.Description = (
|
components.Description = RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps: { description: staticDescription },
|
||||||
clientProps={{ description: staticDescription }}
|
Component: CustomDescription,
|
||||||
Component={CustomDescription}
|
Fallback: ViewDescription,
|
||||||
Fallback={ViewDescription}
|
importMap: req.payload.importMap,
|
||||||
importMap={req.payload.importMap}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasSavePermission) {
|
if (hasSavePermission) {
|
||||||
@@ -71,12 +70,10 @@ export const renderDocumentSlots: (args: {
|
|||||||
globalConfig?.admin?.components?.elements?.PublishButton
|
globalConfig?.admin?.components?.elements?.PublishButton
|
||||||
|
|
||||||
if (CustomPublishButton) {
|
if (CustomPublishButton) {
|
||||||
components.PublishButton = (
|
components.PublishButton = RenderServerComponent({
|
||||||
<RenderServerComponent
|
Component: CustomPublishButton,
|
||||||
Component={CustomPublishButton}
|
importMap: req.payload.importMap,
|
||||||
importMap={req.payload.importMap}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
const CustomSaveDraftButton =
|
const CustomSaveDraftButton =
|
||||||
collectionConfig?.admin?.components?.edit?.SaveDraftButton ||
|
collectionConfig?.admin?.components?.edit?.SaveDraftButton ||
|
||||||
@@ -87,12 +84,10 @@ export const renderDocumentSlots: (args: {
|
|||||||
(globalConfig?.versions?.drafts && !globalConfig?.versions?.drafts?.autosave)
|
(globalConfig?.versions?.drafts && !globalConfig?.versions?.drafts?.autosave)
|
||||||
|
|
||||||
if ((draftsEnabled || unsavedDraftWithValidations) && CustomSaveDraftButton) {
|
if ((draftsEnabled || unsavedDraftWithValidations) && CustomSaveDraftButton) {
|
||||||
components.SaveDraftButton = (
|
components.SaveDraftButton = RenderServerComponent({
|
||||||
<RenderServerComponent
|
Component: CustomSaveDraftButton,
|
||||||
Component={CustomSaveDraftButton}
|
importMap: req.payload.importMap,
|
||||||
importMap={req.payload.importMap}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const CustomSaveButton =
|
const CustomSaveButton =
|
||||||
@@ -100,9 +95,10 @@ export const renderDocumentSlots: (args: {
|
|||||||
globalConfig?.admin?.components?.elements?.SaveButton
|
globalConfig?.admin?.components?.elements?.SaveButton
|
||||||
|
|
||||||
if (CustomSaveButton) {
|
if (CustomSaveButton) {
|
||||||
components.SaveButton = (
|
components.SaveButton = RenderServerComponent({
|
||||||
<RenderServerComponent Component={CustomSaveButton} importMap={req.payload.importMap} />
|
Component: CustomSaveButton,
|
||||||
)
|
importMap: req.payload.importMap,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,18 +243,18 @@ export const renderListView = async (
|
|||||||
modifySearchParams={!isInDrawer}
|
modifySearchParams={!isInDrawer}
|
||||||
preferenceKey={preferenceKey}
|
preferenceKey={preferenceKey}
|
||||||
>
|
>
|
||||||
<RenderServerComponent
|
{RenderServerComponent({
|
||||||
clientProps={clientProps}
|
clientProps,
|
||||||
Component={collectionConfig?.admin?.components?.views?.list?.Component}
|
Component: collectionConfig?.admin?.components?.views?.list?.Component,
|
||||||
Fallback={DefaultListView}
|
Fallback: DefaultListView,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
serverProps={{
|
serverProps: {
|
||||||
...sharedServerProps,
|
...sharedServerProps,
|
||||||
data,
|
data,
|
||||||
listPreferences,
|
listPreferences,
|
||||||
listSearchableFields: collectionConfig.admin.listSearchableFields,
|
listSearchableFields: collectionConfig.admin.listSearchableFields,
|
||||||
}}
|
},
|
||||||
/>
|
})}
|
||||||
</ListQueryProvider>
|
</ListQueryProvider>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -24,61 +24,51 @@ export const renderListViewSlots = ({
|
|||||||
const result: ListViewSlots = {} as ListViewSlots
|
const result: ListViewSlots = {} as ListViewSlots
|
||||||
|
|
||||||
if (collectionConfig.admin.components?.afterList) {
|
if (collectionConfig.admin.components?.afterList) {
|
||||||
result.AfterList = (
|
result.AfterList = RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps,
|
||||||
clientProps={clientProps}
|
Component: collectionConfig.admin.components.afterList,
|
||||||
Component={collectionConfig.admin.components.afterList}
|
importMap: payload.importMap,
|
||||||
importMap={payload.importMap}
|
serverProps,
|
||||||
serverProps={serverProps}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collectionConfig.admin.components?.afterListTable) {
|
if (collectionConfig.admin.components?.afterListTable) {
|
||||||
result.AfterListTable = (
|
result.AfterListTable = RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps,
|
||||||
clientProps={clientProps}
|
Component: collectionConfig.admin.components.afterListTable,
|
||||||
Component={collectionConfig.admin.components.afterListTable}
|
importMap: payload.importMap,
|
||||||
importMap={payload.importMap}
|
serverProps,
|
||||||
serverProps={serverProps}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collectionConfig.admin.components?.beforeList) {
|
if (collectionConfig.admin.components?.beforeList) {
|
||||||
result.BeforeList = (
|
result.BeforeList = RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps,
|
||||||
clientProps={clientProps}
|
Component: collectionConfig.admin.components.beforeList,
|
||||||
Component={collectionConfig.admin.components.beforeList}
|
importMap: payload.importMap,
|
||||||
importMap={payload.importMap}
|
serverProps,
|
||||||
serverProps={serverProps}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collectionConfig.admin.components?.beforeListTable) {
|
if (collectionConfig.admin.components?.beforeListTable) {
|
||||||
result.BeforeListTable = (
|
result.BeforeListTable = RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps,
|
||||||
clientProps={clientProps}
|
Component: collectionConfig.admin.components.beforeListTable,
|
||||||
Component={collectionConfig.admin.components.beforeListTable}
|
importMap: payload.importMap,
|
||||||
importMap={payload.importMap}
|
serverProps,
|
||||||
serverProps={serverProps}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collectionConfig.admin.components?.Description) {
|
if (collectionConfig.admin.components?.Description) {
|
||||||
result.Description = (
|
result.Description = RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps: {
|
||||||
clientProps={{
|
description,
|
||||||
description,
|
...clientProps,
|
||||||
...clientProps,
|
},
|
||||||
}}
|
Component: collectionConfig.admin.components.Description,
|
||||||
Component={collectionConfig.admin.components.Description}
|
importMap: payload.importMap,
|
||||||
importMap={payload.importMap}
|
serverProps,
|
||||||
serverProps={serverProps}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -65,10 +65,10 @@ export const LoginView: React.FC<AdminViewProps> = ({ initPageResult, params, se
|
|||||||
user={user}
|
user={user}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<RenderServerComponent
|
{RenderServerComponent({
|
||||||
Component={beforeLogin}
|
Component: beforeLogin,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
serverProps={{
|
serverProps: {
|
||||||
i18n,
|
i18n,
|
||||||
locale,
|
locale,
|
||||||
params,
|
params,
|
||||||
@@ -76,8 +76,9 @@ export const LoginView: React.FC<AdminViewProps> = ({ initPageResult, params, se
|
|||||||
permissions,
|
permissions,
|
||||||
searchParams,
|
searchParams,
|
||||||
user,
|
user,
|
||||||
}}
|
},
|
||||||
/>
|
})}
|
||||||
|
|
||||||
{!collectionConfig?.auth?.disableLocalStrategy && (
|
{!collectionConfig?.auth?.disableLocalStrategy && (
|
||||||
<LoginForm
|
<LoginForm
|
||||||
prefillEmail={prefillEmail}
|
prefillEmail={prefillEmail}
|
||||||
@@ -86,10 +87,10 @@ export const LoginView: React.FC<AdminViewProps> = ({ initPageResult, params, se
|
|||||||
searchParams={searchParams}
|
searchParams={searchParams}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<RenderServerComponent
|
{RenderServerComponent({
|
||||||
Component={afterLogin}
|
Component: afterLogin,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
serverProps={{
|
serverProps: {
|
||||||
i18n,
|
i18n,
|
||||||
locale,
|
locale,
|
||||||
params,
|
params,
|
||||||
@@ -97,8 +98,8 @@ export const LoginView: React.FC<AdminViewProps> = ({ initPageResult, params, se
|
|||||||
permissions,
|
permissions,
|
||||||
searchParams,
|
searchParams,
|
||||||
user,
|
user,
|
||||||
}}
|
},
|
||||||
/>
|
})}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,24 +127,22 @@ export const RootPage = async ({
|
|||||||
importMap,
|
importMap,
|
||||||
})
|
})
|
||||||
|
|
||||||
const RenderedView = (
|
const RenderedView = RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps: { clientConfig },
|
||||||
clientProps={{ clientConfig }}
|
Component: DefaultView.payloadComponent,
|
||||||
Component={DefaultView.payloadComponent}
|
Fallback: DefaultView.Component,
|
||||||
Fallback={DefaultView.Component}
|
importMap,
|
||||||
importMap={importMap}
|
serverProps: {
|
||||||
serverProps={{
|
...serverProps,
|
||||||
...serverProps,
|
clientConfig,
|
||||||
clientConfig,
|
i18n: initPageResult?.req.i18n,
|
||||||
i18n: initPageResult?.req.i18n,
|
importMap,
|
||||||
importMap,
|
initPageResult,
|
||||||
initPageResult,
|
params,
|
||||||
params,
|
payload: initPageResult?.req.payload,
|
||||||
payload: initPageResult?.req.payload,
|
searchParams,
|
||||||
searchParams,
|
},
|
||||||
}}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
|||||||
@@ -175,10 +175,6 @@ export const sanitizeFields = async ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof field.virtual === 'undefined') {
|
|
||||||
field.virtual = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!field.hooks) {
|
if (!field.hooks) {
|
||||||
field.hooks = {}
|
field.hooks = {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { renderField } from '@payloadcms/ui/forms/renderField'
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import type { SanitizedServerEditorConfig } from '../lexical/config/types.js'
|
import type { SanitizedServerEditorConfig } from '../lexical/config/types.js'
|
||||||
import type { LexicalFieldAdminProps } from '../types.js'
|
import type { LexicalFieldAdminProps, LexicalRichTextFieldProps } from '../types.js'
|
||||||
|
|
||||||
// eslint-disable-next-line payload/no-imports-from-exports-dir
|
// eslint-disable-next-line payload/no-imports-from-exports-dir
|
||||||
import { RichTextField } from '../exports/client/index.js'
|
import { RichTextField } from '../exports/client/index.js'
|
||||||
@@ -57,20 +57,26 @@ export const RscEntryLexicalField: React.FC<
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
const props: LexicalRichTextFieldProps = {
|
||||||
<RichTextField
|
admin: args.admin,
|
||||||
admin={args.admin}
|
clientFeatures,
|
||||||
clientFeatures={clientFeatures}
|
featureClientSchemaMap,
|
||||||
featureClientSchemaMap={featureClientSchemaMap}
|
field: args.clientField as RichTextFieldClient,
|
||||||
field={args.clientField as RichTextFieldClient}
|
forceRender: args.forceRender,
|
||||||
forceRender={args.forceRender}
|
initialLexicalFormState,
|
||||||
initialLexicalFormState={initialLexicalFormState}
|
lexicalEditorConfig: args.sanitizedEditorConfig.lexical,
|
||||||
lexicalEditorConfig={args.sanitizedEditorConfig.lexical}
|
path,
|
||||||
path={path}
|
permissions: args.permissions,
|
||||||
permissions={args.permissions}
|
readOnly: args.readOnly,
|
||||||
readOnly={args.readOnly}
|
renderedBlocks: args.renderedBlocks,
|
||||||
renderedBlocks={args.renderedBlocks}
|
schemaPath,
|
||||||
schemaPath={schemaPath}
|
}
|
||||||
/>
|
|
||||||
)
|
for (const key in props) {
|
||||||
|
if (!props[key]) {
|
||||||
|
delete props[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return <RichTextField {...props} />
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import type {
|
|||||||
Field,
|
Field,
|
||||||
FieldPaths,
|
FieldPaths,
|
||||||
RichTextFieldClient,
|
RichTextFieldClient,
|
||||||
ServerComponentProps } from 'payload'
|
ServerComponentProps,
|
||||||
|
} from 'payload'
|
||||||
|
|
||||||
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
|
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
|
||||||
import { createClientFields, deepCopyObjectSimple } from 'payload'
|
import { createClientFields, deepCopyObjectSimple } from 'payload'
|
||||||
@@ -56,31 +57,31 @@ export const RscEntrySlateField: React.FC<
|
|||||||
|
|
||||||
componentMap.set(
|
componentMap.set(
|
||||||
`leaf.button.${leafObject.name}`,
|
`leaf.button.${leafObject.name}`,
|
||||||
<RenderServerComponent
|
RenderServerComponent({
|
||||||
clientProps={clientProps}
|
clientProps,
|
||||||
Component={LeafButton}
|
Component: LeafButton,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
/>,
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
componentMap.set(
|
componentMap.set(
|
||||||
`leaf.component.${leafObject.name}`,
|
`leaf.component.${leafObject.name}`,
|
||||||
<RenderServerComponent
|
RenderServerComponent({
|
||||||
clientProps={clientProps}
|
clientProps,
|
||||||
Component={LeafComponent}
|
Component: LeafComponent,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
/>,
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (Array.isArray(leafObject.plugins)) {
|
if (Array.isArray(leafObject.plugins)) {
|
||||||
leafObject.plugins.forEach((Plugin, i) => {
|
leafObject.plugins.forEach((Plugin, i) => {
|
||||||
componentMap.set(
|
componentMap.set(
|
||||||
`leaf.plugin.${leafObject.name}.${i}`,
|
`leaf.plugin.${leafObject.name}.${i}`,
|
||||||
<RenderServerComponent
|
RenderServerComponent({
|
||||||
clientProps={clientProps}
|
clientProps,
|
||||||
Component={Plugin}
|
Component: Plugin,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
/>,
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -102,31 +103,31 @@ export const RscEntrySlateField: React.FC<
|
|||||||
if (ElementButton) {
|
if (ElementButton) {
|
||||||
componentMap.set(
|
componentMap.set(
|
||||||
`element.button.${element.name}`,
|
`element.button.${element.name}`,
|
||||||
<RenderServerComponent
|
RenderServerComponent({
|
||||||
clientProps={clientProps}
|
clientProps,
|
||||||
Component={ElementButton}
|
Component: ElementButton,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
/>,
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
componentMap.set(
|
componentMap.set(
|
||||||
`element.component.${element.name}`,
|
`element.component.${element.name}`,
|
||||||
<RenderServerComponent
|
RenderServerComponent({
|
||||||
clientProps={clientProps}
|
clientProps,
|
||||||
Component={ElementComponent}
|
Component: ElementComponent,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
/>,
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (Array.isArray(element.plugins)) {
|
if (Array.isArray(element.plugins)) {
|
||||||
element.plugins.forEach((Plugin, i) => {
|
element.plugins.forEach((Plugin, i) => {
|
||||||
componentMap.set(
|
componentMap.set(
|
||||||
`element.plugin.${element.name}.${i}`,
|
`element.plugin.${element.name}.${i}`,
|
||||||
<RenderServerComponent
|
RenderServerComponent({
|
||||||
clientProps={clientProps}
|
clientProps,
|
||||||
Component={Plugin}
|
Component: Plugin,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
/>,
|
}),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,7 @@ import React from 'react'
|
|||||||
|
|
||||||
import { removeUndefined } from '../../utilities/removeUndefined.js'
|
import { removeUndefined } from '../../utilities/removeUndefined.js'
|
||||||
|
|
||||||
/**
|
type RenderServerComponentFn = (args: {
|
||||||
* Can be used to render both MappedComponents and React Components.
|
|
||||||
*/
|
|
||||||
export const RenderServerComponent: React.FC<{
|
|
||||||
readonly clientProps?: object
|
readonly clientProps?: object
|
||||||
readonly Component?:
|
readonly Component?:
|
||||||
| PayloadComponent
|
| PayloadComponent
|
||||||
@@ -17,18 +14,31 @@ export const RenderServerComponent: React.FC<{
|
|||||||
| React.ComponentType[]
|
| React.ComponentType[]
|
||||||
readonly Fallback?: React.ComponentType
|
readonly Fallback?: React.ComponentType
|
||||||
readonly importMap: ImportMap
|
readonly importMap: ImportMap
|
||||||
|
readonly key?: string
|
||||||
readonly serverProps?: object
|
readonly serverProps?: object
|
||||||
}> = ({ clientProps = {}, Component, Fallback, importMap, serverProps }) => {
|
}) => React.ReactNode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can be used to render both MappedComponents and React Components.
|
||||||
|
*/
|
||||||
|
export const RenderServerComponent: RenderServerComponentFn = ({
|
||||||
|
clientProps = {},
|
||||||
|
Component,
|
||||||
|
Fallback,
|
||||||
|
importMap,
|
||||||
|
key,
|
||||||
|
serverProps,
|
||||||
|
}) => {
|
||||||
if (Array.isArray(Component)) {
|
if (Array.isArray(Component)) {
|
||||||
return Component.map((c, index) => (
|
return Component.map((c, index) =>
|
||||||
<RenderServerComponent
|
RenderServerComponent({
|
||||||
clientProps={clientProps}
|
clientProps,
|
||||||
Component={c}
|
Component: c,
|
||||||
importMap={importMap}
|
importMap,
|
||||||
key={index}
|
key: index,
|
||||||
serverProps={serverProps}
|
serverProps,
|
||||||
/>
|
}),
|
||||||
))
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof Component === 'function') {
|
if (typeof Component === 'function') {
|
||||||
@@ -40,7 +50,7 @@ export const RenderServerComponent: React.FC<{
|
|||||||
...(isRSC ? serverProps : {}),
|
...(isRSC ? serverProps : {}),
|
||||||
})
|
})
|
||||||
|
|
||||||
return <Component {...sanitizedProps} />
|
return <Component key={key} {...sanitizedProps} />
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof Component === 'string' || isPlainObject(Component)) {
|
if (typeof Component === 'string' || isPlainObject(Component)) {
|
||||||
@@ -63,16 +73,17 @@ export const RenderServerComponent: React.FC<{
|
|||||||
...(typeof Component === 'object' && Component?.clientProps ? Component.clientProps : {}),
|
...(typeof Component === 'object' && Component?.clientProps ? Component.clientProps : {}),
|
||||||
})
|
})
|
||||||
|
|
||||||
return <ResolvedComponent {...sanitizedProps} />
|
return <ResolvedComponent key={key} {...sanitizedProps} />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Fallback ? (
|
return Fallback
|
||||||
<RenderServerComponent
|
? RenderServerComponent({
|
||||||
clientProps={clientProps}
|
clientProps,
|
||||||
Component={Fallback}
|
Component: Fallback,
|
||||||
importMap={importMap}
|
importMap,
|
||||||
serverProps={serverProps}
|
key,
|
||||||
/>
|
serverProps,
|
||||||
) : null
|
})
|
||||||
|
: null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import type {
|
|||||||
Field,
|
Field,
|
||||||
PaginatedDocs,
|
PaginatedDocs,
|
||||||
Payload,
|
Payload,
|
||||||
PayloadComponent,
|
|
||||||
SanitizedCollectionConfig,
|
SanitizedCollectionConfig,
|
||||||
StaticLabel,
|
StaticLabel,
|
||||||
} from 'payload'
|
} from 'payload'
|
||||||
@@ -151,9 +150,9 @@ export const buildColumnState = (args: Args): Column[] => {
|
|||||||
? _field.admin.components.Label
|
? _field.admin.components.Label
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
const CustomLabel = CustomLabelToRender ? (
|
const CustomLabel = CustomLabelToRender
|
||||||
<RenderServerComponent Component={CustomLabelToRender} importMap={payload.importMap} />
|
? RenderServerComponent({ Component: CustomLabelToRender, importMap: payload.importMap })
|
||||||
) : undefined
|
: undefined
|
||||||
|
|
||||||
const fieldAffectsDataSubFields =
|
const fieldAffectsDataSubFields =
|
||||||
field &&
|
field &&
|
||||||
@@ -220,41 +219,25 @@ export const buildColumnState = (args: Args): Column[] => {
|
|||||||
_field.admin.components = {}
|
_field.admin.components = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
CustomCell = RenderServerComponent({
|
||||||
* We have to deep copy all the props we send to the client (= CellComponent.clientProps).
|
clientProps: cellClientProps,
|
||||||
* That way, every editor's field / cell props we send to the client have their own object references.
|
Component: _field.editor.CellComponent,
|
||||||
*
|
importMap: payload.importMap,
|
||||||
* If we send the same object reference to the client twice (e.g. through some configurations where 2 or more fields
|
serverProps,
|
||||||
* reference the same editor object, like the root editor), the admin panel may hang indefinitely. This has been happening since
|
})
|
||||||
* a newer Next.js update that made it break when sending the same object reference to the client twice.
|
|
||||||
*
|
|
||||||
* We can use deepCopyObjectSimple as client props should be JSON-serializable.
|
|
||||||
*/
|
|
||||||
const CellComponent: PayloadComponent = _field.editor.CellComponent
|
|
||||||
if (typeof CellComponent === 'object' && CellComponent.clientProps) {
|
|
||||||
CellComponent.clientProps = deepCopyObjectSimple(CellComponent.clientProps)
|
|
||||||
}
|
|
||||||
|
|
||||||
CustomCell = (
|
|
||||||
<RenderServerComponent
|
|
||||||
clientProps={cellClientProps}
|
|
||||||
Component={CellComponent}
|
|
||||||
importMap={payload.importMap}
|
|
||||||
serverProps={serverProps}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
CustomCell =
|
CustomCell =
|
||||||
_field?.admin && 'components' in _field.admin && _field.admin.components?.Cell ? (
|
_field?.admin && 'components' in _field.admin && _field.admin.components?.Cell
|
||||||
<RenderServerComponent
|
? RenderServerComponent({
|
||||||
clientProps={cellClientProps}
|
clientProps: cellClientProps,
|
||||||
Component={
|
Component:
|
||||||
_field?.admin && 'components' in _field.admin && _field.admin.components?.Cell
|
_field?.admin &&
|
||||||
}
|
'components' in _field.admin &&
|
||||||
importMap={payload.importMap}
|
_field.admin.components?.Cell,
|
||||||
serverProps={serverProps}
|
importMap: payload.importMap,
|
||||||
/>
|
serverProps,
|
||||||
) : undefined
|
})
|
||||||
|
: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export const WithServerSideProps: WithServerSidePropsComponent = ({
|
|||||||
return <Component {...propsWithServerOnlyProps} />
|
return <Component {...propsWithServerOnlyProps} />
|
||||||
}
|
}
|
||||||
|
|
||||||
return <WithServerSideProps {...rest} />
|
return WithServerSideProps(rest)
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import type {
|
|||||||
ClientComponentProps,
|
ClientComponentProps,
|
||||||
ClientField,
|
ClientField,
|
||||||
FieldPaths,
|
FieldPaths,
|
||||||
PayloadComponent,
|
|
||||||
SanitizedFieldPermissions,
|
SanitizedFieldPermissions,
|
||||||
ServerComponentProps,
|
ServerComponentProps,
|
||||||
} from 'payload'
|
} from 'payload'
|
||||||
@@ -109,20 +108,18 @@ export const renderField: RenderFieldMethod = ({
|
|||||||
fieldState.customComponents.RowLabels = []
|
fieldState.customComponents.RowLabels = []
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldState.customComponents.RowLabels[rowIndex] = (
|
fieldState.customComponents.RowLabels[rowIndex] = RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps,
|
||||||
clientProps={clientProps}
|
Component: fieldConfig.admin.components.RowLabel,
|
||||||
Component={fieldConfig.admin.components.RowLabel}
|
importMap: req.payload.importMap,
|
||||||
importMap={req.payload.importMap}
|
serverProps: {
|
||||||
serverProps={{
|
...serverProps,
|
||||||
...serverProps,
|
rowLabel: `${getTranslation(fieldConfig.labels.singular, req.i18n)} ${String(
|
||||||
rowLabel: `${getTranslation(fieldConfig.labels.singular, req.i18n)} ${String(
|
rowIndex + 1,
|
||||||
rowIndex + 1,
|
).padStart(2, '0')}`,
|
||||||
).padStart(2, '0')}`,
|
rowNumber: rowIndex + 1,
|
||||||
rowNumber: rowIndex + 1,
|
},
|
||||||
}}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -146,30 +143,12 @@ export const renderField: RenderFieldMethod = ({
|
|||||||
fieldConfig.admin.components = {}
|
fieldConfig.admin.components = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
fieldState.customComponents.Field = RenderServerComponent({
|
||||||
* We have to deep copy all the props we send to the client (= FieldComponent.clientProps).
|
clientProps,
|
||||||
* That way, every editor's field / cell props we send to the client have their own object references.
|
Component: fieldConfig.editor.FieldComponent,
|
||||||
*
|
importMap: req.payload.importMap,
|
||||||
* If we send the same object reference to the client twice (e.g. through some configurations where 2 or more fields
|
serverProps,
|
||||||
* reference the same editor object, like the root editor), the admin panel may hang indefinitely. This has been happening since
|
})
|
||||||
* a newer Next.js update that made it break when sending the same object reference to the client twice.
|
|
||||||
*
|
|
||||||
* We can use deepCopyObjectSimple as client props should be JSON-serializable.
|
|
||||||
*/
|
|
||||||
const FieldComponent: PayloadComponent = fieldConfig.editor.FieldComponent
|
|
||||||
if (typeof FieldComponent === 'object' && FieldComponent.clientProps) {
|
|
||||||
FieldComponent.clientProps = deepCopyObjectSimple(FieldComponent.clientProps)
|
|
||||||
}
|
|
||||||
|
|
||||||
fieldState.customComponents.Field = (
|
|
||||||
<RenderServerComponent
|
|
||||||
clientProps={clientProps}
|
|
||||||
Component={FieldComponent}
|
|
||||||
Fallback={undefined}
|
|
||||||
importMap={req.payload.importMap}
|
|
||||||
serverProps={serverProps}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -182,15 +161,13 @@ export const renderField: RenderFieldMethod = ({
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const Component = fieldConfig.admin.components[key]
|
const Component = fieldConfig.admin.components[key]
|
||||||
fieldState.customComponents[key] = (
|
fieldState.customComponents[key] = RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps,
|
||||||
clientProps={clientProps}
|
Component,
|
||||||
Component={Component}
|
importMap: req.payload.importMap,
|
||||||
importMap={req.payload.importMap}
|
key: `field.admin.components.${key}`,
|
||||||
key={`field.admin.components.${key}`}
|
serverProps,
|
||||||
serverProps={serverProps}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
@@ -217,75 +194,63 @@ export const renderField: RenderFieldMethod = ({
|
|||||||
|
|
||||||
if (fieldConfig.admin?.components) {
|
if (fieldConfig.admin?.components) {
|
||||||
if ('afterInput' in fieldConfig.admin.components) {
|
if ('afterInput' in fieldConfig.admin.components) {
|
||||||
fieldState.customComponents.AfterInput = (
|
fieldState.customComponents.AfterInput = RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps,
|
||||||
clientProps={clientProps}
|
Component: fieldConfig.admin.components.afterInput,
|
||||||
Component={fieldConfig.admin.components.afterInput}
|
importMap: req.payload.importMap,
|
||||||
importMap={req.payload.importMap}
|
key: 'field.admin.components.afterInput',
|
||||||
key="field.admin.components.afterInput"
|
serverProps,
|
||||||
serverProps={serverProps}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('beforeInput' in fieldConfig.admin.components) {
|
if ('beforeInput' in fieldConfig.admin.components) {
|
||||||
fieldState.customComponents.BeforeInput = (
|
fieldState.customComponents.BeforeInput = RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps,
|
||||||
clientProps={clientProps}
|
Component: fieldConfig.admin.components.beforeInput,
|
||||||
Component={fieldConfig.admin.components.beforeInput}
|
importMap: req.payload.importMap,
|
||||||
importMap={req.payload.importMap}
|
key: 'field.admin.components.beforeInput',
|
||||||
key="field.admin.components.beforeInput"
|
serverProps,
|
||||||
serverProps={serverProps}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('Description' in fieldConfig.admin.components) {
|
if ('Description' in fieldConfig.admin.components) {
|
||||||
fieldState.customComponents.Description = (
|
fieldState.customComponents.Description = RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps,
|
||||||
clientProps={clientProps}
|
Component: fieldConfig.admin.components.Description,
|
||||||
Component={fieldConfig.admin.components.Description}
|
importMap: req.payload.importMap,
|
||||||
importMap={req.payload.importMap}
|
key: 'field.admin.components.Description',
|
||||||
key="field.admin.components.Description"
|
serverProps,
|
||||||
serverProps={serverProps}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('Error' in fieldConfig.admin.components) {
|
if ('Error' in fieldConfig.admin.components) {
|
||||||
fieldState.customComponents.Error = (
|
fieldState.customComponents.Error = RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps,
|
||||||
clientProps={clientProps}
|
Component: fieldConfig.admin.components.Error,
|
||||||
Component={fieldConfig.admin.components.Error}
|
importMap: req.payload.importMap,
|
||||||
importMap={req.payload.importMap}
|
key: 'field.admin.components.Error',
|
||||||
key="field.admin.components.Error"
|
serverProps,
|
||||||
serverProps={serverProps}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('Label' in fieldConfig.admin.components) {
|
if ('Label' in fieldConfig.admin.components) {
|
||||||
fieldState.customComponents.Label = (
|
fieldState.customComponents.Label = RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps,
|
||||||
clientProps={clientProps}
|
Component: fieldConfig.admin.components.Label,
|
||||||
Component={fieldConfig.admin.components.Label}
|
importMap: req.payload.importMap,
|
||||||
importMap={req.payload.importMap}
|
key: 'field.admin.components.Label',
|
||||||
key="field.admin.components.Label"
|
serverProps,
|
||||||
serverProps={serverProps}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('Field' in fieldConfig.admin.components) {
|
if ('Field' in fieldConfig.admin.components) {
|
||||||
fieldState.customComponents.Field = (
|
fieldState.customComponents.Field = RenderServerComponent({
|
||||||
<RenderServerComponent
|
clientProps,
|
||||||
clientProps={clientProps}
|
Component: fieldConfig.admin.components.Field,
|
||||||
Component={fieldConfig.admin.components.Field}
|
importMap: req.payload.importMap,
|
||||||
importMap={req.payload.importMap}
|
key: 'field.admin.components.Field',
|
||||||
key="field.admin.components.Field"
|
serverProps,
|
||||||
serverProps={serverProps}
|
})
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,10 +29,10 @@ export const renderFilters = (
|
|||||||
if ('name' in field && field.admin?.components?.Filter) {
|
if ('name' in field && field.admin?.components?.Filter) {
|
||||||
acc.set(
|
acc.set(
|
||||||
field.name,
|
field.name,
|
||||||
<RenderServerComponent
|
RenderServerComponent({
|
||||||
Component={field.admin.components?.Filter}
|
Component: field.admin.components?.Filter,
|
||||||
importMap={importMap}
|
importMap,
|
||||||
/>,
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ export const AfterDashboardClient: PayloadServerReactComponent<CustomComponent>
|
|||||||
return (
|
return (
|
||||||
<Banner>
|
<Banner>
|
||||||
<p>Admin Dependency test component:</p>
|
<p>Admin Dependency test component:</p>
|
||||||
<RenderServerComponent
|
{RenderServerComponent({
|
||||||
Component={payload.config.admin.dependencies?.myTestComponent}
|
Component: payload.config.admin.dependencies?.myTestComponent,
|
||||||
importMap={payload.importMap}
|
importMap: payload.importMap,
|
||||||
/>
|
})}
|
||||||
</Banner>
|
</Banner>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user