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 { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerComponent'
|
||||||
import '@payloadcms/ui/scss/app.scss'
|
import '@payloadcms/ui/scss/app.scss'
|
||||||
@@ -8,14 +8,24 @@ type Args = {
|
|||||||
readonly children: React.ReactNode
|
readonly children: React.ReactNode
|
||||||
readonly importMap: ImportMap
|
readonly importMap: ImportMap
|
||||||
readonly providers: Config['admin']['components']['providers']
|
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({
|
return 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)}
|
||||||
|
serverProps={serverProps}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</NestProviders>
|
</NestProviders>
|
||||||
) : (
|
) : (
|
||||||
@@ -24,5 +34,6 @@ export function NestProviders({ children, importMap, providers }: Args): React.R
|
|||||||
},
|
},
|
||||||
Component: providers[0],
|
Component: providers[0],
|
||||||
importMap,
|
importMap,
|
||||||
|
serverProps,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export const RootLayout = async ({
|
|||||||
|
|
||||||
const payload = await getPayload({ config, importMap })
|
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)
|
const dir = (rtlLanguages as unknown as AcceptedLanguages[]).includes(languageCode)
|
||||||
? 'RTL'
|
? 'RTL'
|
||||||
@@ -117,6 +117,12 @@ export const RootLayout = async ({
|
|||||||
<NestProviders
|
<NestProviders
|
||||||
importMap={payload.importMap}
|
importMap={payload.importMap}
|
||||||
providers={config.admin?.components?.providers}
|
providers={config.admin?.components?.providers}
|
||||||
|
serverProps={{
|
||||||
|
i18n,
|
||||||
|
payload,
|
||||||
|
permissions,
|
||||||
|
user,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</NestProviders>
|
</NestProviders>
|
||||||
|
|||||||
@@ -17,9 +17,14 @@ export const CustomProvider: React.FC<{ children: React.ReactNode }> = ({ childr
|
|||||||
setCustom,
|
setCustom,
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('custom provider called')
|
return (
|
||||||
|
<Context.Provider value={value}>
|
||||||
return <Context.Provider value={value}>{children}</Context.Provider>
|
<div className="custom-provider" style={{ display: 'none' }}>
|
||||||
|
This is a custom provider.
|
||||||
|
</div>
|
||||||
|
{children}
|
||||||
|
</Context.Provider>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useCustom = () => useContext(Context)
|
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',
|
Button: '/components/Logout/index.js#Logout',
|
||||||
},
|
},
|
||||||
providers: [
|
providers: [
|
||||||
'/components/CustomProvider/index.js#CustomProvider',
|
'/components/CustomProviderServer/index.js#CustomProviderServer',
|
||||||
'/components/CustomProvider/index.js#CustomProvider',
|
'/components/CustomProvider/index.js#CustomProvider',
|
||||||
],
|
],
|
||||||
views: {
|
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', () => {
|
describe('custom views', () => {
|
||||||
test('root — should render custom view', async () => {
|
test('root — should render custom view', async () => {
|
||||||
await page.goto(`${serverURL}${adminRoutes.routes.admin}${customViewPath}`)
|
await page.goto(`${serverURL}${adminRoutes.routes.admin}${customViewPath}`)
|
||||||
|
|||||||
Reference in New Issue
Block a user