Skip to content

Commit b6b02ac

Browse files
tak-ambossAlessioGrDanRibbens
authored
fix(ui): fix version list status for unpublished documents (#11983)
### What? Fixes the label for documents which were the current published document but got unpublished in the version view. ### Why? If the most recent published document was unpublished, it remained displayed as "Currently published version" in the version list. ### How? Checks whether the document has a currently published version instead of only looking at the latest published version when determining the label in the versions view. Fixes #10838 --------- Co-authored-by: Alessio Gravili <alessio@gravili.de> Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
1 parent 5365d4f commit b6b02ac

File tree

3 files changed

+151
-8
lines changed

3 files changed

+151
-8
lines changed

packages/next/src/views/Version/SelectComparison/index.tsx

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@
22

33
import type { PaginatedDocs, Where } from 'payload'
44

5-
import { fieldBaseClass, Pill, ReactSelect, useConfig, useTranslation } from '@payloadcms/ui'
5+
import {
6+
fieldBaseClass,
7+
Pill,
8+
ReactSelect,
9+
useConfig,
10+
useDocumentInfo,
11+
useTranslation,
12+
} from '@payloadcms/ui'
613
import { formatDate } from '@payloadcms/ui/shared'
714
import { stringify } from 'qs-esm'
815
import React, { useCallback, useEffect, useState } from 'react'
@@ -37,6 +44,8 @@ export const SelectComparison: React.FC<Props> = (props) => {
3744
},
3845
} = useConfig()
3946

