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.
This commit is contained in:
@@ -84,7 +84,7 @@ export const buildVersionFields = ({
|
||||
const { indexPath, path, schemaPath } = getFieldPathsModified({
|
||||
field,
|
||||
index: fieldIndex,
|
||||
parentIndexPath: 'name' in field ? '' : parentIndexPath,
|
||||
parentIndexPath,
|
||||
parentPath,
|
||||
parentSchemaPath,
|
||||
})
|
||||
@@ -253,15 +253,14 @@ const buildVersionField = ({
|
||||
tabIndex++
|
||||
const isNamedTab = tabHasName(tab)
|
||||
|
||||
const tabAsField = { ...tab, type: 'tab' }
|
||||
|
||||
const {
|
||||
indexPath: tabIndexPath,
|
||||
path: tabPath,
|
||||
schemaPath: tabSchemaPath,
|
||||
} = getFieldPathsModified({
|
||||
field: {
|
||||
...tab,
|
||||
type: 'tab',
|
||||
},
|
||||
field: tabAsField,
|
||||
index: tabIndex,
|
||||
parentIndexPath: indexPath,
|
||||
parentPath,
|
||||
@@ -280,8 +279,8 @@ const buildVersionField = ({
|
||||
modifiedOnly,
|
||||
parentIndexPath: isNamedTab ? '' : tabIndexPath,
|
||||
parentIsLocalized: parentIsLocalized || tab.localized,
|
||||
parentPath: tabPath,
|
||||
parentSchemaPath: tabSchemaPath,
|
||||
parentPath: isNamedTab ? tabPath : path,
|
||||
parentSchemaPath: isNamedTab ? tabSchemaPath : parentSchemaPath,
|
||||
req,
|
||||
selectedLocales,
|
||||
versionSiblingData: 'name' in tab ? versionValue?.[tab.name] : versionValue,
|
||||
@@ -289,7 +288,7 @@ const buildVersionField = ({
|
||||
label: tab.label,
|
||||
})
|
||||
}
|
||||
} // At this point, we are dealing with a `row`, etc
|
||||
} // At this point, we are dealing with a `row`, `collapsible`, etc
|
||||
else if ('fields' in field) {
|
||||
if (field.type === 'array' && versionValue) {
|
||||
const arrayValue = Array.isArray(versionValue) ? versionValue : []
|
||||
@@ -328,8 +327,8 @@ const buildVersionField = ({
|
||||
modifiedOnly,
|
||||
parentIndexPath: 'name' in field ? '' : indexPath,
|
||||
parentIsLocalized: parentIsLocalized || ('localized' in field && field.localized),
|
||||
parentPath: path,
|
||||
parentSchemaPath: schemaPath,
|
||||
parentPath: 'name' in field ? path : parentPath,
|
||||
parentSchemaPath: 'name' in field ? schemaPath : parentSchemaPath,
|
||||
req,
|
||||
selectedLocales,
|
||||
versionSiblingData: versionValue as object,
|
||||
|
||||
@@ -42,19 +42,11 @@ export function getFieldPathsModified({
|
||||
|
||||
const parentPathToUse = parentIsUnnamed ? parentWithoutIndex : parentPath
|
||||
|
||||
const parentSchemaPathSegments = parentSchemaPath.split('.')
|
||||
const parentSchemaIsUnnamed =
|
||||
parentSchemaPathSegments[parentSchemaPathSegments.length - 1].startsWith('_index-')
|
||||
const parentSchemaWithoutIndex = parentSchemaIsUnnamed
|
||||
? parentSchemaPathSegments.slice(0, -1).join('.')
|
||||
: parentSchemaPath
|
||||
const parentSchemaPathToUse = parentSchemaIsUnnamed ? parentSchemaWithoutIndex : parentSchemaPath
|
||||
|
||||
if ('name' in field) {
|
||||
return {
|
||||
indexPath: '',
|
||||
path: `${parentPathToUse ? parentPathToUse + '.' : ''}${field.name}`,
|
||||
schemaPath: `${parentSchemaPathToUse ? parentSchemaPathToUse + '.' : ''}${field.name}`,
|
||||
schemaPath: `${parentSchemaPath ? parentSchemaPath + '.' : ''}${field.name}`,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +55,6 @@ export function getFieldPathsModified({
|
||||
return {
|
||||
indexPath: `${parentIndexPath ? parentIndexPath + '-' : ''}${index}`,
|
||||
path: `${parentPathToUse ? parentPathToUse + '.' : ''}${indexSuffix}`,
|
||||
schemaPath: `${!parentIsUnnamed && parentSchemaPathToUse ? parentSchemaPathToUse + '.' : ''}${indexSuffix}`,
|
||||
schemaPath: `${!parentIsUnnamed && parentSchemaPath ? parentSchemaPath + '.' : ''}${indexSuffix}`,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,64 @@ export const Diff: CollectionConfig = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'CollapsibleBlock',
|
||||
fields: [
|
||||
{
|
||||
type: 'collapsible',
|
||||
label: 'Collapsible',
|
||||
fields: [
|
||||
{
|
||||
type: 'collapsible',
|
||||
label: 'Nested Collapsible',
|
||||
fields: [
|
||||
{
|
||||
name: 'textInCollapsibleInCollapsibleBlock',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'row',
|
||||
fields: [
|
||||
{
|
||||
name: 'textInRowInCollapsibleBlock',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
slug: 'TabsBlock',
|
||||
fields: [
|
||||
{
|
||||
type: 'tabs',
|
||||
tabs: [
|
||||
{
|
||||
name: 'namedTab1InBlock',
|
||||
fields: [
|
||||
{
|
||||
name: 'textInNamedTab1InBlock',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Unnamed Tab 2 In Block',
|
||||
fields: [
|
||||
{
|
||||
name: 'textInUnnamedTab2InBlock',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1213,6 +1213,62 @@ describe('Versions', () => {
|
||||
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(3)).toHaveText('textInBlock2')
|
||||
})
|
||||
|
||||
test('correctly renders diff for collapsibles within block fields', async () => {
|
||||
await navigateToVersionFieldsDiff()
|
||||
|
||||
const textInBlock = page.locator(
|
||||
'[data-field-path="blocks.1.textInCollapsibleInCollapsibleBlock"]',
|
||||
)
|
||||
|
||||
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(1)).toHaveText(
|
||||
'textInCollapsibleInCollapsibleBlock',
|
||||
)
|
||||
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(3)).toHaveText(
|
||||
'textInCollapsibleInCollapsibleBlock2',
|
||||
)
|
||||
})
|
||||
|
||||
test('correctly renders diff for rows within block fields', async () => {
|
||||
await navigateToVersionFieldsDiff()
|
||||
|
||||
const textInBlock = page.locator('[data-field-path="blocks.1.textInRowInCollapsibleBlock"]')
|
||||
|
||||
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(1)).toHaveText(
|
||||
'textInRowInCollapsibleBlock',
|
||||
)
|
||||
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(3)).toHaveText(
|
||||
'textInRowInCollapsibleBlock2',
|
||||
)
|
||||
})
|
||||
|
||||
test('correctly renders diff for named tabs within block fields', async () => {
|
||||
await navigateToVersionFieldsDiff()
|
||||
|
||||
const textInBlock = page.locator(
|
||||
'[data-field-path="blocks.2.namedTab1InBlock.textInNamedTab1InBlock"]',
|
||||
)
|
||||
|
||||
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(1)).toHaveText(
|
||||
'textInNamedTab1InBlock',
|
||||
)
|
||||
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(3)).toHaveText(
|
||||
'textInNamedTab1InBlock2',
|
||||
)
|
||||
})
|
||||
|
||||
test('correctly renders diff for unnamed tabs within block fields', async () => {
|
||||
await navigateToVersionFieldsDiff()
|
||||
|
||||
const textInBlock = page.locator('[data-field-path="blocks.2.textInUnnamedTab2InBlock"]')
|
||||
|
||||
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(1)).toHaveText(
|
||||
'textInUnnamedTab2InBlock',
|
||||
)
|
||||
await expect(textInBlock.locator('tr').nth(1).locator('td').nth(3)).toHaveText(
|
||||
'textInUnnamedTab2InBlock2',
|
||||
)
|
||||
})
|
||||
|
||||
test('correctly renders diff for checkbox fields', async () => {
|
||||
await navigateToVersionFieldsDiff()
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ export type SupportedTimezones =
|
||||
| 'Asia/Singapore'
|
||||
| 'Asia/Tokyo'
|
||||
| 'Asia/Seoul'
|
||||
| 'Australia/Brisbane'
|
||||
| 'Australia/Sydney'
|
||||
| 'Pacific/Guam'
|
||||
| 'Pacific/Noumea'
|
||||
@@ -312,12 +313,30 @@ export interface Diff {
|
||||
}[]
|
||||
| null;
|
||||
blocks?:
|
||||
| (
|
||||
| {
|
||||
textInBlock?: string | null;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'TextBlock';
|
||||
}[]
|
||||
}
|
||||
| {
|
||||
textInCollapsibleInCollapsibleBlock?: string | null;
|
||||
textInRowInCollapsibleBlock?: string | null;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'CollapsibleBlock';
|
||||
}
|
||||
| {
|
||||
namedTab1InBlock?: {
|
||||
textInNamedTab1InBlock?: string | null;
|
||||
};
|
||||
textInUnnamedTab2InBlock?: string | null;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'TabsBlock';
|
||||
}
|
||||
)[]
|
||||
| null;
|
||||
checkbox?: boolean | null;
|
||||
code?: string | null;
|
||||
@@ -772,6 +791,26 @@ export interface DiffSelect<T extends boolean = true> {
|
||||
id?: T;
|
||||
blockName?: T;
|
||||
};
|
||||
CollapsibleBlock?:
|
||||
| T
|
||||
| {
|
||||
textInCollapsibleInCollapsibleBlock?: T;
|
||||
textInRowInCollapsibleBlock?: T;
|
||||
id?: T;
|
||||
blockName?: T;
|
||||
};
|
||||
TabsBlock?:
|
||||
| T
|
||||
| {
|
||||
namedTab1InBlock?:
|
||||
| T
|
||||
| {
|
||||
textInNamedTab1InBlock?: T;
|
||||
};
|
||||
textInUnnamedTab2InBlock?: T;
|
||||
id?: T;
|
||||
blockName?: T;
|
||||
};
|
||||
};
|
||||
checkbox?: T;
|
||||
code?: T;
|
||||
|
||||
@@ -138,6 +138,18 @@ export async function seed(_payload: Payload, parallel: boolean = false) {
|
||||
blockType: 'TextBlock',
|
||||
textInBlock: 'textInBlock',
|
||||
},
|
||||
{
|
||||
blockType: 'CollapsibleBlock',
|
||||
textInCollapsibleInCollapsibleBlock: 'textInCollapsibleInCollapsibleBlock',
|
||||
textInRowInCollapsibleBlock: 'textInRowInCollapsibleBlock',
|
||||
},
|
||||
{
|
||||
blockType: 'TabsBlock',
|
||||
namedTab1InBlock: {
|
||||
textInNamedTab1InBlock: 'textInNamedTab1InBlock',
|
||||
},
|
||||
textInUnnamedTab2InBlock: 'textInUnnamedTab2InBlock',
|
||||
},
|
||||
],
|
||||
checkbox: true,
|
||||
code: 'code',
|
||||
@@ -186,6 +198,18 @@ export async function seed(_payload: Payload, parallel: boolean = false) {
|
||||
blockType: 'TextBlock',
|
||||
textInBlock: 'textInBlock2',
|
||||
},
|
||||
{
|
||||
blockType: 'CollapsibleBlock',
|
||||
textInCollapsibleInCollapsibleBlock: 'textInCollapsibleInCollapsibleBlock2',
|
||||
textInRowInCollapsibleBlock: 'textInRowInCollapsibleBlock2',
|
||||
},
|
||||
{
|
||||
blockType: 'TabsBlock',
|
||||
namedTab1InBlock: {
|
||||
textInNamedTab1InBlock: 'textInNamedTab1InBlock2',
|
||||
},
|
||||
textInUnnamedTab2InBlock: 'textInUnnamedTab2InBlock2',
|
||||
},
|
||||
],
|
||||
checkbox: false,
|
||||
code: 'code2',
|
||||
|
||||
Reference in New Issue
Block a user