Skip to content

Commit 340089f

Browse files
committed
migrates fieldSchemasToFormState
1 parent e8604bd commit 340089f

File tree

6 files changed

+110
-88
lines changed

6 files changed

+110
-88
lines changed

packages/payload/src/admin/forms/Form.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { type SupportedLanguages } from '@payloadcms/translations'
22

33
import type { SanitizedDocumentPermissions } from '../../auth/types.js'
4-
import type { Field, Validate } from '../../fields/config/types.js'
4+
import type { Field, TabAsField, Validate } from '../../fields/config/types.js'
55
import type { TypedLocale } from '../../index.js'
66
import type { DocumentPreferences } from '../../preferences/types.js'
77
import type { PayloadRequest, Where } from '../../types/index.js'
@@ -43,7 +43,7 @@ export type FieldState = {
4343
* The fieldSchema may be part of the form state if `includeSchema: true` is passed to buildFormState.
4444
* This will never be in the form state of the client.
4545
*/
46-
fieldSchema?: Field
46+
fieldSchema?: Field | TabAsField
4747
filterOptions?: FilterOptionsResult
4848
initialValue?: unknown
4949
passesCondition?: boolean

packages/payload/src/fields/config/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1683,7 +1683,7 @@ export type FieldWithManyClient = RelationshipFieldClient | SelectFieldClient
16831683
export type FieldWithMaxDepth = RelationshipField | UploadField
16841684
export type FieldWithMaxDepthClient = JoinFieldClient | RelationshipFieldClient | UploadFieldClient
16851685

1686-
export function fieldHasSubFields<TField extends ClientField | Field>(
1686+
export function fieldHasSubFields<TField extends ClientField | Field | TabAsField>(
16871687
field: TField,
16881688
): field is TField & (TField extends ClientField ? FieldWithSubFieldsClient : FieldWithSubFields) {
16891689
return (

packages/ui/src/forms/fieldSchemasToFormState/addFieldStatePromise.ts

Lines changed: 91 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type {
1010
PayloadRequest,
1111
SanitizedFieldPermissions,
1212
SanitizedFieldsPermissions,
13+
TabAsField,
1314
Validate,
1415
} from 'payload'
1516

@@ -21,7 +22,6 @@ import {
2122
fieldIsHiddenOrDisabled,
2223
fieldIsID,
2324
fieldIsLocalized,
24-
getFieldPaths,
2525
tabHasName,
2626
} from 'payload/shared'
2727

@@ -42,7 +42,7 @@ export type AddFieldStatePromiseArgs = {
4242
clientFieldSchemaMap?: ClientFieldSchemaMap
4343
collectionSlug?: string
4444
data: Data
45-
field: Field
45+
field: Field | TabAsField
4646
fieldIndex: number
4747
fieldSchemaMap: FieldSchemaMap
4848
/**
@@ -168,7 +168,7 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
168168
return
169169
}
170170

171-
const validate: Validate = field.validate
171+
const validate: Validate = 'validate' in field ? field.validate : undefined
172172

173173
let validationResult: string | true = true
174174

@@ -235,12 +235,13 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
235235
const arrayValue = Array.isArray(data[field.name]) ? data[field.name] : []
236236

237237
const { promises, rows } = arrayValue.reduce(
238-
(acc, row, i: number) => {
239-
const parentPath = path + '.' + i
238+
(acc, row, rowIndex: number) => {
239+
const rowPath = path + '.' + rowIndex
240+
240241
row.id = row?.id || new ObjectId().toHexString()
241242

242243
if (!omitParents && (!filter || filter(args))) {
243-
const idKey = parentPath + '.id'
244+
const idKey = rowPath + '.id'
244245

245246
state[idKey] = {
246247
initialValue: row.id,
@@ -270,7 +271,7 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
270271
operation,
271272
parentIndexPath: '',
272273
parentPassesCondition: passesCondition,
273-
parentPath,
274+
parentPath: rowPath,
274275
parentSchemaPath: schemaPath,
275276
permissions:
276277
fieldPermissions === true ? fieldPermissions : fieldPermissions?.fields || {},
@@ -357,22 +358,23 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
357358
const blocksValue = Array.isArray(data[field.name]) ? data[field.name] : []
358359

359360
const { promises, rowMetadata } = blocksValue.reduce(
360-
(acc, row, i: number) => {
361+
(acc, row, rowIndex: number) => {
361362
const block = field.blocks.find((blockType) => blockType.slug === row.blockType)
363+
362364
if (!block) {
363365
throw new Error(
364366
`Block with type "${row.blockType}" was found in block data, but no block with that type is defined in the config for field with schema path ${schemaPath}.`,
365367
)
366368
}
367369

368-
const parentPath = path + '.' + i
370+
const rowPath = path + '.' + rowIndex
369371

370372
if (block) {
371373
row.id = row?.id || new ObjectId().toHexString()
372374

373375
if (!omitParents && (!filter || filter(args))) {
374376
// Handle block `id` field
375-
const idKey = parentPath + '.id'
377+
const idKey = rowPath + '.id'
376378

377379
state[idKey] = {
378380
initialValue: row.id,
@@ -386,7 +388,7 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
386388
}
387389

388390
// Handle `blockType` field
389-
const fieldKey = parentPath + '.blockType'
391+
const fieldKey = rowPath + '.blockType'
390392

391393
state[fieldKey] = {
392394
initialValue: row.blockType,
@@ -400,7 +402,7 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
400402
}
401403

402404
// Handle `blockName` field
403-
const blockNameKey = parentPath + '.blockName'
405+
const blockNameKey = rowPath + '.blockName'
404406

405407
state[blockNameKey] = {}
406408

@@ -434,7 +436,7 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
434436
operation,
435437
parentIndexPath: '',
436438
parentPassesCondition: passesCondition,
437-
parentPath,
439+
parentPath: rowPath,
438440
parentSchemaPath: schemaPath + '.' + block.slug,
439441
permissions:
440442
fieldPermissions === true
@@ -546,6 +548,7 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
546548

547549
break
548550
}
551+
549552
case 'relationship':
550553
case 'upload': {
551554
if (field.filterOptions) {
@@ -678,8 +681,8 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
678681
operation,
679682
parentIndexPath: indexPath,
680683
parentPassesCondition: passesCondition,
681-
parentPath,
682-
parentSchemaPath,
684+
parentPath: path,
685+
parentSchemaPath: schemaPath,
683686
permissions: parentPermissions, // TODO: Verify this is correct
684687
preferences,
685688
previousFormState,
@@ -690,74 +693,85 @@ export const addFieldStatePromise = async (args: AddFieldStatePromiseArgs): Prom
690693
skipValidation,
691694
state,
692695
})
693-
} else if (field.type === 'tabs') {
694-
const promises = field.tabs.map((tab, tabIndex) => {
695-
const isNamedTab = tabHasName(tab)
696-
697-
const {
698-
indexPath: tabIndexPath,
699-
path: tabPath,
700-
schemaPath: tabSchemaPath,
701-
} = getFieldPaths({
702-
field: {
703-
...tab,
704-
type: 'tab',
705-
},
706-
index: tabIndex,
707-
parentIndexPath: indexPath,
708-
parentPath,
709-
parentSchemaPath,
710-
})
711-
712-
let childPermissions: SanitizedFieldsPermissions = undefined
713-
714-
if (isNamedTab) {
715-
if (parentPermissions === true) {
696+
} else if (field.type === 'tab') {
697+
const isNamedTab = tabHasName(field)
698+
699+
let childPermissions: SanitizedFieldsPermissions = undefined
700+
701+
if (isNamedTab) {
702+
if (parentPermissions === true) {
703+
childPermissions = true
704+
} else {
705+
const tabPermissions = parentPermissions?.[field.name]
706+
if (tabPermissions === true) {
716707
childPermissions = true
717708
} else {
718-
const tabPermissions = parentPermissions?.[tab.name]
719-
if (tabPermissions === true) {
720-
childPermissions = true
721-
} else {
722-
childPermissions = tabPermissions?.fields
723-
}
709+
childPermissions = tabPermissions?.fields
724710
}
725-
} else {
726-
childPermissions = parentPermissions
727711
}
712+
} else {
713+
childPermissions = parentPermissions
714+
}
728715

729-
return iterateFields({
730-
id,
731-
addErrorPathToParent: addErrorPathToParentArg,
732-
anyParentLocalized: tab.localized || anyParentLocalized,
733-
clientFieldSchemaMap,
734-
collectionSlug,
735-
data: isNamedTab ? data?.[tab.name] || {} : data,
736-
fields: tab.fields,
737-
fieldSchemaMap,
738-
filter,
739-
forceFullValue,
740-
fullData,
741-
includeSchema,
742-
omitParents,
743-
operation,
744-
parentIndexPath: isNamedTab ? '' : tabIndexPath,
745-
parentPassesCondition: passesCondition,
746-
parentPath: isNamedTab ? tabPath : parentPath,
747-
parentSchemaPath: isNamedTab ? tabSchemaPath : parentSchemaPath,
748-
permissions: childPermissions,
749-
preferences,
750-
previousFormState,
751-
renderAllFields,
752-
renderFieldFn,
753-
req,
754-
skipConditionChecks,
755-
skipValidation,
756-
state,
757-
})
716+
return iterateFields({
717+
id,
718+
addErrorPathToParent: addErrorPathToParentArg,
719+
anyParentLocalized: fieldIsLocalized(field) || anyParentLocalized,
720+
clientFieldSchemaMap,
721+
collectionSlug,
722+
data: isNamedTab ? data?.[field.name] || {} : data,
723+
fields: field.fields,
724+
fieldSchemaMap,
725+
filter,
726+
forceFullValue,
727+
fullData,
728+
includeSchema,
729+
omitParents,
730+
operation,
731+
parentIndexPath: isNamedTab ? '' : indexPath,
732+
parentPassesCondition: passesCondition,
733+
parentPath: isNamedTab ? path : parentPath,
734+
parentSchemaPath: schemaPath,
735+
permissions: childPermissions,
736+
preferences,
737+
previousFormState,
738+
renderAllFields,
739+
renderFieldFn,
740+
req,
741+
skipConditionChecks,
742+
skipValidation,
743+
state,
744+
})
745+
} else if (field.type === 'tabs') {
746+
return iterateFields({
747+
id,
748+
addErrorPathToParent: addErrorPathToParentArg,
749+
anyParentLocalized: fieldIsLocalized(field) || anyParentLocalized,
750+
clientFieldSchemaMap,
751+
collectionSlug,
752+
data,
753+
fields: field.tabs.map((tab) => ({ ...tab, type: 'tab' })),
754+
fieldSchemaMap,
755+
filter,
756+
forceFullValue,
757+
fullData,
758+
includeSchema,
759+
omitParents,
760+
operation,
761+
parentIndexPath: indexPath,
762+
parentPassesCondition: passesCondition,
763+
parentPath: path,
764+
parentSchemaPath: schemaPath,
765+
permissions: parentPermissions,
766+
preferences,
767+
previousFormState,
768+
renderAllFields,
769+
renderFieldFn,
770+
req,
771+
skipConditionChecks,
772+
skipValidation,
773+
state,
758774
})
759-
760-
await Promise.all(promises)
761775
} else if (field.type === 'ui') {
762776
if (!filter || filter(args)) {
763777
state[path] = fieldState

packages/ui/src/forms/fieldSchemasToFormState/iterateFields.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ import type {
22
ClientFieldSchemaMap,
33
Data,
44
DocumentPreferences,
5-
Field as FieldSchema,
5+
Field,
66
FieldSchemaMap,
77
FormState,
88
FormStateWithoutComponents,
99
PayloadRequest,
1010
SanitizedFieldsPermissions,
11+
TabAsField,
1112
} from 'payload'
1213

1314
import { getFieldPaths } from 'payload/shared'
@@ -26,7 +27,7 @@ type Args = {
2627
clientFieldSchemaMap?: ClientFieldSchemaMap
2728
collectionSlug?: string
2829
data: Data
29-
fields: FieldSchema[]
30+
fields: (Field | TabAsField)[]
3031
fieldSchemaMap: FieldSchemaMap
3132
filter?: (args: AddFieldStatePromiseArgs) => boolean
3233
/**
@@ -108,7 +109,7 @@ export const iterateFields = async ({
108109
const { indexPath, path, schemaPath } = getFieldPaths({
109110
field,
110111
index: fieldIndex,
111-
parentIndexPath: 'name' in field ? '' : parentIndexPath,
112+
parentIndexPath,
112113
parentPath,
113114
parentSchemaPath,
114115
})

packages/ui/src/utilities/buildClientFieldSchemaMap/traverseFields.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ export const traverseFields = ({
4848

4949
switch (field.type) {
5050
case 'array':
51-
case 'group':
51+
case 'group': {
5252
traverseFields({
5353
clientSchemaMap,
5454
config,
@@ -62,8 +62,9 @@ export const traverseFields = ({
6262
})
6363

6464
break
65+
}
6566

66-
case 'blocks':
67+
case 'blocks': {
6768
field.blocks.map((block) => {
6869
const blockSchemaPath = `${schemaPath}.${block.slug}`
6970

@@ -82,8 +83,10 @@ export const traverseFields = ({
8283
})
8384

8485
break
86+
}
87+
8588
case 'collapsible':
86-
case 'row':
89+
case 'row': {
8790
traverseFields({
8891
clientSchemaMap,
8992
config,
@@ -96,6 +99,7 @@ export const traverseFields = ({
9699
schemaMap,
97100
})
98101
break
102+
}
99103

100104
case 'richText': {
101105
// richText sub-fields are not part of the ClientConfig or the Config.

0 commit comments

Comments
 (0)