fix(ui): autosave hooks are not reflected in form state (#13416)

Fixes #10515. Needed for #12956.

Hooks run within autosave are not reflected in form state.

Similar to #10268, but for autosave events.

For example, if you are using a computed value, like this:

```ts
[
  // ...
  {
    name: 'title',
    type: 'text',
  },
  {
    name: 'computedTitle',
    type: 'text',
    hooks: {
      beforeChange: [({ data }) => data?.title],
    },
  },
]
```

In the example above, when an autosave event is triggered after changing
the `title` field, we expect the `computedTitle` field to match. But
although this takes place on the database level, the UI does not reflect
this change unless you refresh the page or navigate back and forth.

Here's an example:

Before:


https://github.com/user-attachments/assets/c8c68a78-9957-45a8-a710-84d954d15bcc

After:


https://github.com/user-attachments/assets/16cb87a5-83ca-4891-b01f-f5c4b0a34362

---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210561273449855
This commit is contained in:
Jacob Fletcher
2025-08-11 16:59:03 -04:00
committed by GitHub
parent 9c8f3202e4
commit 1d81b0c6dd
14 changed files with 214 additions and 201 deletions

View File

@@ -5,7 +5,6 @@ import type { ClientCollectionConfig, ClientGlobalConfig } from 'payload'
import { dequal } from 'dequal/lite'
import { reduceFieldsToValues, versionDefaults } from 'payload/shared'
import React, { useDeferredValue, useEffect, useRef, useState } from 'react'
import { toast } from 'sonner'
import {
useAllFormFields,
@@ -17,13 +16,11 @@ import { useDebounce } from '../../hooks/useDebounce.js'
import { useEffectEvent } from '../../hooks/useEffectEvent.js'
import { useQueues } from '../../hooks/useQueues.js'
import { useConfig } from '../../providers/Config/index.js'
import { useDocumentEvents } from '../../providers/DocumentEvents/index.js'
import { useDocumentInfo } from '../../providers/DocumentInfo/index.js'
import { useLocale } from '../../providers/Locale/index.js'
import { useTranslation } from '../../providers/Translation/index.js'
import { formatTimeToNow } from '../../utilities/formatDocTitle/formatDateTitle.js'
import { reduceFieldsToValuesWithValidation } from '../../utilities/reduceFieldsToValuesWithValidation.js'
import { useDocumentDrawerContext } from '../DocumentDrawer/Provider.js'
import { LeaveWithoutSaving } from '../LeaveWithoutSaving/index.js'
import './index.scss'
@@ -51,16 +48,11 @@ export const Autosave: React.FC<Props> = ({ id, collection, global: globalDoc })
incrementVersionCount,
lastUpdateTime,
mostRecentVersionIsAutosaved,
setLastUpdateTime,
setMostRecentVersionIsAutosaved,
setUnpublishedVersionCount,
updateSavedDocumentData,
} = useDocumentInfo()
const { onSave: onSaveFromDocumentDrawer } = useDocumentDrawerContext()
const { reportUpdate } = useDocumentEvents()
const { dispatchFields, isValid, setBackgroundProcessing, setIsValid } = useForm()
const { isValid, setBackgroundProcessing, submit } = useForm()
const [formState] = useAllFormFields()
const modified = useFormModified()
@@ -151,118 +143,38 @@ export const Autosave: React.FC<Props> = ({ id, collection, global: globalDoc })
method = 'POST'
}
if (url) {
if (modifiedRef.current) {
const { data, valid } = reduceFieldsToValuesWithValidation(formStateRef.current, true)
const { valid } = reduceFieldsToValuesWithValidation(formStateRef.current, true)
data._status = 'draft'
const skipSubmission =
submitted && !valid && versionsConfig?.drafts && versionsConfig?.drafts?.validate
const skipSubmission =
submitted && !valid && versionsConfig?.drafts && versionsConfig?.drafts?.validate
if (!skipSubmission && modifiedRef.current && url) {
const result = await submit({
action: url,
context: {
incrementVersionCount: false,
},
disableFormWhileProcessing: false,
disableSuccessStatus: true,
method,
overrides: {
_status: 'draft',
},
skipValidation: versionsConfig?.drafts && !versionsConfig?.drafts?.validate,
})
if (!skipSubmission) {
let res
try {
res = await fetch(url, {
body: JSON.stringify(data),
credentials: 'include',
headers: {
'Accept-Language': i18n.language,
'Content-Type': 'application/json',
},
method,
})
} catch (_err) {
// Swallow Error
}
const newDate = new Date()
// We need to log the time in order to figure out if we need to trigger the state off later
endTimestamp = newDate.getTime()
const json = await res.json()
if (res.status === 200) {
setLastUpdateTime(newDate.getTime())
reportUpdate({
id,
entitySlug,
updatedAt: newDate.toISOString(),
})
// if onSaveFromDocumentDrawer is defined, call it
if (typeof onSaveFromDocumentDrawer === 'function') {
void onSaveFromDocumentDrawer({
...json,
operation: 'update',
})
}
if (!mostRecentVersionIsAutosaved) {
incrementVersionCount()
setMostRecentVersionIsAutosaved(true)
setUnpublishedVersionCount((prev) => prev + 1)
}
}
if (versionsConfig?.drafts && versionsConfig?.drafts?.validate && json?.errors) {
if (Array.isArray(json.errors)) {
const [fieldErrors, nonFieldErrors] = json.errors.reduce(
([fieldErrs, nonFieldErrs], err) => {
const newFieldErrs = []
const newNonFieldErrs = []
if (err?.message) {
newNonFieldErrs.push(err)
}
if (Array.isArray(err?.data)) {
err.data.forEach((dataError) => {
if (dataError?.field) {
newFieldErrs.push(dataError)
} else {
newNonFieldErrs.push(dataError)
}
})
}
return [
[...fieldErrs, ...newFieldErrs],
[...nonFieldErrs, ...newNonFieldErrs],
]
},
[[], []],
)
dispatchFields({
type: 'ADD_SERVER_ERRORS',
errors: fieldErrors,
})
nonFieldErrors.forEach((err) => {
toast.error(err.message || i18n.t('error:unknown'))
})
setIsValid(false)
hideIndicator()
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) {
setIsValid(true)
updateSavedDocumentData(document)
}
}
hideIndicator()
}
if (result && result?.res?.ok && !mostRecentVersionIsAutosaved) {
incrementVersionCount()
setMostRecentVersionIsAutosaved(true)
setUnpublishedVersionCount((prev) => prev + 1)
}
const newDate = new Date()
// We need to log the time in order to figure out if we need to trigger the state off later
endTimestamp = newDate.getTime()
hideIndicator()
}
}
},

