fix: localized tabs with empty data and an array field inside lead to crash in afterChange (#10410)
Previously, this config:
```ts
import type { CollectionConfig } from 'payload'
export const tabSlug = 'tabs'
export const Tab: CollectionConfig = {
slug: tabSlug,
fields: [
{
type: 'tabs',
tabs: [
{
name: 'tabLocalized',
localized: true,
fields: [
{
name: 'title',
type: 'text',
},
{
name: 'array',
type: 'array',
fields: [
{
name: 'title',
type: 'text',
},
],
},
],
},
],
},
],
}
```
This call
```ts
const result = await payload.create({
collection: tabSlug,
locale: englishLocale,
data: {
tabLocalized: {},
},
})
```
Led to the following crash with the MongoDB adapter
<img width="741" alt="image"
src="https://github.com/user-attachments/assets/8d1d37de-a685-4a30-bd37-58af164108a2"
/>
This is due to how Mongoose, apparently just ignores the `minimize:
false` configuration
a83a430a3a/packages/db-mongodb/src/models/buildSchema.ts (L571)
and we, instead of `tabLocalized: { en: { } }` receive just
`tabLocalized: {}`.
This isn't an issue with group fields because we have fallback for them
a83a430a3a/packages/payload/src/fields/hooks/afterChange/promise.ts (L203)
This PR adds the same for tabs.
This commit is contained in:
@@ -165,7 +165,6 @@ export const promise = async ({
|
||||
}
|
||||
|
||||
case 'collapsible':
|
||||
|
||||
case 'row': {
|
||||
await traverseFields({
|
||||
collection,
|
||||
@@ -253,9 +252,9 @@ export const promise = async ({
|
||||
let tabPreviousSiblingDoc = siblingDoc
|
||||
|
||||
if (tabHasName(field)) {
|
||||
tabSiblingData = siblingData[field.name] as JsonObject
|
||||
tabSiblingDoc = siblingDoc[field.name] as JsonObject
|
||||
tabPreviousSiblingDoc = previousDoc[field.name] as JsonObject
|
||||
tabSiblingData = (siblingData[field.name] as JsonObject) ?? {}
|
||||
tabSiblingDoc = (siblingDoc[field.name] as JsonObject) ?? {}
|
||||
tabPreviousSiblingDoc = (previousDoc[field.name] as JsonObject) ?? {}
|
||||
}
|
||||
|
||||
await traverseFields({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
import type { CollectionConfig } from 'payload'
|
||||
|
||||
export const tabSlug = 'tabs'
|
||||
|
||||
@@ -16,6 +16,16 @@ export const Tab: CollectionConfig = {
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'array',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1646,7 +1646,19 @@ describe('Localization', () => {
|
||||
expect(all.groupLocalizedRow.es.text).toBe('hola world or something')
|
||||
})
|
||||
|
||||
it('should properly create/update/read localized tab field', async () => {
|
||||
it('should not crash on empty localized tab', async () => {
|
||||
const result = await payload.create({
|
||||
collection: tabSlug,
|
||||
locale: englishLocale,
|
||||
data: {
|
||||
tabLocalized: {},
|
||||
},
|
||||
})
|
||||
|
||||
expect(result).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should properly create/update/read array field inside localized tab field', async () => {
|
||||
const result = await payload.create({
|
||||
collection: tabSlug,
|
||||
locale: englishLocale,
|
||||
@@ -1686,6 +1698,50 @@ describe('Localization', () => {
|
||||
expect(docEs.tabLocalized.title).toBe('hello es')
|
||||
})
|
||||
|
||||
it('should properly create/update/read localized tab field', async () => {
|
||||
const result = await payload.create({
|
||||
collection: tabSlug,
|
||||
locale: englishLocale,
|
||||
data: {
|
||||
tabLocalized: {
|
||||
array: [
|
||||
{
|
||||
title: 'hello en',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(result.tabLocalized.array[0].title).toBe('hello en')
|
||||
|
||||
await payload.update({
|
||||
collection: tabSlug,
|
||||
locale: spanishLocale,
|
||||
id: result.id,
|
||||
data: {
|
||||
tabLocalized: {
|
||||
array: [{ title: 'hello es' }],
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const docEn = await payload.findByID({
|
||||
collection: tabSlug,
|
||||
locale: englishLocale,
|
||||
id: result.id,
|
||||
})
|
||||
|
||||
const docEs = await payload.findByID({
|
||||
collection: tabSlug,
|
||||
locale: spanishLocale,
|
||||
id: result.id,
|
||||
})
|
||||
|
||||
expect(docEn.tabLocalized.array[0].title).toBe('hello en')
|
||||
expect(docEs.tabLocalized.array[0].title).toBe('hello es')
|
||||
})
|
||||
|
||||
it('should properly create/update/read localized field inside of tab', async () => {
|
||||
const result = await payload.create({
|
||||
collection: tabSlug,
|
||||
|
||||
@@ -522,6 +522,12 @@ export interface Tab {
|
||||
id: string;
|
||||
tabLocalized?: {
|
||||
title?: string | null;
|
||||
array?:
|
||||
| {
|
||||
title?: string | null;
|
||||
id?: string | null;
|
||||
}[]
|
||||
| null;
|
||||
};
|
||||
tab?: {
|
||||
title?: string | null;
|
||||
@@ -1119,6 +1125,12 @@ export interface TabsSelect<T extends boolean = true> {
|
||||
| T
|
||||
| {
|
||||
title?: T;
|
||||
array?:
|
||||
| T
|
||||
| {
|
||||
title?: T;
|
||||
id?: T;
|
||||
};
|
||||
};
|
||||
tab?:
|
||||
| T
|
||||
|
||||
Reference in New Issue
Block a user