fix(ui): don't populate on auto save (#13649)

Edited by @jacobsfletch

Autosave is run with default depth, causing form state and the document
info context to be inconsistent across the load/autosave/save lifecycle.

For example, when loading the app, the document is queried with `depth:
0` and relationships are _not_ populated. Same with save/draft/publish.
Autosave, on the other hand, populates these relationships, causing the
data to temporarily change in shape in between these events.

Here's an example:


https://github.com/user-attachments/assets/153ea112-7591-4f54-9216-575322f4edbe

Now, autosave runs with `depth: 0` as expected, consistent with the
other events of the document lifecycle.

**Plus this is a huge performance improvement.**

Fixes #13643 and #13192.

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1211224908421570

---------

Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
This commit is contained in:
Aapo Laakkio
2025-09-03 23:59:36 +03:00
committed by GitHub
parent 1a1696d9ae
commit 7794541af3
5 changed files with 67 additions and 3 deletions

View File

@@ -1,6 +1,6 @@
import type { CollectionConfig } from 'payload'
import { autosaveCollectionSlug } from '../slugs.js'
import { autosaveCollectionSlug, postCollectionSlug } from '../slugs.js'
const AutosavePosts: CollectionConfig = {
slug: autosaveCollectionSlug,
@@ -53,6 +53,16 @@ const AutosavePosts: CollectionConfig = {
unique: true,
localized: true,
},
{
name: 'relationship',
type: 'relationship',
relationTo: postCollectionSlug,
admin: {
components: {
Label: './elements/CustomFieldLabel/index.tsx#CustomFieldLabel',
},
},
},
{
name: 'computedTitle',
label: 'Computed Title',

View File

@@ -423,6 +423,48 @@ describe('Versions', () => {
await expect(drawer.locator('.id-label')).toBeVisible()
})
test('collection - should autosave using proper depth', async () => {
const { id: postID } = await payload.create({
collection: postCollectionSlug,
data: {
title: 'post title',
description: 'post description',
},
})
const { id: docID } = await payload.create({
collection: autosaveCollectionSlug,
data: {
title: 'autosave title',
description: 'autosave description',
relationship: postID,
},
})
await page.goto(autosaveURL.edit(docID))
await expect(page.locator('#custom-field-label')).toHaveText(
`Value in DocumentInfoContext: ${postID}`,
)
await assertNetworkRequests(
page,
// Important: assert that depth is 0 in this request
`${serverURL}/api/autosave-posts/${docID}?depth=0&draft=true&autosave=true&locale=en`,
async () => {
await page.locator('#field-title').fill('changed title')
},
{
allowedNumberOfRequests: 1,
},
)
// Ensure that the value in context remains consistent across saves
await expect(page.locator('#custom-field-label')).toHaveText(
`Value in DocumentInfoContext: ${postID}`,
)
})
test('collection - should show "save as draft" button when showSaveDraftButton is true', async () => {
await page.goto(autosaveWithDraftButtonURL.create)
await expect(page.locator('#action-save-draft')).toBeVisible()

View File

@@ -0,0 +1,10 @@
'use client'
import { useDocumentInfo } from '@payloadcms/ui'
export const CustomFieldLabel = () => {
const { data } = useDocumentInfo()
return (
<p id="custom-field-label">{`Value in DocumentInfoContext: ${data?.relationship || '<No value>'}`}</p>
)
}

View File

@@ -199,6 +199,7 @@ export interface Post {
export interface AutosavePost {
id: string;
title: string;
relationship?: (string | null) | Post;
computedTitle?: string | null;
richText?: {
root: {
@@ -835,6 +836,7 @@ export interface PostsSelect<T extends boolean = true> {
*/
export interface AutosavePostsSelect<T extends boolean = true> {
title?: T;
relationship?: T;
computedTitle?: T;
richText?: T;
json?: T;