View File

@@ -20,6 +20,11 @@ export type DocumentDrawerContextProps = {
}) => Promise<void> | void
readonly onSave?: (args: {
collectionConfig?: ClientCollectionConfig
/**
* @experimental - Note: this property is experimental and may change in the future. Use as your own discretion.
* If you want to pass additional data to the onSuccess callback, you can use this context object.
*/
context?: Record<string, unknown>
doc: TypeWithID
operation: 'create' | 'update'
result: Data

View File

@@ -161,7 +161,7 @@ export const Upload_v4: React.FC<UploadProps_v4> = (props) => {
const { t } = useTranslation()
const { setModified } = useForm()
const { id, docPermissions, savedDocumentData, setUploadStatus } = useDocumentInfo()
const { id, data, docPermissions, setUploadStatus } = useDocumentInfo()
const isFormSubmitting = useFormProcessing()
const { errorMessage, setValue, showError, value } = useField<File>({
path: 'file',
@@ -349,7 +349,7 @@ export const Upload_v4: React.FC<UploadProps_v4> = (props) => {
const acceptMimeTypes = uploadConfig.mimeTypes?.join(', ')
const imageCacheTag = uploadConfig?.cacheTags && savedDocumentData?.updatedAt
const imageCacheTag = uploadConfig?.cacheTags && data?.updatedAt
useEffect(() => {
const handleControlFileUrl = async () => {
@@ -375,11 +375,11 @@ export const Upload_v4: React.FC<UploadProps_v4> = (props) => {
return (
<div className={[fieldBaseClass, baseClass].filter(Boolean).join(' ')}>
<FieldError message={errorMessage} showError={showError} />
{savedDocumentData && savedDocumentData.filename && !removedFile && (
{data && data.filename && !removedFile && (
<FileDetails
collectionSlug={collectionSlug}
customUploadActions={customActions}
doc={savedDocumentData}
doc={data}
enableAdjustments={showCrop || showFocalPoint}
handleRemove={canRemoveUpload ? handleFileRemoval : undefined}
hasImageSizes={hasImageSizes}
@@ -388,7 +388,7 @@ export const Upload_v4: React.FC<UploadProps_v4> = (props) => {
uploadConfig={uploadConfig}
/>
)}
{((!uploadConfig.hideFileInputOnCreate && !savedDocumentData?.filename) || removedFile) && (
{((!uploadConfig.hideFileInputOnCreate && !data?.filename) || removedFile) && (
<div className={`${baseClass}__upload`}>
{!value && !showUrlInput && (
<Dropzone onChange={handleFileSelection}>
@@ -506,7 +506,7 @@ export const Upload_v4: React.FC<UploadProps_v4> = (props) => {
<UploadActions
customActions={customActions}
enableAdjustments={showCrop || showFocalPoint}
enablePreviewSizes={hasImageSizes && savedDocumentData?.filename && !removedFile}
enablePreviewSizes={hasImageSizes && data?.filename && !removedFile}
mimeType={value.type}
/>
</div>
@@ -523,17 +523,17 @@ export const Upload_v4: React.FC<UploadProps_v4> = (props) => {
)}
</div>
)}
{(value || savedDocumentData?.filename) && (
{(value || data?.filename) && (
<EditDepthProvider>
<Drawer Header={null} slug={editDrawerSlug}>
<EditUpload
fileName={value?.name || savedDocumentData?.filename}
fileSrc={savedDocumentData?.url || fileSrc}
fileName={value?.name || data?.filename}
fileSrc={data?.url || fileSrc}
imageCacheTag={imageCacheTag}
initialCrop={uploadEdits?.crop ?? undefined}
initialFocalPoint={{
x: uploadEdits?.focalPoint?.x || savedDocumentData?.focalX || 50,
y: uploadEdits?.focalPoint?.y || savedDocumentData?.focalY || 50,
x: uploadEdits?.focalPoint?.x || data?.focalX || 50,
y: uploadEdits?.focalPoint?.y || data?.focalY || 50,
}}
onSave={onEditsSave}
showCrop={showCrop}
@@ -542,18 +542,14 @@ export const Upload_v4: React.FC<UploadProps_v4> = (props) => {
</Drawer>
</EditDepthProvider>
)}
{savedDocumentData && hasImageSizes && (
{data && hasImageSizes && (
<Drawer
className={`${baseClass}__previewDrawer`}
hoverTitle
slug={sizePreviewSlug}
title={t('upload:sizesFor', { label: savedDocumentData.filename })}
title={t('upload:sizesFor', { label: data.filename })}
>
<PreviewSizes
doc={savedDocumentData}
imageCacheTag={imageCacheTag}
uploadConfig={uploadConfig}
/>
<PreviewSizes doc={data} imageCacheTag={imageCacheTag} uploadConfig={uploadConfig} />
</Drawer>
)}
</div>

View File

@@ -18,6 +18,7 @@ import type {
Context as FormContextType,
FormProps,
GetDataByPath,
Submit,
SubmitOptions,
} from './types.js'
@@ -199,14 +200,19 @@ export const Form: React.FC<FormProps> = (props) => {
return isValid
}, [collectionSlug, config, dispatchFields, id, operation, t, user, documentForm])
const submit = useCallback(
async (options: SubmitOptions = {}, e): Promise<void> => {
const submit = useCallback<Submit>(
async (options, e) => {
const {
action: actionArg = action,
context,
disableFormWhileProcessing = true,
disableSuccessStatus: disableSuccessStatusFromArgs,
method: methodToUse = method,
overrides: overridesFromArgs = {},
skipValidation,
} = options
} = options || ({} as SubmitOptions)
const disableToast = disableSuccessStatusFromArgs ?? disableSuccessStatus
if (disabled) {
if (e) {
@@ -217,6 +223,7 @@ export const Form: React.FC<FormProps> = (props) => {
// create new toast promise which will resolve manually later
let errorToast, successToast
const promise = new Promise((resolve, reject) => {
successToast = resolve
errorToast = reject
@@ -225,7 +232,7 @@ export const Form: React.FC<FormProps> = (props) => {
const hasFormSubmitAction =
actionArg || typeof action === 'string' || typeof action === 'function'
if (redirect || disableSuccessStatus || !hasFormSubmitAction) {
if (redirect || disableToast || !hasFormSubmitAction) {
// Do not show submitting toast, as the promise toast may never disappear under these conditions.
// Instead, make successToast() or errorToast() throw toast.success / toast.error
successToast = (data) => toast.success(data)
@@ -247,8 +254,10 @@ export const Form: React.FC<FormProps> = (props) => {
e.preventDefault()
}
setProcessing(true)
setDisabled(true)
if (disableFormWhileProcessing) {
setProcessing(true)
setDisabled(true)
}
if (waitForAutocomplete) {
await wait(100)
@@ -290,6 +299,7 @@ export const Form: React.FC<FormProps> = (props) => {
skipValidation || disableValidationOnSubmit ? true : await contextRef.current.validateForm()
setIsValid(isValid)
// If not valid, prevent submission
if (!isValid) {
errorToast(t('error:correctInvalidFields'))
@@ -366,9 +376,10 @@ export const Form: React.FC<FormProps> = (props) => {
if (isJSON) {
json = await res.json()
}
if (res.status < 400) {
if (typeof onSuccess === 'function') {
const newFormState = await onSuccess(json)
const newFormState = await onSuccess(json, context)
if (newFormState) {
dispatchFields({
@@ -379,12 +390,13 @@ export const Form: React.FC<FormProps> = (props) => {
})
}
}
setSubmitted(false)
setProcessing(false)
if (redirect) {
startRouteTransition(() => router.push(redirect))
} else if (!disableSuccessStatus) {
} else if (!disableToast) {
successToast(json.message || t('general:submissionSuccessful'))
}
} else {
@@ -392,6 +404,7 @@ export const Form: React.FC<FormProps> = (props) => {
setSubmitted(true)
contextRef.current = { ...contextRef.current } // triggers rerender of all components that subscribe to form
if (json.message) {
errorToast(json.message)
return
@@ -443,6 +456,8 @@ export const Form: React.FC<FormProps> = (props) => {
errorToast(message)
}
return { formState: contextRef.current.fields, res }
} catch (err) {
console.error('Error submitting form', err) // eslint-disable-line no-console
setProcessing(false)

View File

@@ -52,7 +52,7 @@ export type FormProps = {
log?: boolean
onChange?: ((args: { formState: FormState; submitted?: boolean }) => Promise<FormState>)[]
onSubmit?: (fields: FormState, data: Data) => void
onSuccess?: (json: unknown) => Promise<FormState | void> | void
onSuccess?: (json: unknown, context?: Record<string, unknown>) => Promise<FormState | void> | void
redirect?: string
submitted?: boolean
uuid?: string
@@ -70,16 +70,40 @@ export type FormProps = {
export type SubmitOptions = {
action?: string
/**
* @experimental - Note: this property is experimental and may change in the future. Use as your own discretion.
* If you want to pass additional data to the onSuccess callback, you can use this context object.
*/
context?: Record<string, unknown>
/**
* When true, will disable the form while it is processing.
* @default true
*/
disableFormWhileProcessing?: boolean
/**
* When true, will disable the success toast after form submission.
* @default false
*/
disableSuccessStatus?: boolean
method?: string
overrides?: ((formState) => FormData) | Record<string, unknown>
/**
* When true, will skip validation before submitting the form.
* @default false
*/
skipValidation?: boolean
}
export type DispatchFields = React.Dispatch<any>
export type Submit = (
options?: SubmitOptions,
e?: React.FormEvent<HTMLFormElement>,
) => Promise<void>
) => Promise</**
* @experimental - Note: the `{ res: ... }` return type is experimental and may change in the future. Use as your own discretion.
* Returns the form state and the response from the server.
*/
{ formState?: FormState; res: Response } | void>
export type ValidateForm = () => Promise<boolean>

View File

@@ -97,6 +97,7 @@ const DocumentInfo: React.FC<
const [versionCount, setVersionCount] = useState(versionCountFromProps)
const [hasPublishedDoc, setHasPublishedDoc] = useState(hasPublishedDocFromProps)
const [unpublishedVersionCount, setUnpublishedVersionCount] = useState(
unpublishedVersionCountFromProps,
)
@@ -104,11 +105,14 @@ const DocumentInfo: React.FC<
const [documentIsLocked, setDocumentIsLocked] = useControllableState<boolean | undefined>(
isLockedFromProps,
)
const [currentEditor, setCurrentEditor] = useControllableState<ClientUser | null>(
currentEditorFromProps,
)
const [lastUpdateTime, setLastUpdateTime] = useControllableState<number>(lastUpdateTimeFromProps)
const [savedDocumentData, setSavedDocumentData] = useControllableState(initialData)
const [data, setData] = useControllableState(initialData)
const [uploadStatus, setUploadStatus] = useControllableState<'failed' | 'idle' | 'uploading'>(
'idle',
)
@@ -294,13 +298,6 @@ const DocumentInfo: React.FC<
}
}, [collectionConfig, globalConfig, versionCount])
const updateSavedDocumentData = React.useCallback<DocumentInfoContext['updateSavedDocumentData']>(
(json) => {
setSavedDocumentData(json)
},
[setSavedDocumentData],
)
/**
* @todo: Remove this in v4
* Users should use the `DocumentTitleContext` instead.
@@ -309,14 +306,14 @@ const DocumentInfo: React.FC<
setDocumentTitle(
formatDocTitle({
collectionConfig,
data: { ...savedDocumentData, id },
data: { ...data, id },
dateFormat,
fallback: id?.toString(),
globalConfig,
i18n,
}),
)
}, [collectionConfig, globalConfig, savedDocumentData, dateFormat, i18n, id])
}, [collectionConfig, globalConfig, data, dateFormat, i18n, id])
// clean on unmount
useEffect(() => {
@@ -351,6 +348,7 @@ const DocumentInfo: React.FC<
...props,
action,
currentEditor,
data,
docConfig,
docPermissions,
documentIsLocked,
@@ -367,8 +365,9 @@ const DocumentInfo: React.FC<
lastUpdateTime,
mostRecentVersionIsAutosaved,
preferencesKey,
savedDocumentData,
savedDocumentData: data,
setCurrentEditor,
setData,
setDocFieldPreferences,
setDocumentIsLocked,
setDocumentTitle,
@@ -381,7 +380,7 @@ const DocumentInfo: React.FC<
unlockDocument,
unpublishedVersionCount,
updateDocumentEditor,
updateSavedDocumentData,
updateSavedDocumentData: setData,
uploadStatus,
versionCount,
}

View File

@@ -49,6 +49,7 @@ export type DocumentInfoProps = {
export type DocumentInfoContext = {
currentEditor?: ClientUser | null | number | string
data?: Data
docConfig?: ClientCollectionConfig | ClientGlobalConfig
documentIsLocked?: boolean
documentLockState: React.RefObject<{
@@ -61,21 +62,26 @@ export type DocumentInfoContext = {
incrementVersionCount: () => void
isInitializing: boolean
preferencesKey?: string
/**
* @deprecated This property is deprecated and will be removed in v4.
* Use `data` instead.
*/
savedDocumentData?: Data
setCurrentEditor?: React.Dispatch<React.SetStateAction<ClientUser>>
setData: (data: Data) => void
setDocFieldPreferences: (
field: string,
fieldPreferences: { [key: string]: unknown } & Partial<InsideFieldsPreferences>,
) => void
setDocumentIsLocked?: React.Dispatch<React.SetStateAction<boolean>>
/**
*
* @deprecated This property is deprecated and will be removed in v4.
* This is for performance reasons. Use the `DocumentTitleContext` instead.
* This is for performance reasons. Use the `DocumentTitleContext` instead
* via the `useDocumentTitle` hook.
* @example
* ```tsx
* import { useDocumentTitle } from '@payloadcms/ui'
* const { setDocumentTitle } = useDocumentTitle()
* const { setDocumentTitle } = useDocumentTitle()
* ```
*/
setDocumentTitle: React.Dispatch<React.SetStateAction<string>>
@@ -86,17 +92,22 @@ export type DocumentInfoContext = {
setUploadStatus?: (status: 'failed' | 'idle' | 'uploading') => void
/**
* @deprecated This property is deprecated and will be removed in v4.
* This is for performance reasons. Use the `DocumentTitleContext` instead.
* This is for performance reasons. Use the `DocumentTitleContext` instead
* via the `useDocumentTitle` hook.
* @example
* ```tsx
* import { useDocumentTitle } from '@payloadcms/ui'
* const { title } = useDocumentTitle()
* const { title } = useDocumentTitle()
* ```
*/
title: string
unlockDocument: (docID: number | string, slug: string) => Promise<void>
unpublishedVersionCount: number
updateDocumentEditor: (docID: number | string, slug: string, user: ClientUser) => Promise<void>
/**
* @deprecated This property is deprecated and will be removed in v4.
* Use `setData` instead.
*/
updateSavedDocumentData: (data: Data) => void
uploadStatus?: 'failed' | 'idle' | 'uploading'
versionCount: number

View File

@@ -19,8 +19,7 @@ export const useDocumentTitle = (): IDocumentTitleContext => use(DocumentTitleCo
export const DocumentTitleProvider: React.FC<{
children: React.ReactNode
}> = ({ children }) => {
const { id, collectionSlug, docConfig, globalSlug, initialData, savedDocumentData } =
useDocumentInfo()
const { id, collectionSlug, data, docConfig, globalSlug, initialData } = useDocumentInfo()
const {
config: {
@@ -45,14 +44,14 @@ export const DocumentTitleProvider: React.FC<{
setDocumentTitle(
formatDocTitle({
collectionConfig: collectionSlug ? (docConfig as ClientCollectionConfig) : undefined,
data: { ...savedDocumentData, id },
data: { ...data, id },
dateFormat,
fallback: id?.toString(),
globalConfig: globalSlug ? (docConfig as ClientGlobalConfig) : undefined,
i18n,
}),
)
}, [savedDocumentData, dateFormat, i18n, id, collectionSlug, docConfig, globalSlug])
}, [data, dateFormat, i18n, id, collectionSlug, docConfig, globalSlug])
return <DocumentTitleContext value={{ setDocumentTitle, title }}>{children}</DocumentTitleContext>
}

View File

@@ -65,6 +65,7 @@ export function DefaultEditView({
BeforeFields,
collectionSlug,
currentEditor,
data,
disableActions,
disableCreate,
disableLeaveWithoutSaving,
@@ -86,12 +87,12 @@ export function DefaultEditView({
redirectAfterDelete,
redirectAfterDuplicate,
redirectAfterRestore,
savedDocumentData,
setCurrentEditor,
setData,
setDocumentIsLocked,
setLastUpdateTime,
unlockDocument,
updateDocumentEditor,
updateSavedDocumentData,
} = useDocumentInfo()
const {
@@ -237,7 +238,7 @@ export function DefaultEditView({
setDocumentIsLocked(false)
setCurrentEditor(null)
} catch (err) {
console.error('Failed to unlock before leave', err)
console.error('Failed to unlock before leave', err) // eslint-disable-line no-console
}
}
}
@@ -256,15 +257,17 @@ export function DefaultEditView({
])
const onSave = useCallback(
async (json): Promise<FormState> => {
async (json, context?: Record<string, unknown>): Promise<FormState> => {
const controller = handleAbortRef(abortOnSaveRef)
const document = json?.doc || json?.result
const updatedAt = document?.updatedAt || new Date().toISOString()
reportUpdate({
id,
entitySlug,
updatedAt: document?.updatedAt || new Date().toISOString(),
updatedAt,
})
// If we're editing the doc of the logged-in user,
@@ -273,10 +276,14 @@ export function DefaultEditView({
void refreshCookieAsync()
}
incrementVersionCount()
setLastUpdateTime(updatedAt)
if (typeof updateSavedDocumentData === 'function') {
void updateSavedDocumentData(document || {})
if (context?.incrementVersionCount !== false) {
incrementVersionCount()
}
if (typeof setData === 'function') {
void setData(document || {})
}
if (typeof onSaveFromContext === 'function') {
@@ -284,6 +291,7 @@ export function DefaultEditView({
void onSaveFromContext({
...json,
context,
operation,
updatedAt:
operation === 'update'
@@ -306,7 +314,7 @@ export function DefaultEditView({
await getDocPermissions(json)
if ((id || globalSlug) && !autosaveEnabled) {
if (id || globalSlug) {
const docPreferences = await getDocPreferences()
const { state } = await getFormState({
@@ -341,18 +349,19 @@ export function DefaultEditView({
user,
collectionSlug,
userSlug,
incrementVersionCount,
updateSavedDocumentData,
setLastUpdateTime,
setData,
onSaveFromContext,
redirectAfterCreate,
isEditing,
depth,
redirectAfterCreate,
getDocPermissions,
globalSlug,
autosaveEnabled,
refreshCookieAsync,
incrementVersionCount,
adminRoute,
locale,
startRouteTransition,
router,
resetUploadEdits,
getDocPreferences,
@@ -362,7 +371,6 @@ export function DefaultEditView({
schemaPathSegments,
isLockingEnabled,
setDocumentIsLocked,
startRouteTransition,
],
)
@@ -549,7 +557,7 @@ export function DefaultEditView({
SaveButton,
SaveDraftButton,
}}
data={savedDocumentData}
data={data}
disableActions={disableActions || isFolderCollection || isTrashed}
disableCreate={disableCreate}
EditMenuItems={EditMenuItems}
@@ -612,14 +620,14 @@ export function DefaultEditView({
className={`${baseClass}__auth`}
collectionSlug={collectionConfig.slug}
disableLocalStrategy={collectionConfig.auth?.disableLocalStrategy}
email={savedDocumentData?.email}
email={data?.email}
loginWithUsername={auth?.loginWithUsername}
operation={operation}
readOnly={!hasSavePermission}
requirePassword={!id}
setValidateBeforeSubmit={setValidateBeforeSubmit}
useAPIKey={auth.useAPIKey}
username={savedDocumentData?.username}
username={data?.username}
verify={auth.verify}
/>
)}