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({
|
const { indexPath, path, schemaPath } = getFieldPathsModified({
|
||||||
field,
|
field,
|
||||||
index: fieldIndex,
|
index: fieldIndex,
|
||||||
parentIndexPath: 'name' in field ? '' : parentIndexPath,
|
parentIndexPath,
|
||||||
parentPath,
|
parentPath,
|
||||||
parentSchemaPath,
|
parentSchemaPath,
|
||||||
})
|
})
|
||||||
@@ -253,15 +253,14 @@ const buildVersionField = ({
|
|||||||
tabIndex++
|
tabIndex++
|
||||||
const isNamedTab = tabHasName(tab)
|
const isNamedTab = tabHasName(tab)
|
||||||
|
|
||||||
|
const tabAsField = { ...tab, type: 'tab' }
|
||||||
|
|
||||||
const {
|
const {
|
||||||
indexPath: tabIndexPath,
|
indexPath: tabIndexPath,
|
||||||
path: tabPath,
|
path: tabPath,
|
||||||
schemaPath: tabSchemaPath,
|
schemaPath: tabSchemaPath,
|
||||||
} = getFieldPathsModified({
|
} = getFieldPathsModified({
|
||||||
field: {
|
field: tabAsField,
|
||||||
...tab,
|
|
||||||
type: 'tab',
|
|
||||||
},
|
|
||||||
index: tabIndex,
|
index: tabIndex,
|
||||||
parentIndexPath: indexPath,
|
parentIndexPath: indexPath,
|
||||||
parentPath,
|
parentPath,
|
||||||
@@ -280,8 +279,8 @@ const buildVersionField = ({
|
|||||||
modifiedOnly,
|
modifiedOnly,
|
||||||
parentIndexPath: isNamedTab ? '' : tabIndexPath,
|
parentIndexPath: isNamedTab ? '' : tabIndexPath,
|
||||||
parentIsLocalized: parentIsLocalized || tab.localized,
|
parentIsLocalized: parentIsLocalized || tab.localized,
|
||||||
parentPath: tabPath,
|
parentPath: isNamedTab ? tabPath : path,
|
||||||
parentSchemaPath: tabSchemaPath,
|
parentSchemaPath: isNamedTab ? tabSchemaPath : parentSchemaPath,
|
||||||
req,
|
req,
|
||||||
selectedLocales,
|
selectedLocales,
|
||||||
versionSiblingData: 'name' in tab ? versionValue?.[tab.name] : versionValue,
|
versionSiblingData: 'name' in tab ? versionValue?.[tab.name] : versionValue,
|
||||||
@@ -289,7 +288,7 @@ const buildVersionField = ({
|
|||||||
label: tab.label,
|
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) {
|
else if ('fields' in field) {
|
||||||
if (field.type === 'array' && versionValue) {
|
if (field.type === 'array' && versionValue) {
|
||||||
const arrayValue = Array.isArray(versionValue) ? versionValue : []
|
const arrayValue = Array.isArray(versionValue) ? versionValue : []
|
||||||
@@ -328,8 +327,8 @@ const buildVersionField = ({
|
|||||||
modifiedOnly,
|
modifiedOnly,
|
||||||
parentIndexPath: 'name' in field ? '' : indexPath,
|
parentIndexPath: 'name' in field ? '' : indexPath,
|
||||||
parentIsLocalized: parentIsLocalized || ('localized' in field && field.localized),
|
parentIsLocalized: parentIsLocalized || ('localized' in field && field.localized),
|
||||||
parentPath: path,
|
parentPath: 'name' in field ? path : parentPath,
|
||||||
parentSchemaPath: schemaPath,
|
parentSchemaPath: 'name' in field ? schemaPath : parentSchemaPath,
|
||||||
req,
|
req,
|
||||||
selectedLocales,
|
selectedLocales,
|
||||||
versionSiblingData: versionValue as object,
|
versionSiblingData: versionValue as object,
|
||||||
|
|||||||
@@ -42,19 +42,11 @@ export function getFieldPathsModified({
|
|||||||
|
|
||||||
const parentPathToUse = parentIsUnnamed ? parentWithoutIndex : parentPath
|
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) {
|
if ('name' in field) {
|
||||||
return {
|
return {
|
||||||
indexPath: '',
|
indexPath: '',
|
||||||
path: `${parentPathToUse ? parentPathToUse + '.' : ''}${field.name}`,
|
path: `${parentPathToUse ? parentPathToUse + '.' : ''}${field.name}`,
|
||||||
schemaPath: `${parentSchemaPathToUse ? parentSchemaPathToUse + '.' : ''}${field.name}`,
|
schemaPath: `${parentSchemaPath ? parentSchemaPath + '.' : ''}${field.name}`,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,6 +55,6 @@ export function getFieldPathsModified({
|
|||||||
return {
|
return {
|
||||||
indexPath: `${parentIndexPath ? parentIndexPath + '-' : ''}${index}`,
|
indexPath: `${parentIndexPath ? parentIndexPath + '-' : ''}${index}`,
|
||||||
path: `${parentPathToUse ? parentPathToUse + '.' : ''}${indexSuffix}`,
|
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')
|
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 () => {
|
test('correctly renders diff for checkbox fields', async () => {
|
||||||
await navigateToVersionFieldsDiff()
|
await navigateToVersionFieldsDiff()
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ export type SupportedTimezones =
|
|||||||
| 'Asia/Singapore'
|
| 'Asia/Singapore'
|
||||||
| 'Asia/Tokyo'
|
| 'Asia/Tokyo'
|
||||||
| 'Asia/Seoul'
|
| 'Asia/Seoul'
|
||||||
|
| 'Australia/Brisbane'
|
||||||
| 'Australia/Sydney'
|
| 'Australia/Sydney'
|
||||||
| 'Pacific/Guam'
|
| 'Pacific/Guam'
|
||||||
| 'Pacific/Noumea'
|
| 'Pacific/Noumea'
|
||||||
@@ -312,12 +313,30 @@ export interface Diff {
|
|||||||
}[]
|
}[]
|
||||||
| null;
|
| null;
|
||||||
blocks?:
|
blocks?:
|
||||||
|
| (
|
||||||
| {
|
| {
|
||||||
textInBlock?: string | null;
|
textInBlock?: string | null;
|
||||||
id?: string | null;
|
id?: string | null;
|
||||||
blockName?: string | null;
|
blockName?: string | null;
|
||||||
blockType: 'TextBlock';
|
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;
|
| null;
|
||||||
checkbox?: boolean | null;
|
checkbox?: boolean | null;
|
||||||
code?: string | null;
|
code?: string | null;
|
||||||
@@ -772,6 +791,26 @@ export interface DiffSelect<T extends boolean = true> {
|
|||||||
id?: T;
|
id?: T;
|
||||||
blockName?: 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;
|
checkbox?: T;
|
||||||
code?: T;
|
code?: T;
|
||||||
|
|||||||
@@ -138,6 +138,18 @@ export async function seed(_payload: Payload, parallel: boolean = false) {
|
|||||||
blockType: 'TextBlock',
|
blockType: 'TextBlock',
|
||||||
textInBlock: 'textInBlock',
|
textInBlock: 'textInBlock',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
blockType: 'CollapsibleBlock',
|
||||||
|
textInCollapsibleInCollapsibleBlock: 'textInCollapsibleInCollapsibleBlock',
|
||||||
|
textInRowInCollapsibleBlock: 'textInRowInCollapsibleBlock',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blockType: 'TabsBlock',
|
||||||
|
namedTab1InBlock: {
|
||||||
|
textInNamedTab1InBlock: 'textInNamedTab1InBlock',
|
||||||
|
},
|
||||||
|
textInUnnamedTab2InBlock: 'textInUnnamedTab2InBlock',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
checkbox: true,
|
checkbox: true,
|
||||||
code: 'code',
|
code: 'code',
|
||||||
@@ -186,6 +198,18 @@ export async function seed(_payload: Payload, parallel: boolean = false) {
|
|||||||
blockType: 'TextBlock',
|
blockType: 'TextBlock',
|
||||||
textInBlock: 'textInBlock2',
|
textInBlock: 'textInBlock2',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
blockType: 'CollapsibleBlock',
|
||||||
|
textInCollapsibleInCollapsibleBlock: 'textInCollapsibleInCollapsibleBlock2',
|
||||||
|
textInRowInCollapsibleBlock: 'textInRowInCollapsibleBlock2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
blockType: 'TabsBlock',
|
||||||
|
namedTab1InBlock: {
|
||||||
|
textInNamedTab1InBlock: 'textInNamedTab1InBlock2',
|
||||||
|
},
|
||||||
|
textInUnnamedTab2InBlock: 'textInUnnamedTab2InBlock2',
|
||||||
|
},
|
||||||
],
|
],
|
||||||
checkbox: false,
|
checkbox: false,
|
||||||
code: 'code2',
|
code: 'code2',
|
||||||
|
|||||||
Reference in New Issue
Block a user