Skip to content

Commit

Permalink
fix(ui): fixed issue with updatedAt timestamps not updating in the UI…
Browse files Browse the repository at this point in the history
… when drafts are updated (#10503)

Fixes #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.
  • Loading branch information
paulpopus authored Jan 13, 2025
1 parent 0252681 commit 082c4f0
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 7 deletions.
5 changes: 5 additions & 0 deletions packages/payload/src/versions/saveVersion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
13 changes: 11 additions & 2 deletions packages/ui/src/elements/Autosave/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 (
Expand Down Expand Up @@ -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(() => {
Expand Down
18 changes: 13 additions & 5 deletions packages/ui/src/views/Edit/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -240,21 +242,27 @@ 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(),
})
}

if (!isEditing && depth < 2) {
// 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 {
Expand All @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions test/versions/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
53 changes: 53 additions & 0 deletions test/versions/e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
55 changes: 55 additions & 0 deletions test/versions/int.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down

0 comments on commit 082c4f0

Please sign in to comment.