fix: field inside an unnamed group field erroring when used as a title (#12771)

Fixes https://github.com/payloadcms/payload/issues/12632

Config sanitisation will error without this PR when attempting to
useAsTitle a field inside an unnamed group field.
This commit is contained in:
Paul
2025-06-12 05:57:37 -07:00
committed by GitHub
parent cf43c5cd08
commit 143aff57ae
5 changed files with 36 additions and 5 deletions

View File

@@ -152,7 +152,7 @@ describe('flattenFields', () => {
// Should return the group as a top-level item, not the inner field
expect(withoutExtract).toHaveLength(1)
expect(withoutExtract[0].type).toBe('group')
expect(withoutExtract[0].type).toBe('text')
expect(withoutExtract[0].accessor).toBeUndefined()
expect(withoutExtract[0].labelWithPrefix).toBeUndefined()
})
@@ -635,8 +635,8 @@ describe('flattenFields', () => {
const defaultResult = flattenTopLevelFields(unnamedTabWithUnnamedGroup)
expect(defaultResult).toHaveLength(1)
expect(defaultResult[0].type).toBe('group')
expect(defaultResult[0].label).toBe('Unnamed Group In Tab')
expect(defaultResult[0].type).toBe('text')
expect(defaultResult[0].label).toBe('Nested In Unnamed Group')
expect('accessor' in defaultResult[0]).toBe(false)
expect('labelWithPrefix' in defaultResult[0]).toBe(false)

View File

@@ -84,6 +84,7 @@ export function flattenTopLevelFields<TField extends ClientField | Field>(
} = normalizedOptions
return fields.reduce<FlattenedField<TField>[]>((acc, field) => {
// If a group field has subfields and has a name, otherwise we catch it below along with collapsible and row fields
if (field.type === 'group' && 'fields' in field) {
if (moveSubFieldsToTop) {
const isNamedGroup = 'name' in field && typeof field.name === 'string' && !!field.name
@@ -120,8 +121,12 @@ export function flattenTopLevelFields<TField extends ClientField | Field>(
}),
)
} else {
// Hoisting diabled - keep as top level field
acc.push(field as FlattenedField<TField>)
if (fieldAffectsData(field)) {
// Hoisting diabled - keep as top level field
acc.push(field as FlattenedField<TField>)
} else {
acc.push(...flattenTopLevelFields(field.fields as TField[], options))
}
}
} else if (field.type === 'tabs' && 'tabs' in field) {
return [

View File

@@ -0,0 +1,22 @@
import type { CollectionConfig } from 'payload'
import { useAsTitleGroupFieldSlug } from '../slugs.js'
export const UseAsTitleGroupField: CollectionConfig = {
slug: useAsTitleGroupFieldSlug,
admin: {
useAsTitle: 'name',
},
fields: [
{
type: 'group',
label: 'unnamed group',
fields: [
{
name: 'name',
type: 'text',
},
],
},
],
}

View File

@@ -23,6 +23,7 @@ import { Placeholder } from './collections/Placeholder.js'
import { Posts } from './collections/Posts.js'
import { UploadCollection } from './collections/Upload.js'
import { UploadTwoCollection } from './collections/UploadTwo.js'
import { UseAsTitleGroupField } from './collections/UseAsTitleGroupField.js'
import { Users } from './collections/Users.js'
import { with300Documents } from './collections/With300Documents.js'
import { CustomGlobalViews1 } from './globals/CustomViews1.js'
@@ -174,6 +175,7 @@ export default buildConfigWithDefaults({
with300Documents,
ListDrawer,
Placeholder,
UseAsTitleGroupField,
],
globals: [
GlobalHidden,

View File

@@ -8,6 +8,8 @@ export const group1Collection1Slug = 'group-one-collection-ones'
export const group1Collection2Slug = 'group-one-collection-twos'
export const group2Collection1Slug = 'group-two-collection-ones'
export const group2Collection2Slug = 'group-two-collection-twos'
export const useAsTitleGroupFieldSlug = 'use-as-title-group-field'
export const hiddenCollectionSlug = 'hidden-collection'
export const notInViewCollectionSlug = 'not-in-view-collection'
export const noApiViewCollectionSlug = 'collection-no-api-view'