Skip to content

Commit 3c4b3ee

Browse files
authored
fix(next): version view breaking for deeply nested tabs, rows and collapsibles (#11808)
Fixes #11458 Some complex, nested fields were receiving incorrect field paths and schema paths, leading to a `"Error: No client field found"` error. This PR ensures field paths are calculated correctly, by matching it to how they're calculated in payload hooks.
1 parent fb01b40 commit 3c4b3ee

File tree

7 files changed

+194
-26
lines changed

7 files changed

+194
-26
lines changed

packages/next/src/views/Version/RenderFieldsToDiff/buildVersionFields.tsx

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export const buildVersionFields = ({
8484
const { indexPath, path, schemaPath } = getFieldPathsModified({
8585
field,
8686
index: fieldIndex,
87-
parentIndexPath: 'name' in field ? '' : parentIndexPath,
87+
parentIndexPath,
8888
parentPath,
8989
parentSchemaPath,
9090
})
@@ -253,15 +253,14 @@ const buildVersionField = ({
253253
tabIndex++
254254
const isNamedTab = tabHasName(tab)
255255

256+
const tabAsField = { ...tab, type: 'tab' }
257+
256258
const {
257259
indexPath: tabIndexPath,
258260
path: tabPath,
259261
schemaPath: tabSchemaPath,
260262
} = getFieldPathsModified({
261-
field: {
262-
...tab,
263-
type: 'tab',
264-
},
263+
field: tabAsField,
265264
index: tabIndex,
266265
parentIndexPath: indexPath,
267266
parentPath,
@@ -280,16 +279,16 @@ const buildVersionField = ({
280279
modifiedOnly,
281280
parentIndexPath: isNamedTab ? '' : tabIndexPath,
282281
parentIsLocalized: parentIsLocalized || tab.localized,
283-
parentPath: tabPath,
284-
parentSchemaPath: tabSchemaPath,
282+
parentPath: isNamedTab ? tabPath : path,
283+
parentSchemaPath: isNamedTab ? tabSchemaPath : parentSchemaPath,
285284
req,
286285
selectedLocales,
287286
versionSiblingData: 'name' in tab ? versionValue?.[tab.name] : versionValue,
288287
}).versionFields,
289288
label: tab.label,
290289
})
291290
}
292-
} // At this point, we are dealing with a `row`, etc
291+
} // At this point, we are dealing with a `row`, `collapsible`, etc
293292
else if ('fields' in field) {
294293
if (field.type === 'array' && versionValue) {
295294
const arrayValue = Array.isArray(versionValue) ? versionValue : []
@@ -328,8 +327,8 @@ const buildVersionField = ({
328327
modifiedOnly,
329328
parentIndexPath: 'name' in field ? '' : indexPath,
330329
parentIsLocalized: parentIsLocalized || ('localized' in field && field.localized),
331-
parentPath: path,
332-
parentSchemaPath: schemaPath,
330+
parentPath: 'name' in field ? path : parentPath,
331+
parentSchemaPath: 'name' in field ? schemaPath : parentSchemaPath,
333332
req,
334333
selectedLocales,
335334
versionSiblingData: versionValue as object,

packages/next/src/views/Version/RenderFieldsToDiff/utilities/getFieldPathsModified.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,11 @@ export function getFieldPathsModified({
4242

4343
const parentPathToUse = parentIsUnnamed ? parentWithoutIndex : parentPath
4444

45-
const parentSchemaPathSegments = parentSchemaPath.split('.')
46-
const parentSchemaIsUnnamed =
47-
parentSchemaPathSegments[parentSchemaPathSegments.length - 1].startsWith('_index-')
48-
const parentSchemaWithoutIndex = parentSchemaIsUnnamed
49-
? parentSchemaPathSegments.slice(0, -1).join('.')
50-
: parentSchemaPath
51-
const parentSchemaPathToUse = parentSchemaIsUnnamed ? parentSchemaWithoutIndex : parentSchemaPath
52-
5345
if ('name' in field) {
5446
return {
5547
indexPath: '',
5648
path: `${parentPathToUse ? parentPathToUse + '.' : ''}${field.name}`,
57-
schemaPath: `${parentSchemaPathToUse ? parentSchemaPathToUse + '.' : ''}${field.name}`,
49+
schemaPath: `${parentSchemaPath ? parentSchemaPath + '.' : ''}${field.name}`,
5850
}
5951
}
6052

@@ -63,6 +55,6 @@ export function getFieldPathsModified({
6355
return {
6456
indexPath: `${parentIndexPath ? parentIndexPath + '-' : ''}${index}`,
6557
path: `${parentPathToUse ? parentPathToUse + '.' : ''}${indexSuffix}`,
66-
schemaPath: `${!parentIsUnnamed && parentSchemaPathToUse ? parentSchemaPathToUse + '.' : ''}${indexSuffix}`,
58+
schemaPath: `${!parentIsUnnamed && parentSchemaPath ? parentSchemaPath + '.' : ''}${indexSuffix}`,
6759
}
6860
}

packages/payload/src/fields/utilities/getFieldPaths.ts

Whitespace-only changes.

test/versions/collections/Diff.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,64 @@ export const Diff: CollectionConfig = {
3939
},
4040
],
4141
},
42+
{
43+
slug: 'CollapsibleBlock',
44+
fields: [
45+
{
46+
type: 'collapsible',
47+
label: 'Collapsible',
48+
fields: [
49+
{
50+
type: 'collapsible',
51+
label: 'Nested Collapsible',
52+
fields: [
53+
{
54+
name: 'textInCollapsibleInCollapsibleBlock',
55+
type: 'text',
56+
},
57+
],
58+
},
59+
{
60+
type: 'row',
61+
fields: [
62+
{
63+
name: 'textInRowInCollapsibleBlock',
64+
type: 'text',
65+
},
66+
],
67+
},
68+
],
69+
},
70+
],
71+
},
72+
{
73+
slug: 'TabsBlock',
74+
fields: [
75+
{
76+
type: 'tabs',
77+
tabs: [
78+
{
79+
name: 'namedTab1InBlock',
80+
fields: [
81+
{
82+
name: 'textInNamedTab1InBlock',
83+
type: 'text',
84+
},
85+
],
86+
},
87+
{
88+
label: 'Unnamed Tab 2 In Block',
89+
fields: [
90+
{
91+
name: 'textInUnnamedTab2InBlock',
92+
type: 'text',
93+
},
94+
],
95+
},
96+
],
97+
},
98+
],
99+
},
42100
],
43101
},
44102
{

test/versions/e2e.spec.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,62 @@ describe('Versions', () => {
12131213
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(3)).toHaveText('textInBlock2')
12141214
})
12151215

1216+
test('correctly renders diff for collapsibles within block fields', async () => {
1217+
await navigateToVersionFieldsDiff()
1218+
1219+
const textInBlock = page.locator(
1220+
'[data-field-path="blocks.1.textInCollapsibleInCollapsibleBlock"]',
1221+
)
1222+
1223+
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(1)).toHaveText(
1224+
'textInCollapsibleInCollapsibleBlock',
1225+
)
1226+
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(3)).toHaveText(
1227+
'textInCollapsibleInCollapsibleBlock2',
1228+
)
1229+
})
1230+
1231+
test('correctly renders diff for rows within block fields', async () => {
1232+
await navigateToVersionFieldsDiff()
1233+
1234+
const textInBlock = page.locator('[data-field-path="blocks.1.textInRowInCollapsibleBlock"]')
1235+
1236+
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(1)).toHaveText(
1237+
'textInRowInCollapsibleBlock',
1238+
)
1239+
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(3)).toHaveText(
1240+
'textInRowInCollapsibleBlock2',
1241+
)
1242+
})
1243+
1244+
test('correctly renders diff for named tabs within block fields', async () => {
1245+
await navigateToVersionFieldsDiff()
1246+
1247+
const textInBlock = page.locator(
1248+
'[data-field-path="blocks.2.namedTab1InBlock.textInNamedTab1InBlock"]',
1249+
)
1250+
1251+
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(1)).toHaveText(
1252+
'textInNamedTab1InBlock',
1253+
)
1254+
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(3)).toHaveText(
1255+
'textInNamedTab1InBlock2',
1256+
)
1257+
})
1258+
1259+
test('correctly renders diff for unnamed tabs within block fields', async () => {
1260+
await navigateToVersionFieldsDiff()
1261+
1262+
const textInBlock = page.locator('[data-field-path="blocks.2.textInUnnamedTab2InBlock"]')
1263+
1264+
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(1)).toHaveText(
1265+
'textInUnnamedTab2InBlock',
1266+
)
1267+
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(3)).toHaveText(
1268+
'textInUnnamedTab2InBlock2',
1269+
)
1270+
})
1271+
12161272
test('correctly renders diff for checkbox fields', async () => {
12171273
await navigateToVersionFieldsDiff()
12181274

test/versions/payload-types.ts

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ export type SupportedTimezones =
5454
| 'Asia/Singapore'
5555
| 'Asia/Tokyo'
5656
| 'Asia/Seoul'
57+
| 'Australia/Brisbane'
5758
| 'Australia/Sydney'
5859
| 'Pacific/Guam'
5960
| 'Pacific/Noumea'
@@ -312,12 +313,30 @@ export interface Diff {
312313
}[]
313314
| null;
314315
blocks?:
315-
| {
316-
textInBlock?: string | null;
317-
id?: string | null;
318-
blockName?: string | null;
319-
blockType: 'TextBlock';
320-
}[]
316+
| (
317+
| {
318+
textInBlock?: string | null;
319+
id?: string | null;
320+
blockName?: string | null;
321+
blockType: 'TextBlock';
322+
}
323+
| {
324+
textInCollapsibleInCollapsibleBlock?: string | null;
325+
textInRowInCollapsibleBlock?: string | null;
326+
id?: string | null;
327+
blockName?: string | null;
328+
blockType: 'CollapsibleBlock';
329+
}
330+
| {
331+
namedTab1InBlock?: {
332+
textInNamedTab1InBlock?: string | null;
333+
};
334+
textInUnnamedTab2InBlock?: string | null;
335+
id?: string | null;
336+
blockName?: string | null;
337+
blockType: 'TabsBlock';
338+
}
339+
)[]
321340
| null;
322341
checkbox?: boolean | null;
323342
code?: string | null;
@@ -772,6 +791,26 @@ export interface DiffSelect<T extends boolean = true> {
772791
id?: T;
773792
blockName?: T;
774793
};
794+
CollapsibleBlock?:
795+
| T
796+
| {
797+
textInCollapsibleInCollapsibleBlock?: T;
798+
textInRowInCollapsibleBlock?: T;
799+
id?: T;
800+
blockName?: T;
801+
};
802+
TabsBlock?:
803+
| T
804+
| {
805+
namedTab1InBlock?:
806+
| T
807+
| {
808+
textInNamedTab1InBlock?: T;
809+
};
810+
textInUnnamedTab2InBlock?: T;
811+
id?: T;
812+
blockName?: T;
813+
};
775814
};
776815
checkbox?: T;
777816
code?: T;

test/versions/seed.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,18 @@ export async function seed(_payload: Payload, parallel: boolean = false) {
138138
blockType: 'TextBlock',
139139
textInBlock: 'textInBlock',
140140
},
141+
{
142+
blockType: 'CollapsibleBlock',
143+
textInCollapsibleInCollapsibleBlock: 'textInCollapsibleInCollapsibleBlock',
144+
textInRowInCollapsibleBlock: 'textInRowInCollapsibleBlock',
145+
},
146+
{
147+
blockType: 'TabsBlock',
148+
namedTab1InBlock: {
149+
textInNamedTab1InBlock: 'textInNamedTab1InBlock',
150+
},
151+
textInUnnamedTab2InBlock: 'textInUnnamedTab2InBlock',
152+
},
141153
],
142154
checkbox: true,
143155
code: 'code',
@@ -186,6 +198,18 @@ export async function seed(_payload: Payload, parallel: boolean = false) {
186198
blockType: 'TextBlock',
187199
textInBlock: 'textInBlock2',
188200
},
201+
{
202+
blockType: 'CollapsibleBlock',
203+
textInCollapsibleInCollapsibleBlock: 'textInCollapsibleInCollapsibleBlock2',
204+
textInRowInCollapsibleBlock: 'textInRowInCollapsibleBlock2',
205+
},
206+
{
207+
blockType: 'TabsBlock',
208+
namedTab1InBlock: {
209+
textInNamedTab1InBlock: 'textInNamedTab1InBlock2',
210+
},
211+
textInUnnamedTab2InBlock: 'textInUnnamedTab2InBlock2',
212+
},
189213
],
190214
checkbox: false,
191215
code: 'code2',

0 commit comments

Comments
 (0)