fix(next): prevent errors in globals version view (#12920)
### What? This PR fixes a runtime error that occurs when opening the "More versions..." drawer while browsing the versions for a global. It also fixes a minor runtime error when navigating to a global version view where an optional chaining operator was missing as the collection variable would be undefined as we are viewing a global. This PR also adds an e2e test to ensure the versions drawer is accessible and renders the appropriate number of versions for globals. ### Why? To properly render global version views without errors. ### How? By threading the global slug to the versions drawer and adjusting some properties of the `renderDocument` server function call there. This PR also adds an optional chaining operator the `versionUseAsTitle` in the original view to prevent an error in globals. Notes: - This was brought to my attention in Discord by a handful of users Before: (Missing optional chaining error) [error1-verions-Editing---Menu---Payload.webm](https://github.com/user-attachments/assets/3dc4dbe4-ee5a-43df-8d25-05128b05e063) Before: (Versions drawer error) [error2-versions-Editing---Menu---Payload.webm](https://github.com/user-attachments/assets/98c3e1da-cb0b-4a36-bafd-240f641e8814) After: [versions-globals-Dashboard---Payload.webm](https://github.com/user-attachments/assets/c778d3f0-a8fe-4e31-92cb-62da8e6d8cb4)
This commit is contained in:
@@ -238,6 +238,7 @@ export const DefaultVersionView: React.FC<DefaultVersionsViewProps> = ({
|
||||
<SelectComparison
|
||||
collectionSlug={collectionSlug}
|
||||
docID={originalDocID}
|
||||
globalSlug={globalSlug}
|
||||
onChange={onChangeVersionFrom}
|
||||
versionFromID={versionFromID}
|
||||
versionFromOptions={versionFromOptions}
|
||||
|
||||
@@ -24,11 +24,12 @@ export const formatVersionDrawerSlug = ({
|
||||
}) => `version-drawer_${depth}_${uuid}`
|
||||
|
||||
export const VersionDrawerContent: React.FC<{
|
||||
collectionSlug: string
|
||||
docID: number | string
|
||||
collectionSlug?: string
|
||||
docID?: number | string
|
||||
drawerSlug: string
|
||||
globalSlug?: string
|
||||
}> = (props) => {
|
||||
const { collectionSlug, docID, drawerSlug } = props
|
||||
const { collectionSlug, docID, drawerSlug, globalSlug } = props
|
||||
const { closeModal } = useModal()
|
||||
const searchParams = useSearchParams()
|
||||
const prevSearchParams = useRef(searchParams)
|
||||
@@ -46,12 +47,20 @@ export const VersionDrawerContent: React.FC<{
|
||||
setIsLoading(true)
|
||||
|
||||
try {
|
||||
const isGlobal = Boolean(globalSlug)
|
||||
const entitySlug = collectionSlug ?? globalSlug
|
||||
|
||||
const result = await renderDocument({
|
||||
collectionSlug,
|
||||
collectionSlug: entitySlug,
|
||||
docID,
|
||||
drawerSlug,
|
||||
paramsOverride: {
|
||||
segments: ['collections', collectionSlug, String(docID), 'versions'],
|
||||
segments: [
|
||||
isGlobal ? 'globals' : 'collections',
|
||||
entitySlug,
|
||||
isGlobal ? undefined : String(docID),
|
||||
'versions',
|
||||
].filter(Boolean),
|
||||
},
|
||||
redirectAfterDelete: false,
|
||||
redirectAfterDuplicate: false,
|
||||
@@ -75,7 +84,7 @@ export const VersionDrawerContent: React.FC<{
|
||||
|
||||
void fetchDocumentView()
|
||||
},
|
||||
[closeModal, collectionSlug, drawerSlug, renderDocument, searchParams, t],
|
||||
[closeModal, collectionSlug, globalSlug, drawerSlug, renderDocument, searchParams, t],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
@@ -93,11 +102,12 @@ export const VersionDrawerContent: React.FC<{
|
||||
return DocumentView
|
||||
}
|
||||
export const VersionDrawer: React.FC<{
|
||||
collectionSlug: string
|
||||
docID: number | string
|
||||
collectionSlug?: string
|
||||
docID?: number | string
|
||||
drawerSlug: string
|
||||
globalSlug?: string
|
||||
}> = (props) => {
|
||||
const { collectionSlug, docID, drawerSlug } = props
|
||||
const { collectionSlug, docID, drawerSlug, globalSlug } = props
|
||||
const { t } = useTranslation()
|
||||
|
||||
return (
|
||||
@@ -107,7 +117,12 @@ export const VersionDrawer: React.FC<{
|
||||
slug={drawerSlug}
|
||||
title={t('version:selectVersionToCompare')}
|
||||
>
|
||||
<VersionDrawerContent collectionSlug={collectionSlug} docID={docID} drawerSlug={drawerSlug} />
|
||||
<VersionDrawerContent
|
||||
collectionSlug={collectionSlug}
|
||||
docID={docID}
|
||||
drawerSlug={drawerSlug}
|
||||
globalSlug={globalSlug}
|
||||
/>
|
||||
</Drawer>
|
||||
)
|
||||
}
|
||||
@@ -115,9 +130,11 @@ export const VersionDrawer: React.FC<{
|
||||
export const useVersionDrawer = ({
|
||||
collectionSlug,
|
||||
docID,
|
||||
globalSlug,
|
||||
}: {
|
||||
collectionSlug: string
|
||||
docID: number | string
|
||||
collectionSlug?: string
|
||||
docID?: number | string
|
||||
globalSlug?: string
|
||||
}) => {
|
||||
const drawerDepth = useEditDepth()
|
||||
const uuid = useId()
|
||||
@@ -147,9 +164,14 @@ export const useVersionDrawer = ({
|
||||
|
||||
const MemoizedDrawer = useMemo(() => {
|
||||
return () => (
|
||||
<VersionDrawer collectionSlug={collectionSlug} docID={docID} drawerSlug={drawerSlug} />
|
||||
<VersionDrawer
|
||||
collectionSlug={collectionSlug}
|
||||
docID={docID}
|
||||
drawerSlug={drawerSlug}
|
||||
globalSlug={globalSlug}
|
||||
/>
|
||||
)
|
||||
}, [collectionSlug, docID, drawerSlug])
|
||||
}, [collectionSlug, docID, drawerSlug, globalSlug])
|
||||
|
||||
return useMemo(
|
||||
() => ({
|
||||
|
||||
@@ -17,13 +17,14 @@ export const SelectComparison: React.FC<Props> = memo((props) => {
|
||||
const {
|
||||
collectionSlug,
|
||||
docID,
|
||||
globalSlug,
|
||||
onChange: onChangeFromProps,
|
||||
versionFromID,
|
||||
versionFromOptions,
|
||||
} = props
|
||||
const { t } = useTranslation()
|
||||
|
||||
const { Drawer, openDrawer } = useVersionDrawer({ collectionSlug, docID })
|
||||
const { Drawer, openDrawer } = useVersionDrawer({ collectionSlug, docID, globalSlug })
|
||||
|
||||
const options = useMemo(() => {
|
||||
return [
|
||||
|
||||
@@ -3,8 +3,9 @@ import type { PaginatedDocs, SanitizedCollectionConfig } from 'payload'
|
||||
import type { CompareOption } from '../Default/types.js'
|
||||
|
||||
export type Props = {
|
||||
collectionSlug: string
|
||||
docID: number | string
|
||||
collectionSlug?: string
|
||||
docID?: number | string
|
||||
globalSlug?: string
|
||||
onChange: (val: CompareOption) => void
|
||||
versionFromID?: string
|
||||
versionFromOptions: CompareOption[]
|
||||
|
||||
@@ -425,7 +425,7 @@ export async function VersionView(props: DocumentViewServerProps) {
|
||||
VersionToCreatedAtLabel={formatPill({ doc: versionTo, labelStyle: 'pill' })}
|
||||
versionToID={versionTo.id}
|
||||
versionToStatus={versionTo.version?._status}
|
||||
versionToUseAsTitle={versionTo[collectionConfig.admin?.useAsTitle || 'id']}
|
||||
versionToUseAsTitle={versionTo[collectionConfig?.admin?.useAsTitle || 'id']}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -205,6 +205,7 @@ describe('Versions', () => {
|
||||
const fieldValue = autosaveRelationField.locator('.value-container')
|
||||
await expect(fieldValue).toContainText('test')
|
||||
})
|
||||
|
||||
test('should show collection versions view level action in collection versions view', async () => {
|
||||
await page.goto(url.list)
|
||||
await page.locator('tbody tr .cell-title a').first().click()
|
||||
@@ -839,6 +840,51 @@ describe('Versions', () => {
|
||||
await page.goto(url.global(disablePublishGlobalSlug))
|
||||
await expect(page.locator('#action-save')).not.toBeAttached()
|
||||
})
|
||||
|
||||
test('global — should show versions drawer when SelectComparison more option is clicked', async () => {
|
||||
await payload.updateGlobal({
|
||||
slug: draftGlobalSlug,
|
||||
data: {
|
||||
title: 'initial title',
|
||||
},
|
||||
})
|
||||
await payload.updateGlobal({
|
||||
slug: draftGlobalSlug,
|
||||
data: {
|
||||
title: 'initial title 2',
|
||||
},
|
||||
})
|
||||
|
||||
const url = new AdminUrlUtil(serverURL, draftGlobalSlug)
|
||||
await page.goto(`${url.global(draftGlobalSlug)}/versions`)
|
||||
|
||||
const versionsTable = page.locator('.table table')
|
||||
await expect(versionsTable).toBeVisible()
|
||||
|
||||
const versionAnchor = versionsTable.locator('tbody tr.row-1 td.cell-updatedAt a')
|
||||
await expect(versionAnchor).toBeVisible()
|
||||
await versionAnchor.click()
|
||||
|
||||
const compareFromContainer = page.locator(
|
||||
'.view-version__version-from .field-type.compare-version',
|
||||
)
|
||||
await expect(compareFromContainer).toBeVisible()
|
||||
|
||||
const fromSelect = compareFromContainer.locator('.react-select .rs__control')
|
||||
await expect(fromSelect).toBeVisible()
|
||||
await fromSelect.click()
|
||||
|
||||
const moreVersions = compareFromContainer.locator('.rs__option:has-text("More versions...")')
|
||||
await expect(moreVersions).toBeVisible()
|
||||
await moreVersions.click()
|
||||
|
||||
const versionDrawer = page.locator('dialog.version-drawer')
|
||||
await expect(versionDrawer).toBeVisible()
|
||||
|
||||
const versionsDrawerTableBody = versionDrawer.locator('main.versions table tbody')
|
||||
await expect(versionsDrawerTableBody).toBeVisible()
|
||||
await expect(versionsDrawerTableBody.locator('tr')).toHaveCount(2)
|
||||
})
|
||||
})
|
||||
|
||||
describe('Scheduled publish', () => {
|
||||
|
||||
Reference in New Issue
Block a user