fix(db-postgres): localized groups/tabs and nested fields (#6158)

---------

Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
This commit is contained in:
Ritsu
2024-07-24 20:57:10 +03:00
committed by GitHub
parent 09ad6e4280
commit 51f1c8e7e8
5 changed files with 440 additions and 48 deletions

View File

@@ -1,6 +1,5 @@
/* eslint-disable no-param-reassign */
import type { Field, TabAsField } from 'payload'
import type { SanitizedConfig } from 'payload'
import type { Field, SanitizedConfig , TabAsField } from 'payload'
import { fieldAffectsData } from 'payload/shared'
@@ -430,7 +429,12 @@ export const traverseFields = <T extends Record<string, unknown>>({
if (field.localized && Array.isArray(table._locales)) {
table._locales.forEach((localeRow) => {
valuesToTransform.push({ ref: localizedFieldData, table: localeRow })
valuesToTransform.push({
ref: localizedFieldData,
table: {
...localeRow,
},
})
})
} else {
valuesToTransform.push({ ref: result, table })
@@ -445,52 +449,28 @@ export const traverseFields = <T extends Record<string, unknown>>({
case 'tab':
case 'group': {
const groupFieldPrefix = `${fieldPrefix || ''}${field.name}_`
const groupData = {}
const locale = table._locale as string
const refKey = field.localized && locale ? locale : field.name
if (field.localized) {
if (typeof locale === 'string' && !ref[locale]) {
ref[locale] = {}
delete table._locale
}
if (field.localized && locale) delete table._locale
ref[refKey] = traverseFields<Record<string, unknown>>({
adapter,
blocks,
config,
dataRef: groupData as Record<string, unknown>,
deletions,
fieldPrefix: groupFieldPrefix,
fields: field.fields,
numbers,
path: `${sanitizedPath}${field.name}`,
relationships,
table,
texts,
})
Object.entries(ref).forEach(([groupLocale, groupLocaleData]) => {
ref[groupLocale] = traverseFields<Record<string, unknown>>({
adapter,
blocks,
config,
dataRef: groupLocaleData as Record<string, unknown>,
deletions,
fieldPrefix: groupFieldPrefix,
fields: field.fields,
numbers,
path: `${sanitizedPath}${field.name}`,
relationships,
table,
texts,
})
})
if ('_order' in ref) {
delete ref._order
}
} else {
const groupData = {}
ref[field.name] = traverseFields<Record<string, unknown>>({
adapter,
blocks,
config,
dataRef: groupData as Record<string, unknown>,
deletions,
fieldPrefix: groupFieldPrefix,
fields: field.fields,
numbers,
path: `${sanitizedPath}${field.name}`,
relationships,
table,
texts,
})
if ('_order' in ref) {
delete ref._order
}
if ('_order' in ref) {
delete ref._order
}
return

View File

@@ -0,0 +1,64 @@
import type { CollectionConfig } from 'payload/types'
export const groupSlug = 'groups'
export const Group: CollectionConfig = {
slug: groupSlug,
fields: [
{
name: 'groupLocalized',
type: 'group',
fields: [
{
name: 'title',
type: 'text',
},
],
localized: true,
},
{
name: 'group',
type: 'group',
fields: [
{
name: 'title',
type: 'text',
localized: true,
},
],
},
{
name: 'deep',
type: 'group',
fields: [
{
name: 'array',
type: 'array',
fields: [
{
name: 'title',
type: 'text',
localized: true,
},
],
},
{
name: 'blocks',
type: 'blocks',
blocks: [
{
slug: 'first',
fields: [
{
name: 'title',
type: 'text',
localized: true,
},
],
},
],
},
],
},
],
}

View File

@@ -0,0 +1,66 @@
import type { CollectionConfig } from 'payload/types'
export const tabSlug = 'tabs'
export const Tab: CollectionConfig = {
slug: tabSlug,
fields: [
{
type: 'tabs',
tabs: [
{
name: 'tabLocalized',
localized: true,
fields: [
{
name: 'title',
type: 'text',
},
],
},
{
name: 'tab',
fields: [
{
localized: true,
name: 'title',
type: 'text',
},
],
},
{
name: 'deep',
fields: [
{
name: 'array',
type: 'array',
fields: [
{
localized: true,
type: 'text',
name: 'title',
},
],
},
{
name: 'blocks',
type: 'blocks',
blocks: [
{
slug: 'first',
fields: [
{
localized: true,
type: 'text',
name: 'title',
},
],
},
],
},
],
},
],
},
],
}

View File

@@ -7,7 +7,9 @@ import type { LocalizedPost } from './payload-types.js'
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
import { devUser } from '../credentials.js'
import { ArrayCollection } from './collections/Array/index.js'
import { Group } from './collections/Group/index.js'
import { NestedToArrayAndBlock } from './collections/NestedToArrayAndBlock/index.js'
import { Tab } from './collections/Tab/index.js'
import {
blocksWithLocalizedSameName,
defaultLocale,
@@ -225,6 +227,8 @@ export default buildConfigWithDefaults({
slug: 'dummy',
},
NestedToArrayAndBlock,
Group,
Tab,
{
slug: localizedSortSlug,
access: openAccess,

View File

@@ -7,7 +7,9 @@ import { englishLocale } from '../globals/config.js'
import { idToString } from '../helpers/idToString.js'
import { initPayloadInt } from '../helpers/initPayloadInt.js'
import { arrayCollectionSlug } from './collections/Array/index.js'
import { groupSlug } from './collections/Group/index.js'
import { nestedToArrayAndBlockCollectionSlug } from './collections/NestedToArrayAndBlock/index.js'
import { tabSlug } from './collections/Tab/index.js'
import configPromise from './config.js'
import {
defaultLocale,
@@ -1112,6 +1114,282 @@ describe('Localization', () => {
expect(allLocales.localizedCheckbox.es).toBeFalsy()
})
})
describe('Localized group and tabs', () => {
it('should properly create/update/read localized group field', async () => {
const result = await payload.create({
collection: groupSlug,
data: {
groupLocalized: {
title: 'hello en',
},
},
locale: englishLocale,
})
expect(result.groupLocalized?.title).toBe('hello en')
await payload.update({
collection: groupSlug,
locale: spanishLocale,
id: result.id,
data: {
groupLocalized: {
title: 'hello es',
},
},
})
const docEn = await payload.findByID({
collection: groupSlug,
locale: englishLocale,
id: result.id,
})
const docEs = await payload.findByID({
collection: groupSlug,
locale: spanishLocale,
id: result.id,
})
expect(docEn.groupLocalized.title).toBe('hello en')
expect(docEs.groupLocalized.title).toBe('hello es')
})
it('should properly create/update/read localized field inside of group', async () => {
const result = await payload.create({
collection: groupSlug,
locale: englishLocale,
data: {
group: {
title: 'hello en',
},
},
})
expect(result.group.title).toBe('hello en')
await payload.update({
collection: groupSlug,
locale: spanishLocale,
id: result.id,
data: {
group: {
title: 'hello es',
},
},
})
const docEn = await payload.findByID({
collection: groupSlug,
locale: englishLocale,
id: result.id,
})
const docEs = await payload.findByID({
collection: groupSlug,
locale: spanishLocale,
id: result.id,
})
expect(docEn.group.title).toBe('hello en')
expect(docEs.group.title).toBe('hello es')
})
it('should properly create/update/read deep localized field inside of group', async () => {
const result = await payload.create({
collection: groupSlug,
locale: englishLocale,
data: {
deep: {
blocks: [
{
blockType: 'first',
title: 'hello en',
},
],
array: [{ title: 'hello en' }],
},
},
})
expect(result.deep.array[0].title).toBe('hello en')
await payload.update({
collection: groupSlug,
locale: spanishLocale,
id: result.id,
data: {
deep: {
blocks: [
{
blockType: 'first',
title: 'hello es',
id: result.deep.blocks[0].id,
},
],
array: [
{
id: result.deep.array[0].id,
title: 'hello es',
},
],
},
},
})
const docEn = await payload.findByID({
collection: groupSlug,
locale: englishLocale,
id: result.id,
})
const docEs = await payload.findByID({
collection: groupSlug,
locale: spanishLocale,
id: result.id,
})
expect(docEn.deep.array[0].title).toBe('hello en')
expect(docEn.deep.blocks[0].title).toBe('hello en')
expect(docEs.deep.array[0].title).toBe('hello es')
expect(docEs.deep.blocks[0].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: {
title: 'hello en',
},
},
})
expect(result.tabLocalized?.title).toBe('hello en')
await payload.update({
collection: tabSlug,
locale: spanishLocale,
id: result.id,
data: {
tabLocalized: {
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.title).toBe('hello en')
expect(docEs.tabLocalized.title).toBe('hello es')
})
it('should properly create/update/read localized field inside of tab', async () => {
const result = await payload.create({
collection: tabSlug,
locale: englishLocale,
data: {
tab: {
title: 'hello en',
},
},
})
expect(result.tab.title).toBe('hello en')
await payload.update({
collection: tabSlug,
locale: spanishLocale,
id: result.id,
data: {
tab: {
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.tab.title).toBe('hello en')
expect(docEs.tab.title).toBe('hello es')
})
it('should properly create/update/read deep localized field inside of tab', async () => {
const result = await payload.create({
collection: tabSlug,
locale: englishLocale,
data: {
deep: {
blocks: [
{
blockType: 'first',
title: 'hello en',
},
],
array: [{ title: 'hello en' }],
},
},
})
expect(result.deep.array[0].title).toBe('hello en')
await payload.update({
collection: tabSlug,
locale: spanishLocale,
id: result.id,
data: {
deep: {
blocks: [
{
blockType: 'first',
title: 'hello es',
id: result.deep.blocks[0].id,
},
],
array: [
{
id: result.deep.array[0].id,
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.deep.array[0].title).toBe('hello en')
expect(docEn.deep.blocks[0].title).toBe('hello en')
expect(docEs.deep.array[0].title).toBe('hello es')
expect(docEs.deep.blocks[0].title).toBe('hello es')
})
})
})
async function createLocalizedPost(data: {