chore: adjusts endpoint for buildFormState

This commit is contained in:
Jarrod Flesch
2024-02-20 23:13:48 -05:00
26 changed files with 386 additions and 201 deletions

View File

@@ -8,4 +8,5 @@ export default ({ params, searchParams }) =>
collectionSlug: params.collection,
searchParams,
config,
route: `/${params.collection + '/' + params.segments?.join('/')}`,
})

View File

@@ -3,4 +3,4 @@
import { Dashboard } from '@payloadcms/next/pages/Dashboard'
import config from 'payload-config'
export default async () => Dashboard({ config })
export default async ({ searchParams }) => Dashboard({ config, searchParams })

View File

@@ -22,6 +22,8 @@ export const Account = async ({
const { config, payload, permissions, user, i18n, locale } = await initPage({
config: configPromise,
redirectUnauthenticatedUser: true,
searchParams,
route: `/account`,
})
const {

View File

@@ -15,15 +15,19 @@ export const CollectionList = async ({
collectionSlug,
config: configPromise,
searchParams,
route,
}: {
collectionSlug: string
config: Promise<SanitizedConfig>
searchParams: { [key: string]: string | string[] | undefined }
route
}) => {
const { config, payload, permissions, user, collectionConfig } = await initPage({
config: configPromise,
redirectUnauthenticatedUser: true,
collectionSlug,
route,
searchParams,
})
let listPreferences: ListPreferences

View File

@@ -7,12 +7,16 @@ import { DefaultDashboard } from './Default'
export const Dashboard = async ({
config: configPromise,
searchParams,
}: {
config: Promise<SanitizedConfig>
searchParams: { [key: string]: string | string[] | undefined }
}) => {
const { config, user, permissions } = await initPage({
config: configPromise,
redirectUnauthenticatedUser: true,
route: '',
searchParams,
})
const CustomDashboardComponent = config.admin.components?.views?.Dashboard

View File

@@ -43,12 +43,16 @@ export const Document = async ({
const isEditing = Boolean(globalSlug || (collectionSlug && !!id))
const route = `/${collectionSlug || globalSlug + '/' + params.segments.join('/')}`
const { config, payload, permissions, user, collectionConfig, globalConfig, locale, i18n } =
await initPage({
config: configPromise,
redirectUnauthenticatedUser: true,
collectionSlug,
globalSlug,
searchParams,
route,
})
if (!collectionConfig && !globalConfig) {
@@ -149,7 +153,7 @@ export const Document = async ({
limit: 1,
})) as any as { docs: { value: DocumentPreferences }[] }
const formState = await buildStateFromSchema({
const initialState = await buildStateFromSchema({
id,
data: data || {},
fieldSchema: formatFields(fields, isEditing),
@@ -176,13 +180,11 @@ export const Document = async ({
globalSlug,
data,
hasSavePermission,
formState,
initialState,
isEditing,
docPermissions,
docPreferences,
updatedAt: data?.updatedAt?.toString(),
user,
locale,
payload,
config,
searchParams,

View File

@@ -35,7 +35,7 @@ export const Login: React.FC<{
config: Promise<SanitizedConfig>
searchParams: { [key: string]: string | string[] | undefined }
}> = async ({ config: configPromise, searchParams }) => {
const { config, user } = await initPage({ config: configPromise })
const { config, user } = await initPage({ config: configPromise, searchParams, route: '/login' })
const {
admin: { components: { afterLogin, beforeLogin } = {}, user: userSlug },

View File

@@ -0,0 +1,67 @@
import httpStatus from 'http-status'
import {
BuildFormStateArgs,
FieldSchemaMap,
buildFieldSchemaMap,
buildStateFromSchema,
reduceFieldsToValues,
} from '@payloadcms/ui'
import { Field, PayloadRequest, SanitizedConfig } from 'payload/types'
let cached = global._payload_fieldSchemaMap
if (!cached) {
// eslint-disable-next-line no-multi-assign
cached = global._payload_fieldSchemaMap = null
}
export const getFieldSchemaMap = (config: SanitizedConfig): FieldSchemaMap => {
if (cached) {
return cached
}
cached = buildFieldSchemaMap(config)
return cached
}
export const buildFormState = async ({ req }: { req: PayloadRequest }) => {
const { data: reqData, user, t, locale } = req
// TODO: run ADMIN access control for user
const fieldSchemaMap = getFieldSchemaMap(req.payload.config)
const { id, operation, docPreferences, formState, schemaPath } = reqData as BuildFormStateArgs
const schemaPathSegments = schemaPath.split('.')
let fieldSchema: Field[]
if (schemaPathSegments.length === 1) {
if (req.payload.collections[schemaPath]) {
fieldSchema = req.payload.collections[schemaPath].config.fields
} else if (req.payload.globals[schemaPath]) {
fieldSchema = req.payload.globals[schemaPath].config.fields
}
} else if (fieldSchemaMap.has(schemaPath)) {
fieldSchema = fieldSchemaMap.get(schemaPath)
}
const data = reduceFieldsToValues(formState, true)
const result = await buildStateFromSchema({
id,
data,
fieldSchema,
locale,
operation,
preferences: docPreferences,
t,
user,
})
return Response.json(result, {
status: httpStatus.OK,
})
}

View File

@@ -12,6 +12,7 @@ import {
} from './types'
import { RouteError } from './RouteError'
import { buildFormState } from './buildFormState'
import { endpointsAreDisabled } from './checkEndpoints'
import { me } from './auth/me'
@@ -50,6 +51,9 @@ const endpoints = {
GET: {
access,
},
POST: {
'form-state': buildFormState,
},
},
collection: {
GET: {
@@ -295,6 +299,7 @@ export const POST =
config,
params: { collection: slug1 },
})
collection = req.payload.collections?.[slug1]
const disableEndpoints = endpointsAreDisabled({
@@ -315,6 +320,7 @@ export const POST =
payloadRequest: req,
endpoints: collection.config.endpoints,
})
if (customEndpointResponse) return customEndpointResponse
switch (slug.length) {
@@ -324,6 +330,7 @@ export const POST =
break
case 2:
if (slug2 in endpoints.collection.POST) {
// /:collection/form-state
// /:collection/login
// /:collection/logout
// /:collection/unlock

View File

@@ -1,4 +1,5 @@
import { headers as getHeaders } from 'next/headers'
import qs from 'qs'
import { auth } from './auth'
@@ -22,12 +23,16 @@ export const initPage = async ({
collectionSlug,
globalSlug,
localeParam,
searchParams,
route,
}: {
config: SanitizedConfig | Promise<SanitizedConfig>
redirectUnauthenticatedUser?: boolean
collectionSlug?: string
globalSlug?: string
localeParam?: string
searchParams?: { [key: string]: string | string[] | undefined }
route?: string
}): Promise<{
payload: Awaited<ReturnType<typeof getPayload>>
permissions: Awaited<ReturnType<typeof auth>>['permissions']
@@ -46,15 +51,18 @@ export const initPage = async ({
config: configPromise,
cookies,
})
const language = getRequestLanguage({ cookies, headers })
const config = await configPromise
const { localization, routes, collections, globals } = config
if (redirectUnauthenticatedUser && !user) {
// `redirect(`${payload.config.routes.admin}/unauthorized`)` is not built yet
redirect(`${routes.admin}/login`)
if (redirectUnauthenticatedUser && !user && route !== '/login') {
const stringifiedSearchParams = Object.keys(searchParams ?? {}).length
? `?${qs.stringify(searchParams)}`
: ''
redirect(`${routes.admin}/login?redirect=${routes.admin + route + stringifiedSearchParams}`)
}
const payload = await getPayload({

View File

@@ -25,6 +25,9 @@ import IDLabel from '../IDLabel'
import type { EditViewProps } from '../../views/types'
import { DefaultEditView } from '../../views/Edit'
import { Gutter } from '../Gutter'
import { LoadingOverlay } from '../Loading'
import { getFormState } from '../../views/Edit/getFormState'
import { useFieldPath } from '../../forms/FieldPathProvider'
const Content: React.FC<DocumentDrawerProps> = ({ collectionSlug, Header, drawerSlug, onSave }) => {
const config = useConfig()
@@ -37,7 +40,7 @@ const Content: React.FC<DocumentDrawerProps> = ({ collectionSlug, Header, drawer
const { closeModal, modalState, toggleModal } = useModal()
const locale = useLocale()
const { user } = useAuth()
const [internalState, setInternalState] = useState<FormState>()
const [initialState, setInitialState] = useState<FormState>()
const { i18n, t } = useTranslation()
const hasInitializedState = useRef(false)
const [isOpen, setIsOpen] = useState(false)
@@ -48,6 +51,7 @@ const Content: React.FC<DocumentDrawerProps> = ({ collectionSlug, Header, drawer
const { admin: { components: { views: { Edit } = {} } = {} } = {}, fields: fieldsFromConfig } =
collectionConfig
const { schemaPath } = useFieldPath()
const { id, docPermissions } = useDocumentInfo()
// The component definition could come from multiple places in the config
@@ -105,7 +109,33 @@ const Content: React.FC<DocumentDrawerProps> = ({ collectionSlug, Header, drawer
(isEditing && docPermissions?.update?.permission) ||
(!isEditing && (docPermissions as CollectionPermission)?.create?.permission)
const isLoading = !internalState || !docPermissions || isLoadingDocument
useEffect(() => {
if (!hasInitializedState.current && data) {
const getInitialState = async () => {
const result = await getFormState({
serverURL,
apiRoute: api,
body: {
id,
operation: isEditing ? 'update' : 'create',
formState: data,
docPreferences: null, // TODO: get this
schemaPath,
},
})
setInitialState(result)
}
getInitialState()
}
}, [])
const isLoading = !initialState || !docPermissions || isLoadingDocument
if (isLoading) {
return <LoadingOverlay />
}
const componentProps: EditViewProps = {
id,
@@ -144,11 +174,10 @@ const Content: React.FC<DocumentDrawerProps> = ({ collectionSlug, Header, drawer
onSave,
collectionSlug: collectionConfig.slug,
docPermissions: docPermissions as CollectionPermission,
docPreferences: null,
docPreferences: null, // TODO: get this
user,
updatedAt: data?.updatedAt,
locale,
initializeFormState: true,
initialState,
}
return (

View File

@@ -28,3 +28,4 @@ export { default as buildInitialState } from '../forms/Form'
export { default as FieldDescription } from '../forms/FieldDescription'
export { default as useField } from '../forms/useField'
export { default as Error } from '../forms/Error'
export type { BuildFormStateArgs } from '../forms/utilities/buildStateFromSchema'

View File

@@ -5,3 +5,5 @@ export type { EntityToGroup, Group } from '../utilities/groupNavItems'
export { EntityType, groupNavItems } from '../utilities/groupNavItems'
export { withMergedProps } from '../utilities/withMergedProps'
export type { FieldMap, MappedField } from '../utilities/buildComponentMap/types'
export { buildFieldSchemaMap } from '../utilities/buildFieldSchemaMap'
export type { FieldSchemaMap } from '../utilities/buildFieldSchemaMap/types'

View File

@@ -16,7 +16,6 @@ export const FieldPathProvider: React.FC<{
children: React.ReactNode
}> = (props) => {
const { children, path, schemaPath } = props
return (
<FieldPathContext.Provider
value={{

View File

@@ -39,7 +39,6 @@ import getSiblingDataFunc from './getSiblingData'
import initContextState from './initContextState'
import reduceFieldsToValues from './reduceFieldsToValues'
import useDebounce from '../../hooks/useDebounce'
import { FieldPathProvider } from '../FieldPathProvider'
const baseClass = 'form'
@@ -514,7 +513,7 @@ const Form: React.FC<Props> = (props) => {
<ProcessingContext.Provider value={processing}>
<ModifiedContext.Provider value={modified}>
<FormFieldsContext.Provider value={fieldsReducer}>
<FieldPathProvider path="">{children}</FieldPathProvider>
{children}
</FormFieldsContext.Provider>
</ModifiedContext.Provider>
</ProcessingContext.Provider>

View File

@@ -39,6 +39,7 @@ type BlockFieldProps = UseDraggableSortableReturn & {
path: string
labels: Labels
permissions: FieldPermissions
schemaPath: string
}
export const BlockRow: React.FC<BlockFieldProps> = ({
@@ -54,6 +55,7 @@ export const BlockRow: React.FC<BlockFieldProps> = ({
listeners,
moveRow,
path: parentPath,
schemaPath,
permissions,
readOnly,
removeRow,
@@ -132,7 +134,7 @@ export const BlockRow: React.FC<BlockFieldProps> = ({
onToggle={(collapsed) => setCollapse(row.id, collapsed)}
>
<HiddenInput name={`${path}.id`} value={row.id} />
<FieldPathProvider path={path} schemaPath={`${parentPath}.${block.slug}`}>
<FieldPathProvider path={path} schemaPath={`${schemaPath}.${block.slug}`}>
<RenderFields
className={`${baseClass}__fields`}
fieldMap={block.subfields}

View File

@@ -96,6 +96,7 @@ const BlocksField: React.FC<Props> = (props) => {
valid,
value,
path,
schemaPath,
} = useField<number>({
hasRows: true,
path: pathFromProps || name,
@@ -248,6 +249,7 @@ const BlocksField: React.FC<Props> = (props) => {
labels={labels}
moveRow={moveRow}
path={path}
schemaPath={schemaPath}
permissions={permissions}
readOnly={readOnly}
removeRow={removeRow}

View File

@@ -1,7 +1,7 @@
import type { TFunction } from '@payloadcms/translations'
import type { User } from 'payload/auth'
import type { Field as FieldSchema, Data } from 'payload/types'
import type { Field as FieldSchema, Data, DocumentPreferences } from 'payload/types'
import type { FormState } from '../../Form/types'
import { iterateFields } from './iterateFields'
@@ -21,6 +21,14 @@ type Args = {
user?: User | null
}
export type BuildFormStateArgs = {
id?: string | number
operation?: 'create' | 'update'
docPreferences: DocumentPreferences
formState?: FormState
schemaPath: string
}
const buildStateFromSchema = async (args: Args): Promise<FormState> => {
const { id, data: fullData = {}, fieldSchema, locale, operation, preferences, t, user } = args

View File

@@ -11,7 +11,7 @@ import type { AuthContext } from './types'
import { requests } from '../../utilities/api'
import useDebounce from '../../hooks/useDebounce'
import { useConfig } from '../Config'
import { usePathname, useRouter } from 'next/navigation'
import { usePathname, useRouter, useSearchParams } from 'next/navigation'
// import { useLocale } from '../Locale'
const Context = createContext({} as AuthContext)
@@ -19,6 +19,7 @@ const Context = createContext({} as AuthContext)
const maxTimeoutTime = 2147483647
export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const searchParams = useSearchParams()
const [user, setUser] = useState<User | null>()
const [tokenInMemory, setTokenInMemory] = useState<string>()
const [tokenExpiration, setTokenExpiration] = useState<number>()
@@ -209,6 +210,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children
if (autoLoginJson?.token) {
setTokenAndExpiration(autoLoginJson)
}
push(searchParams.get('redirect') || admin)
} else {
setUser(null)
revokeTokenAndExpire()

View File

@@ -0,0 +1,25 @@
import type { SanitizedConfig } from 'payload/types'
import { FieldSchemaMap } from './types'
import { traverseFields } from './traverseFields'
export const buildFieldSchemaMap = (config: SanitizedConfig): FieldSchemaMap => {
const result: FieldSchemaMap = new Map()
config.collections.forEach((collection) => {
traverseFields({
schemaPath: collection.slug,
fields: collection.fields,
schemaMap: result,
})
})
config.globals.forEach((global) => {
traverseFields({
schemaPath: global.slug,
fields: global.fields,
schemaMap: result,
})
})
return result
}

View File

@@ -0,0 +1,53 @@
import { Field, tabHasName } from 'payload/types'
import { FieldSchemaMap } from './types'
type Args = {
fields: Field[]
schemaMap: FieldSchemaMap
schemaPath: string
}
export const traverseFields = ({ fields, schemaMap, schemaPath }: Args) => {
fields.map((field) => {
switch (field.type) {
case 'group':
case 'array':
traverseFields({
fields: field.fields,
schemaMap,
schemaPath: `${schemaPath}.${field.name}`,
})
break
case 'collapsible':
case 'row':
traverseFields({
fields: field.fields,
schemaMap,
schemaPath,
})
break
case 'blocks':
field.blocks.map((block) => {
traverseFields({
fields: block.fields,
schemaMap,
schemaPath: `${schemaPath}.${field.name}.${block.slug}`,
})
})
break
case 'tabs':
field.tabs.map((tab) => {
const tabSchemaPath = tabHasName(tab) ? `${schemaPath}.${tab.name}` : schemaPath
traverseFields({
fields: tab.fields,
schemaMap,
schemaPath: tabSchemaPath,
})
})
break
}
})
}

View File

@@ -0,0 +1,3 @@
import { Field } from 'payload/types'
export type FieldSchemaMap = Map<string, Field[]>

View File

@@ -1,63 +0,0 @@
'use server'
import { getPayload } from 'payload'
import { FormState } from '../../forms/Form/types'
import configPromise from 'payload-config'
import buildStateFromSchema from '../../forms/utilities/buildStateFromSchema'
import { reduceFieldsToValues } from '../..'
import { DocumentPreferences } from 'payload/types'
import { Locale } from 'payload/config'
import { User } from 'payload/auth'
import { initI18n } from '@payloadcms/translations'
import { translations } from '@payloadcms/translations/api'
export const getFormStateFromServer = async (
args: {
collectionSlug: string
docPreferences: DocumentPreferences
locale: Locale
id?: string
operation: 'create' | 'update'
user: User
language: string
},
{
formState,
}: {
formState: FormState
},
) => {
const { collectionSlug, docPreferences, locale, id, operation, user, language } = args
const payload = await getPayload({
config: configPromise,
})
const collectionConfig = payload.collections[collectionSlug]?.config
if (!collectionConfig) {
throw new Error(`Collection with slug "${collectionSlug}" not found`)
}
const data = reduceFieldsToValues(formState, true)
const { t } = await initI18n({
translations,
language: language,
config: payload.config.i18n,
context: 'api',
})
const result = await buildStateFromSchema({
id,
data,
fieldSchema: collectionConfig.fields,
locale: locale.code,
operation,
preferences: docPreferences,
t,
user,
})
return result
}

View File

@@ -0,0 +1,26 @@
import { SanitizedConfig } from 'payload/types'
import { FormState } from '../../forms/Form/types'
import { BuildFormStateArgs } from '../..'
export const getFormState = async (args: {
serverURL: SanitizedConfig['serverURL']
apiRoute: SanitizedConfig['routes']['api']
body: BuildFormStateArgs
}): Promise<FormState> => {
const { serverURL, apiRoute, body } = args
const res = await fetch(`${serverURL}${apiRoute}/form-state`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
})
if (res.ok) {
const json = (await res.json()) as FormState
return json
}
return body?.formState
}

View File

@@ -1,5 +1,5 @@
'use client'
import React, { Fragment, useCallback, useState } from 'react'
import React, { Fragment, useCallback } from 'react'
import { FormLoadingOverlayToggle } from '../../elements/Loading'
import Form from '../../forms/Form'
@@ -9,18 +9,19 @@ import { OperationProvider } from '../../providers/OperationProvider'
import { DocumentControls } from '../../elements/DocumentControls'
import { DocumentFields } from '../../elements/DocumentFields'
import { LeaveWithoutSaving } from '../../elements/LeaveWithoutSaving'
// import Meta from '../../../../utilities/Meta'
import Auth from './Auth'
import { SetStepNav } from './SetStepNav'
import { EditViewProps } from '../types'
import { getFormStateFromServer } from './action'
import { Upload } from './Upload'
import { useConfig } from '../../providers/Config'
import { useTranslation } from '../../providers/Translation'
import { useComponentMap } from '../../providers/ComponentMapProvider'
import { SetDocumentTitle } from './SetDocumentTitle'
import { Props as FormProps, FormState } from '../../forms/Form/types'
import './index.scss'
import { BuildFormStateArgs } from '../..'
import { getFormState } from './getFormState'
import { FieldPathProvider } from '../../forms/FieldPathProvider'
const baseClass = 'collection-edit'
@@ -32,20 +33,22 @@ export const DefaultEditView: React.FC<EditViewProps> = (props) => {
AfterDocument,
AfterFields,
data,
formState: initialStateFromProps,
initializeFormState,
initialState,
// isLoading,
onSave: onSaveFromProps,
docPreferences,
docPermissions,
docPreferences,
user,
locale,
} = props
const config = useConfig()
const { collections, globals } = config
const {
serverURL,
collections,
globals,
routes: { api: apiRoute },
} = config
const { i18n } = useTranslation()
const { getFieldMap } = useComponentMap()
const collectionConfig =
@@ -55,6 +58,8 @@ export const DefaultEditView: React.FC<EditViewProps> = (props) => {
const globalConfig =
'globalSlug' in props && globals.find((global) => global.slug === props.globalSlug)
const [schemaPath] = React.useState(collectionConfig?.slug || globalConfig?.slug)
const fieldMap = getFieldMap({
collectionSlug: collectionConfig?.slug,
globalSlug: globalConfig?.slug,
@@ -64,22 +69,6 @@ export const DefaultEditView: React.FC<EditViewProps> = (props) => {
const isEditing = 'isEditing' in props ? props.isEditing : undefined
const operation = isEditing ? 'update' : 'create'
const [initialState] = useState(() => {
if (initializeFormState) {
const initializedState = getFormStateFromServer.bind(null, {
collectionSlug: collectionConfig?.slug,
id: id || undefined,
locale,
language: i18n.language,
operation,
docPreferences,
user,
})({ formState: {} })
return initializedState
} else return initialStateFromProps
})
const auth = collectionConfig ? collectionConfig.auth : undefined
const upload = collectionConfig ? collectionConfig.upload : undefined
const hasSavePermission = 'hasSavePermission' in props ? props.hasSavePermission : undefined
@@ -137,41 +126,56 @@ export const DefaultEditView: React.FC<EditViewProps> = (props) => {
// setViewActions(defaultActions)
// }, [id, location.pathname, collectionConfig?.admin?.components?.views?.Edit, setViewActions])
const rebuildFormState = getFormStateFromServer.bind(null, {
collectionSlug: collectionConfig?.slug,
id: id || undefined,
locale,
language: i18n.language,
operation,
docPreferences,
user,
})
const onChange: FormProps['onChange'][0] = useCallback(
async ({ formState: prevFormState }) =>
getFormState({
serverURL,
apiRoute,
body: {
id,
operation,
formState: prevFormState,
docPreferences,
schemaPath,
},
}),
[
serverURL,
apiRoute,
collectionConfig,
globalConfig,
id,
operation,
docPreferences,
schemaPath,
],
)
return (
<main className={classes}>
<OperationProvider operation={operation}>
<Form
action={action}
className={`${baseClass}__form`}
disabled={!hasSavePermission}
initialState={initialState}
method={id ? 'PATCH' : 'POST'}
beforeSubmit={[rebuildFormState]}
onChange={[rebuildFormState]}
onSuccess={onSave}
>
<FormLoadingOverlayToggle
action={operation}
// formIsLoading={isLoading}
// loadingSuffix={getTranslation(collectionConfig.labels.singular, i18n)}
name={`collection-edit--${
typeof collectionConfig?.labels?.singular === 'string'
? collectionConfig.labels.singular
: 'document'
}`}
type="withoutNav"
/>
{/* <Meta
<FieldPathProvider path="" schemaPath={schemaPath}>
<OperationProvider operation={operation}>
<Form
action={action}
className={`${baseClass}__form`}
disabled={!hasSavePermission}
initialState={initialState}
method={id ? 'PATCH' : 'POST'}
onChange={[onChange]}
onSuccess={onSave}
>
<FormLoadingOverlayToggle
action={operation}
// formIsLoading={isLoading}
// loadingSuffix={getTranslation(collectionConfig.labels.singular, i18n)}
name={`collection-edit--${
typeof collectionConfig?.labels?.singular === 'string'
? collectionConfig.labels.singular
: 'document'
}`}
type="withoutNav"
/>
{/* <Meta
description={`${isEditing ? t('general:editing') : t('general:creating')} - ${getTranslation(
collection.labels.singular,
i18n,
@@ -182,61 +186,62 @@ export const DefaultEditView: React.FC<EditViewProps> = (props) => {
i18n,
)}`}
/> */}
{BeforeDocument}
{preventLeaveWithoutSaving && <LeaveWithoutSaving />}
<SetStepNav
collectionSlug={collectionConfig?.slug}
globalSlug={globalConfig?.slug}
useAsTitle={collectionConfig?.admin?.useAsTitle}
id={id}
isEditing={isEditing || false}
pluralLabel={collectionConfig?.labels?.plural}
/>
<SetDocumentTitle
config={config}
collectionConfig={collectionConfig}
globalConfig={globalConfig}
/>
<DocumentControls
apiURL={apiURL}
slug={collectionConfig?.slug}
data={data}
disableActions={disableActions}
hasSavePermission={hasSavePermission}
id={id}
isEditing={isEditing}
permissions={docPermissions}
/>
<DocumentFields
BeforeFields={
<Fragment>
{auth && (
<Auth
className={`${baseClass}__auth`}
collectionSlug={collectionConfig.slug}
email={data?.email}
operation={operation}
readOnly={!hasSavePermission}
requirePassword={!isEditing}
useAPIKey={auth.useAPIKey}
verify={auth.verify}
/>
)}
{upload && (
<Upload
uploadConfig={upload}
collectionSlug={collectionConfig.slug}
initialState={initialState}
/>
)}
</Fragment>
}
fieldMap={fieldMap}
AfterFields={AfterFields}
/>
{AfterDocument}
</Form>
</OperationProvider>
{BeforeDocument}
{preventLeaveWithoutSaving && <LeaveWithoutSaving />}
<SetStepNav
collectionSlug={collectionConfig?.slug}
globalSlug={globalConfig?.slug}
useAsTitle={collectionConfig?.admin?.useAsTitle}
id={id}
isEditing={isEditing || false}
pluralLabel={collectionConfig?.labels?.plural}
/>
<SetDocumentTitle
config={config}
collectionConfig={collectionConfig}
globalConfig={globalConfig}
/>
<DocumentControls
apiURL={apiURL}
slug={collectionConfig?.slug}
data={data}
disableActions={disableActions}
hasSavePermission={hasSavePermission}
id={id}
isEditing={isEditing}
permissions={docPermissions}
/>
<DocumentFields
BeforeFields={
<Fragment>
{auth && (
<Auth
className={`${baseClass}__auth`}
collectionSlug={collectionConfig.slug}
email={data?.email}
operation={operation}
readOnly={!hasSavePermission}
requirePassword={!isEditing}
useAPIKey={auth.useAPIKey}
verify={auth.verify}
/>
)}
{upload && (
<Upload
uploadConfig={upload}
collectionSlug={collectionConfig.slug}
initialState={initialState}
/>
)}
</Fragment>
}
fieldMap={fieldMap}
AfterFields={AfterFields}
/>
{AfterDocument}
</Form>
</OperationProvider>
</FieldPathProvider>
</main>
)
}

View File

@@ -1,7 +1,6 @@
import type { CollectionPermission, GlobalPermission, Permissions, User } from 'payload/auth'
import type { Document, DocumentPreferences, Payload, SanitizedConfig } from 'payload/types'
import type { FormState } from '../forms/Form/types'
import type { Locale } from 'payload/config'
import { I18n } from '@payloadcms/translations'
export type EditViewProps = (
@@ -22,15 +21,13 @@ export type EditViewProps = (
action?: string
apiURL: string
canAccessAdmin?: boolean
data: Document
docPreferences: DocumentPreferences
data: Document
// isLoading: boolean
onSave?: (json: any) => void
updatedAt: string
user: User | null | undefined
locale: Locale
formState?: FormState
initializeFormState?: boolean
initialState?: FormState
BeforeDocument?: React.ReactNode
AfterDocument?: React.ReactNode
AfterFields?: React.ReactNode