47+
const { hasPublishedDoc } = useDocumentInfo()
48+
4049
const [options, setOptions] = useState<
4150
{
4251
label: React.ReactNode | string
@@ -109,7 +118,10 @@ export const SelectComparison: React.FC<Props> = (props) => {
109118
},
110119
published: {
111120
currentLabel: t('version:currentPublishedVersion'),
112-
latestVersion: latestPublishedVersion,
121+
// The latest published version does not necessarily equal the current published version,
122+
// because the latest published version might have been unpublished in the meantime.
123+
// Hence, we should only use the latest published version if there is a published document.
124+
latestVersion: hasPublishedDoc ? latestPublishedVersion : undefined,
113125
pillStyle: 'success',
114126
previousLabel: t('version:previouslyPublished'),
115127
},

packages/next/src/views/Versions/index.tsx

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,34 @@ export async function VersionsView(props: DocumentViewServerProps) {
8585
payload,
8686
status: 'draft',
8787
})
88-
latestPublishedVersion = await getLatestVersion({
89-
slug: collectionSlug,
90-
type: 'collection',
91-
parentID: id,
92-
payload,
93-
status: 'published',
88+
const publishedDoc = await payload.count({
89+
collection: collectionSlug,
90+
depth: 0,
91+
overrideAccess: true,
92+
req,
93+
where: {
94+
id: {
95+
equals: id,
96+
},
97+
_status: {
98+
equals: 'published',
99+
},
100+
},
94101
})
102+
103+
// If we pass a latestPublishedVersion to buildVersionColumns,
104+
// this will be used to display it as the "current published version".
105+
// However, the latest published version might have been unpublished in the meantime.
106+
// Hence, we should only pass the latest published version if there is a published document.
107+
latestPublishedVersion =
108+
publishedDoc.totalDocs > 0 &&
109+
(await getLatestVersion({
110+
slug: collectionSlug,
111+
type: 'collection',
112+
parentID: id,
113+
payload,
114+
status: 'published',
115+
}))
95116
}
96117
} catch (err) {
97118
logError({ err, payload })

test/versions/e2e.spec.ts

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,116 @@ describe('Versions', () => {
205205
await expect(page.locator('#field-title')).toHaveValue('v1')
206206
})
207207

208+
test('should show currently published version status in versions view', async () => {
209+
const publishedDoc = await payload.create({
210+
collection: draftCollectionSlug,
211+
data: {
212+
_status: 'published',
213+
title: 'title',
214+
description: 'description',
215+
},
216+
overrideAccess: true,
217+
})
218+
219+
await page.goto(`${url.edit(publishedDoc.id)}/versions`)
220+
await expect(page.locator('main.versions')).toContainText('Current Published Version')
221+
})
222+
223+
test('should show unpublished version status in versions view', async () => {
224+
const publishedDoc = await payload.create({
225+
collection: draftCollectionSlug,
226+
data: {
227+
_status: 'published',
228+
title: 'title',
229+
description: 'description',
230+
},
231+
overrideAccess: true,
232+
})
233+
234+
// Unpublish the document
235+
await payload.update({
236+
collection: draftCollectionSlug,
237+
id: publishedDoc.id,
238+
data: {
239+
_status: 'draft',
240+
},
241+
draft: false,
242+
})
243+
244+
await page.goto(`${url.edit(publishedDoc.id)}/versions`)
245+
await expect(page.locator('main.versions')).toContainText('Previously Published')
246+
})
247+
248+
test('should show global versions view level action in globals versions view', async () => {
249+
const global = new AdminUrlUtil(serverURL, draftGlobalSlug)
250+
await page.goto(`${global.global(draftGlobalSlug)}/versions`)
251+
await expect(page.locator('.app-header .global-versions-button')).toHaveCount(1)
252+
})
253+
254+
test('global — has versions tab', async () => {
255+
const global = new AdminUrlUtil(serverURL, draftGlobalSlug)
256+
await page.goto(global.global(draftGlobalSlug))
257+
258+
const docURL = page.url()
259+
const pathname = new URL(docURL).pathname
260+
261+
const versionsTab = page.locator('.doc-tab', {
262+
hasText: 'Versions',
263+
})
264+
await versionsTab.waitFor({ state: 'visible' })
265+
266+
expect(versionsTab).toBeTruthy()
267+
const href = versionsTab.locator('a').first()
268+
await expect(href).toHaveAttribute('href', `${pathname}/versions`)
269+
})
270+
271+
test('global — respects max number of versions', async () => {
272+
await payload.updateGlobal({
273+
slug: draftWithMaxGlobalSlug,
274+
data: {
275+
title: 'initial title',
276+
},
277+
})
278+
279+
const global = new AdminUrlUtil(serverURL, draftWithMaxGlobalSlug)
280+
await page.goto(global.global(draftWithMaxGlobalSlug))
281+
282+
const titleFieldInitial = page.locator('#field-title')
283+
await titleFieldInitial.fill('updated title')
284+
await saveDocAndAssert(page, '#action-save-draft')
285+
await expect(titleFieldInitial).toHaveValue('updated title')
286+
287+
const versionsTab = page.locator('.doc-tab', {
288+
hasText: '1',
289+
})
290+
291+
await versionsTab.waitFor({ state: 'visible' })
292+
293+
expect(versionsTab).toBeTruthy()
294+
295+
const titleFieldUpdated = page.locator('#field-title')
296+
await titleFieldUpdated.fill('latest title')
297+
await saveDocAndAssert(page, '#action-save-draft')
298+
await expect(titleFieldUpdated).toHaveValue('latest title')
299+
300+
const versionsTabUpdated = page.locator('.doc-tab', {
301+
hasText: '1',
302+
})
303+
304+
await versionsTabUpdated.waitFor({ state: 'visible' })
305+
306+
expect(versionsTabUpdated).toBeTruthy()
307+
})
308+
309+
test('global — has versions route', async () => {
310+
const global = new AdminUrlUtil(serverURL, autoSaveGlobalSlug)
311+
const versionsURL = `${global.global(autoSaveGlobalSlug)}/versions`
312+
await page.goto(versionsURL)
313+
await expect(() => {
314+
expect(page.url()).toMatch(/\/versions/)
315+
}).toPass({ timeout: 10000, intervals: [100] })
316+
})
317+
208318
test('collection - should autosave', async () => {
209319
await page.goto(autosaveURL.create)
210320
await page.locator('#field-title').fill('autosave title')

0 commit comments

Comments
 (0)