fix(ui): fixed issue with updatedAt timestamps not updating in the UI when drafts are updated (#10503)
Fixes https://github.com/payloadcms/payload/issues/10436 Fixes an issue where drafts' updatedAt timestamp is not being updated. We weren't updating the `versionData` to have the right timestamp in the saveVersion operation when drafts were being updated. Added e2e tests to make sure 'Last Modified' is always different in both autosave and non-autosave drafts.
This commit is contained in:
@@ -42,6 +42,11 @@ export const saveVersion = async ({
|
||||
if (draft) {
|
||||
versionData._status = 'draft'
|
||||
}
|
||||
|
||||
if (collection?.timestamps && draft) {
|
||||
versionData.updatedAt = now
|
||||
}
|
||||
|
||||
if (versionData._id) {
|
||||
delete versionData._id
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ export const Autosave: React.FC<Props> = ({ id, collection, global: globalDoc })
|
||||
setLastUpdateTime,
|
||||
setMostRecentVersionIsAutosaved,
|
||||
setUnpublishedVersionCount,
|
||||
updateSavedDocumentData,
|
||||
} = useDocumentInfo()
|
||||
const queueRef = useRef([])
|
||||
const isProcessingRef = useRef(false)
|
||||
@@ -180,9 +181,9 @@ export const Autosave: React.FC<Props> = ({ id, collection, global: globalDoc })
|
||||
setMostRecentVersionIsAutosaved(true)
|
||||
setUnpublishedVersionCount((prev) => prev + 1)
|
||||
}
|
||||
} else {
|
||||
return res.json()
|
||||
}
|
||||
|
||||
return res.json()
|
||||
})
|
||||
.then((json) => {
|
||||
if (
|
||||
@@ -231,6 +232,14 @@ export const Autosave: React.FC<Props> = ({ id, collection, global: globalDoc })
|
||||
setSaving(false)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// If it's not an error then we can update the document data inside the context
|
||||
const document = json?.doc || json?.result
|
||||
|
||||
// Manually update the data since this function doesn't fire the `submit` function from useForm
|
||||
if (document) {
|
||||
updateSavedDocumentData(document)
|
||||
}
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
|
||||
@@ -225,10 +225,12 @@ export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({
|
||||
async (json): Promise<FormState> => {
|
||||
const controller = handleAbortRef(abortOnSaveRef)
|
||||
|
||||
const document = json?.doc || json?.result
|
||||
|
||||
reportUpdate({
|
||||
id,
|
||||
entitySlug,
|
||||
updatedAt: json?.result?.updatedAt || new Date().toISOString(),
|
||||
updatedAt: document?.updatedAt || new Date().toISOString(),
|
||||
})
|
||||
|
||||
// If we're editing the doc of the logged-in user,
|
||||
@@ -240,13 +242,19 @@ export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({
|
||||
incrementVersionCount()
|
||||
|
||||
if (typeof updateSavedDocumentData === 'function') {
|
||||
void updateSavedDocumentData(json?.doc || {})
|
||||
void updateSavedDocumentData(document || {})
|
||||
}
|
||||
|
||||
if (typeof onSaveFromContext === 'function') {
|
||||
const operation = id ? 'update' : 'create'
|
||||
|
||||
void onSaveFromContext({
|
||||
...json,
|
||||
operation: id ? 'update' : 'create',
|
||||
operation,
|
||||
updatedAt:
|
||||
operation === 'update'
|
||||
? new Date().toISOString()
|
||||
: document?.updatedAt || new Date().toISOString(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -254,7 +262,7 @@ export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({
|
||||
// Redirect to the same locale if it's been set
|
||||
const redirectRoute = formatAdminURL({
|
||||
adminRoute,
|
||||
path: `/collections/${collectionSlug}/${json?.doc?.id}${locale ? `?locale=${locale}` : ''}`,
|
||||
path: `/collections/${collectionSlug}/${document?.id}${locale ? `?locale=${locale}` : ''}`,
|
||||
})
|
||||
router.push(redirectRoute)
|
||||
} else {
|
||||
@@ -269,7 +277,7 @@ export const DefaultEditView: React.FC<ClientSideEditViewProps> = ({
|
||||
const { state } = await getFormState({
|
||||
id,
|
||||
collectionSlug,
|
||||
data: json?.doc || json?.result,
|
||||
data: document,
|
||||
docPermissions,
|
||||
docPreferences,
|
||||
globalSlug,
|
||||
|
||||
@@ -23,6 +23,8 @@ export default buildConfigWithDefaults({
|
||||
importMap: {
|
||||
baseDir: path.resolve(dirname),
|
||||
},
|
||||
// The autosave test uses this format in order to compare timestamps in the UI
|
||||
dateFormat: 'MMMM do yyyy, h:mm:ss a',
|
||||
},
|
||||
collections: [
|
||||
DisablePublish,
|
||||
|
||||
@@ -426,6 +426,59 @@ describe('Versions', () => {
|
||||
await expect(drawer.locator('.id-label')).toBeVisible()
|
||||
})
|
||||
|
||||
test('collection - should update updatedAt', async () => {
|
||||
await page.goto(url.create)
|
||||
await page.waitForURL(`**/${url.create}`)
|
||||
|
||||
// fill out doc in english
|
||||
await page.locator('#field-title').fill('title')
|
||||
await page.locator('#field-description').fill('initial description')
|
||||
await saveDocAndAssert(page)
|
||||
|
||||
const updatedAtWrapper = await page.locator(
|
||||
'.doc-controls .doc-controls__content .doc-controls__list-item',
|
||||
{
|
||||
hasText: 'Last Modified',
|
||||
},
|
||||
)
|
||||
const initialUpdatedAt = await updatedAtWrapper.locator('.doc-controls__value').textContent()
|
||||
|
||||
// wait for 1 second so that the timestamp can be different
|
||||
await wait(1000)
|
||||
|
||||
await page.locator('#field-description').fill('changed description')
|
||||
await saveDocAndAssert(page)
|
||||
|
||||
const newUpdatedAt = await updatedAtWrapper.locator('.doc-controls__value').textContent()
|
||||
|
||||
expect(newUpdatedAt).not.toEqual(initialUpdatedAt)
|
||||
})
|
||||
|
||||
test('collection - should update updatedAt on autosave', async () => {
|
||||
await page.goto(autosaveURL.create)
|
||||
await page.locator('#field-title').fill('autosave title')
|
||||
await waitForAutoSaveToRunAndComplete(page)
|
||||
await expect(page.locator('#field-title')).toHaveValue('autosave title')
|
||||
|
||||
const updatedAtWrapper = await page.locator(
|
||||
'.doc-controls .doc-controls__content .doc-controls__list-item',
|
||||
{
|
||||
hasText: 'Last Modified',
|
||||
},
|
||||
)
|
||||
const initialUpdatedAt = await updatedAtWrapper.locator('.doc-controls__value').textContent()
|
||||
|
||||
// wait for 1 second so that the timestamp can be different
|
||||
await wait(1000)
|
||||
|
||||
await page.locator('#field-title').fill('autosave title updated')
|
||||
await waitForAutoSaveToRunAndComplete(page)
|
||||
|
||||
const newUpdatedAt = await updatedAtWrapper.locator('.doc-controls__value').textContent()
|
||||
|
||||
expect(newUpdatedAt).not.toEqual(initialUpdatedAt)
|
||||
})
|
||||
|
||||
test('global - should autosave', async () => {
|
||||
const url = new AdminUrlUtil(serverURL, autoSaveGlobalSlug)
|
||||
await page.goto(url.global(autoSaveGlobalSlug))
|
||||
|
||||
@@ -593,6 +593,61 @@ describe('Versions', () => {
|
||||
expect(draftPost.title.es).toBe(spanishTitle)
|
||||
})
|
||||
|
||||
it('should have correct updatedAt timestamps when saving drafts', async () => {
|
||||
const created = await payload.create({
|
||||
collection: draftCollectionSlug,
|
||||
data: {
|
||||
description: 'desc',
|
||||
title: 'title',
|
||||
},
|
||||
draft: true,
|
||||
})
|
||||
|
||||
await wait(10)
|
||||
|
||||
const updated = await payload.update({
|
||||
id: created.id,
|
||||
collection: draftCollectionSlug,
|
||||
data: {
|
||||
title: 'updated title',
|
||||
},
|
||||
draft: true,
|
||||
})
|
||||
|
||||
const createdUpdatedAt = new Date(created.updatedAt)
|
||||
const updatedUpdatedAt = new Date(updated.updatedAt)
|
||||
|
||||
expect(Number(updatedUpdatedAt)).toBeGreaterThan(Number(createdUpdatedAt))
|
||||
})
|
||||
|
||||
it('should have correct updatedAt timestamps when saving drafts with autosave', async () => {
|
||||
const created = await payload.create({
|
||||
collection: draftCollectionSlug,
|
||||
data: {
|
||||
description: 'desc',
|
||||
title: 'title',
|
||||
},
|
||||
draft: true,
|
||||
})
|
||||
|
||||
await wait(10)
|
||||
|
||||
const updated = await payload.update({
|
||||
id: created.id,
|
||||
collection: draftCollectionSlug,
|
||||
data: {
|
||||
title: 'updated title',
|
||||
},
|
||||
draft: true,
|
||||
autosave: true,
|
||||
})
|
||||
|
||||
const createdUpdatedAt = new Date(created.updatedAt)
|
||||
const updatedUpdatedAt = new Date(updated.updatedAt)
|
||||
|
||||
expect(Number(updatedUpdatedAt)).toBeGreaterThan(Number(createdUpdatedAt))
|
||||
})
|
||||
|
||||
it('should validate when publishing with the draft arg', async () => {
|
||||
// no title (not valid for publishing)
|
||||
const doc = await payload.create({
|
||||
|
||||
Reference in New Issue
Block a user