fix(next): threads server props to custom providers (#9412)
When defining custom providers as server components, they currently do not receive any of the server props that custom components expect to receive, like `payload`, `i18n`, `user`, and so on.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import type { Config, ImportMap } from 'payload'
|
||||
import type { Config, ImportMap, ServerProps } from 'payload'
|
||||
|
||||
import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
|
||||
import '@payloadcms/ui/scss/app.scss'
|
||||
@@ -8,14 +8,24 @@ type Args = {
|
||||
readonly children: React.ReactNode
|
||||
readonly importMap: ImportMap
|
||||
readonly providers: Config['admin']['components']['providers']
|
||||
readonly serverProps: ServerProps
|
||||
}
|
||||
|
||||
export function NestProviders({ children, importMap, providers }: Args): React.ReactNode {
|
||||
export function NestProviders({
|
||||
children,
|
||||
importMap,
|
||||
providers,
|
||||
serverProps,
|
||||
}: Args): React.ReactNode {
|
||||
return RenderServerComponent({
|
||||
clientProps: {
|
||||
children:
|
||||
providers.length > 1 ? (
|
||||
<NestProviders importMap={importMap} providers={providers.slice(1)}>
|
||||
<NestProviders
|
||||
importMap={importMap}
|
||||
providers={providers.slice(1)}
|
||||
serverProps={serverProps}
|
||||
>
|
||||
{children}
|
||||
</NestProviders>
|
||||
) : (
|
||||
@@ -24,5 +34,6 @@ export function NestProviders({ children, importMap, providers }: Args): React.R
|
||||
},
|
||||
Component: providers[0],
|
||||
importMap,
|
||||
serverProps,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ export const RootLayout = async ({
|
||||
|
||||
const payload = await getPayload({ config, importMap })
|
||||
|
||||
const { i18n, permissions, user } = await initReq(config)
|
||||
const { i18n, permissions, req, user } = await initReq(config)
|
||||
|
||||
const dir = (rtlLanguages as unknown as AcceptedLanguages[]).includes(languageCode)
|
||||
? 'RTL'
|
||||
@@ -117,6 +117,12 @@ export const RootLayout = async ({
|
||||
<NestProviders
|
||||
importMap={payload.importMap}
|
||||
providers={config.admin?.components?.providers}
|
||||
serverProps={{
|
||||
i18n,
|
||||
payload,
|
||||
permissions,
|
||||
user,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</NestProviders>
|
||||
|
||||
@@ -17,9 +17,14 @@ export const CustomProvider: React.FC<{ children: React.ReactNode }> = ({ childr
|
||||
setCustom,
|
||||
}
|
||||
|
||||
console.log('custom provider called')
|
||||
|
||||
return <Context.Provider value={value}>{children}</Context.Provider>
|
||||
return (
|
||||
<Context.Provider value={value}>
|
||||
<div className="custom-provider" style={{ display: 'none' }}>
|
||||
This is a custom provider.
|
||||
</div>
|
||||
{children}
|
||||
</Context.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export const useCustom = () => useContext(Context)
|
||||
|
||||
17
test/admin/components/CustomProviderServer/index.tsx
Normal file
17
test/admin/components/CustomProviderServer/index.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { ServerProps } from 'payload'
|
||||
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
export const CustomProviderServer: React.FC<{ children: React.ReactNode } & ServerProps> = ({
|
||||
children,
|
||||
payload,
|
||||
}) => {
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="custom-provider-server" style={{ display: 'none' }}>
|
||||
{`This is a custom provider with payload: ${Boolean(payload)}`}
|
||||
</div>
|
||||
{children}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -61,7 +61,7 @@ export default buildConfigWithDefaults({
|
||||
Button: '/components/Logout/index.js#Logout',
|
||||
},
|
||||
providers: [
|
||||
'/components/CustomProvider/index.js#CustomProvider',
|
||||
'/components/CustomProviderServer/index.js#CustomProviderServer',
|
||||
'/components/CustomProvider/index.js#CustomProvider',
|
||||
],
|
||||
views: {
|
||||
|
||||
@@ -460,6 +460,22 @@ describe('admin1', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('custom providers', () => {
|
||||
test('should render custom providers', async () => {
|
||||
await page.goto(`${serverURL}/admin`)
|
||||
await expect(page.locator('.custom-provider')).toHaveCount(1)
|
||||
await expect(page.locator('.custom-provider')).toContainText('This is a custom provider.')
|
||||
})
|
||||
|
||||
test('should render custom provider server components with props', async () => {
|
||||
await page.goto(`${serverURL}/admin`)
|
||||
await expect(page.locator('.custom-provider-server')).toHaveCount(1)
|
||||
await expect(page.locator('.custom-provider-server')).toContainText(
|
||||
'This is a custom provider with payload: true',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('custom views', () => {
|
||||
test('root — should render custom view', async () => {
|
||||
await page.goto(`${serverURL}${adminRoutes.routes.admin}${customViewPath}`)
|
||||
|
||||
Reference in New Issue
Block a user