Skip to content

Commit 9607453

Browse files
authored
fix: server edit view components don't receive document id prop (#13526)
### What? Make the document `id` available to server-rendered admin components that expect it—specifically `EditMenuItems` and `BeforeDocumentControls`—so `props.id` matches the official docs. ### Why? The docs show examples using `props.id`, but the runtime `serverProps` and TS types didn’t include it. This led to `undefined` at render time. ### How? - Add id to ServerProps and set it in renderDocumentSlots from req.routeParams.id. Fixes #13420
1 parent 5cf215d commit 9607453

File tree

6 files changed

+70
-9
lines changed

6 files changed

+70
-9
lines changed

docs/custom-components/edit-view.mdx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -293,20 +293,19 @@ Here's an example of a custom `editMenuItems` component:
293293

294294
```tsx
295295
import React from 'react'
296-
import { PopupList } from '@payloadcms/ui'
297296

298297
import type { EditMenuItemsServerProps } from 'payload'
299298

300299
export const EditMenuItems = async (props: EditMenuItemsServerProps) => {
301300
const href = `/custom-action?id=${props.id}`
302301

303302
return (
304-
<PopupList.ButtonGroup>
305-
<PopupList.Button href={href}>Custom Edit Menu Item</PopupList.Button>
306-
<PopupList.Button href={href}>
303+
<>
304+
<a href={href}>Custom Edit Menu Item</a>
305+
<a href={href}>
307306
Another Custom Edit Menu Item - add as many as you need!
308-
</PopupList.Button>
309-
</PopupList.ButtonGroup>
307+
</a>
308+
</>
310309
)
311310
}
312311
```

packages/next/src/views/Document/renderDocumentSlots.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type {
22
BeforeDocumentControlsServerPropsOnly,
3-
DefaultServerFunctionArgs,
43
DocumentSlots,
54
EditMenuItemsServerPropsOnly,
65
PayloadRequest,
@@ -39,6 +38,7 @@ export const renderDocumentSlots: (args: {
3938
const isPreviewEnabled = collectionConfig?.admin?.preview || globalConfig?.admin?.preview
4039

4140
const serverProps: ServerProps = {
41+
id: req.routeParams.id as number | string,
4242
i18n: req.i18n,
4343
payload: req.payload,
4444
user: req.user,

packages/payload/src/config/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ export type Params = { [key: string]: string | string[] | undefined }
402402
export type ServerProps = {
403403
readonly documentSubViewType?: DocumentSubViewTypes
404404
readonly i18n: I18nClient
405+
readonly id?: number | string
405406
readonly locale?: Locale
406407
readonly params?: Params
407408
readonly payload: Payload

test/admin/collections/editMenuItems.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { CollectionConfig } from 'payload'
22

3-
import { editMenuItemsSlug, postsCollectionSlug, uploadCollectionSlug } from '../slugs.js'
3+
import { editMenuItemsSlug } from '../slugs.js'
44

55
export const EditMenuItems: CollectionConfig = {
66
slug: editMenuItemsSlug,
@@ -11,6 +11,9 @@ export const EditMenuItems: CollectionConfig = {
1111
{
1212
path: '/components/EditMenuItems/index.js#EditMenuItems',
1313
},
14+
{
15+
path: '/components/EditMenuItemsServer/index.js#EditMenuItemsServer',
16+
},
1417
],
1518
},
1619
},
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { EditMenuItemsServerProps } from 'payload'
2+
3+
import React from 'react'
4+
5+
export const EditMenuItemsServer = (props: EditMenuItemsServerProps) => {
6+
const href = `/custom-action?id=${props.id}`
7+
8+
return (
9+
<div>
10+
<a href={href}>Custom Edit Menu Item (Server)</a>
11+
</div>
12+
)
13+
}

test/admin/e2e/document-view/e2e.spec.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -731,7 +731,7 @@ describe('Document View', () => {
731731
})
732732

733733
describe('custom editMenuItem components', () => {
734-
test('should render custom editMenuItems component', async () => {
734+
test('should render custom editMenuItems client component', async () => {
735735
await page.goto(editMenuItemsURL.create)
736736
await page.locator('#field-title')?.fill(title)
737737
await saveDocAndAssert(page)
@@ -746,6 +746,51 @@ describe('Document View', () => {
746746

747747
await expect(customEditMenuItem).toBeVisible()
748748
})
749+
750+
test('should render custom editMenuItems server component', async () => {
751+
await page.goto(editMenuItemsURL.create)
752+
await page.locator('#field-title')?.fill(title)
753+
await saveDocAndAssert(page)
754+
755+
const threeDotMenu = page.getByRole('main').locator('.doc-controls__popup')
756+
await expect(threeDotMenu).toBeVisible()
757+
await threeDotMenu.click()
758+
759+
const popup = page.locator('.popup--active .popup__content')
760+
await expect(popup).toBeVisible()
761+
762+
const customEditMenuItem = popup.getByRole('link', {
763+
name: 'Custom Edit Menu Item (Server)',
764+
})
765+
766+
await expect(customEditMenuItem).toBeVisible()
767+
})
768+
769+
test('should render doc id in href of custom editMenuItems server component link', async () => {
770+
await page.goto(editMenuItemsURL.create)
771+
await page.locator('#field-title')?.fill(title)
772+
await saveDocAndAssert(page)
773+
774+
const threeDotMenu = page.getByRole('main').locator('.doc-controls__popup')
775+
await expect(threeDotMenu).toBeVisible()
776+
await threeDotMenu.click()
777+
778+
const popup = page.locator('.popup--active .popup__content')
779+
await expect(popup).toBeVisible()
780+
781+
const customEditMenuItem = popup.getByRole('link', {
782+
name: 'Custom Edit Menu Item (Server)',
783+
})
784+
785+
await expect(customEditMenuItem).toBeVisible()
786+
787+
// Extract the document id from the edit page URL (last path segment)
788+
const editPath = new URL(page.url()).pathname
789+
const docId = editPath.split('/').filter(Boolean).pop()!
790+
791+
// Assert the href contains the same id
792+
await expect(customEditMenuItem).toHaveAttribute('href', `/custom-action?id=${docId}`)
793+
})
749794
})
750795
})
751796

0 commit comments

Comments
 (0)