fix: #1775 - siblingData for unnamed fields within array rows improperly formatted
This commit is contained in:
17
src/admin/components/forms/Form/createNestedFieldPath.ts
Normal file
17
src/admin/components/forms/Form/createNestedFieldPath.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Field, fieldAffectsData } from '../../../../fields/config/types';
|
||||
|
||||
export const createNestedFieldPath = (parentPath: string, field: Field): string => {
|
||||
if (parentPath) {
|
||||
if (fieldAffectsData(field)) {
|
||||
return `${parentPath}.${field.name}`;
|
||||
}
|
||||
|
||||
return parentPath;
|
||||
}
|
||||
|
||||
if (fieldAffectsData(field)) {
|
||||
return field.name;
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
@@ -8,9 +8,25 @@ const getSiblingData = (fields: Fields, path: string): Data => {
|
||||
}
|
||||
const siblingFields = {};
|
||||
|
||||
// If this field is nested
|
||||
// We can provide a list of sibling fields
|
||||
const parentFieldPath = path.substring(0, path.lastIndexOf('.') + 1);
|
||||
// Determine if the last segment of the path is an array-based row
|
||||
const pathSegments = path.split('.');
|
||||
const lastSegment = pathSegments[pathSegments.length - 1];
|
||||
const lastSegmentIsRowIndex = !Number.isNaN(Number(lastSegment));
|
||||
|
||||
let parentFieldPath: string;
|
||||
|
||||
if (lastSegmentIsRowIndex) {
|
||||
// If the last segment is a row index,
|
||||
// the sibling data is that row's contents
|
||||
// so create a parent field path that will
|
||||
// retrieve all contents of that row index only
|
||||
parentFieldPath = `${path}.`;
|
||||
} else {
|
||||
// Otherwise, the last path segment is a field name
|
||||
// and it should be removed
|
||||
parentFieldPath = path.substring(0, path.lastIndexOf('.') + 1);
|
||||
}
|
||||
|
||||
Object.keys(fields).forEach((fieldKey) => {
|
||||
if (!fields[fieldKey].disableFormData && fieldKey.indexOf(parentFieldPath) === 0) {
|
||||
siblingFields[fieldKey.replace(parentFieldPath, '')] = fields[fieldKey].value;
|
||||
|
||||
@@ -17,16 +17,16 @@ import { useDocumentInfo } from '../../../utilities/DocumentInfo';
|
||||
import { useOperation } from '../../../utilities/OperationProvider';
|
||||
import { Collapsible } from '../../../elements/Collapsible';
|
||||
import RenderFields from '../../RenderFields';
|
||||
import { fieldAffectsData } from '../../../../../fields/config/types';
|
||||
import { Props } from './types';
|
||||
import { usePreferences } from '../../../utilities/Preferences';
|
||||
import { ArrayAction } from '../../../elements/ArrayAction';
|
||||
import { scrollToID } from '../../../../utilities/scrollToID';
|
||||
import HiddenInput from '../HiddenInput';
|
||||
import { RowLabel } from '../../RowLabel';
|
||||
import { getTranslation } from '../../../../../utilities/getTranslation';
|
||||
import { createNestedFieldPath } from '../../Form/createNestedFieldPath';
|
||||
|
||||
import './index.scss';
|
||||
import { getTranslation } from '../../../../../utilities/getTranslation';
|
||||
|
||||
const baseClass = 'array-field';
|
||||
|
||||
@@ -312,7 +312,7 @@ const ArrayFieldType: React.FC<Props> = (props) => {
|
||||
indexPath={indexPath}
|
||||
fieldSchema={fields.map((field) => ({
|
||||
...field,
|
||||
path: `${path}.${i}${fieldAffectsData(field) ? `.${field.name}` : ''}`,
|
||||
path: createNestedFieldPath(`${path}.${i}`, field),
|
||||
}))}
|
||||
/>
|
||||
|
||||
@@ -326,10 +326,7 @@ const ArrayFieldType: React.FC<Props> = (props) => {
|
||||
<Banner type="error">
|
||||
{t('validation:requiresAtLeast', {
|
||||
count: minRows,
|
||||
label: getTranslation(minRows
|
||||
? labels.plural
|
||||
: labels.singular,
|
||||
i18n) || t(minRows > 1 ? 'general:row' : 'general:rows'),
|
||||
label: getTranslation(minRows ? labels.plural : labels.singular, i18n) || t(minRows > 1 ? 'general:row' : 'general:rows'),
|
||||
})}
|
||||
</Banner>
|
||||
)}
|
||||
|
||||
@@ -23,12 +23,12 @@ import { useOperation } from '../../../utilities/OperationProvider';
|
||||
import { Collapsible } from '../../../elements/Collapsible';
|
||||
import { ArrayAction } from '../../../elements/ArrayAction';
|
||||
import RenderFields from '../../RenderFields';
|
||||
import { fieldAffectsData } from '../../../../../fields/config/types';
|
||||
import SectionTitle from './SectionTitle';
|
||||
import Pill from '../../../elements/Pill';
|
||||
import { scrollToID } from '../../../../utilities/scrollToID';
|
||||
import HiddenInput from '../HiddenInput';
|
||||
import { getTranslation } from '../../../../../utilities/getTranslation';
|
||||
import { createNestedFieldPath } from '../../Form/createNestedFieldPath';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
@@ -345,7 +345,7 @@ const BlocksField: React.FC<Props> = (props) => {
|
||||
permissions={permissions?.fields}
|
||||
fieldSchema={blockToRender.fields.map((field) => ({
|
||||
...field,
|
||||
path: `${path}.${i}${fieldAffectsData(field) ? `.${field.name}` : ''}`,
|
||||
path: createNestedFieldPath(`${path}.${i}`, field),
|
||||
}))}
|
||||
indexPath={indexPath}
|
||||
/>
|
||||
|
||||
@@ -7,8 +7,8 @@ import { usePreferences } from '../../../utilities/Preferences';
|
||||
import { DocumentPreferences } from '../../../../../preferences/types';
|
||||
import { useDocumentInfo } from '../../../utilities/DocumentInfo';
|
||||
import FieldDescription from '../../FieldDescription';
|
||||
import { getFieldPath } from '../getFieldPath';
|
||||
import { RowLabel } from '../../RowLabel';
|
||||
import { createNestedFieldPath } from '../../Form/createNestedFieldPath';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
@@ -101,7 +101,7 @@ const CollapsibleField: React.FC<Props> = (props) => {
|
||||
indexPath={indexPath}
|
||||
fieldSchema={fields.map((field) => ({
|
||||
...field,
|
||||
path: getFieldPath(path, field),
|
||||
path: createNestedFieldPath(path, field),
|
||||
}))}
|
||||
/>
|
||||
</Collapsible>
|
||||
|
||||
@@ -4,11 +4,11 @@ import RenderFields from '../../RenderFields';
|
||||
import withCondition from '../../withCondition';
|
||||
import FieldDescription from '../../FieldDescription';
|
||||
import { Props } from './types';
|
||||
import { fieldAffectsData } from '../../../../../fields/config/types';
|
||||
import { useCollapsible } from '../../../elements/Collapsible/provider';
|
||||
import { GroupProvider, useGroup } from './provider';
|
||||
import { useTabs } from '../Tabs/provider';
|
||||
import { getTranslation } from '../../../../../utilities/getTranslation';
|
||||
import { createNestedFieldPath } from '../../Form/createNestedFieldPath';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
@@ -60,16 +60,16 @@ const Group: React.FC<Props> = (props) => {
|
||||
<GroupProvider>
|
||||
<div className={`${baseClass}__wrap`}>
|
||||
{(label || description) && (
|
||||
<header className={`${baseClass}__header`}>
|
||||
{label && (
|
||||
<h3 className={`${baseClass}__title`}>{getTranslation(label, i18n)}</h3>
|
||||
)}
|
||||
<FieldDescription
|
||||
className={`field-description-${path.replace(/\./gi, '__')}`}
|
||||
value={null}
|
||||
description={description}
|
||||
/>
|
||||
</header>
|
||||
<header className={`${baseClass}__header`}>
|
||||
{label && (
|
||||
<h3 className={`${baseClass}__title`}>{getTranslation(label, i18n)}</h3>
|
||||
)}
|
||||
<FieldDescription
|
||||
className={`field-description-${path.replace(/\./gi, '__')}`}
|
||||
value={null}
|
||||
description={description}
|
||||
/>
|
||||
</header>
|
||||
)}
|
||||
<RenderFields
|
||||
permissions={permissions?.fields}
|
||||
@@ -78,7 +78,7 @@ const Group: React.FC<Props> = (props) => {
|
||||
indexPath={indexPath}
|
||||
fieldSchema={fields.map((subField) => ({
|
||||
...subField,
|
||||
path: `${path}${fieldAffectsData(subField) ? `.${subField.name}` : ''}`,
|
||||
path: createNestedFieldPath(path, subField),
|
||||
}))}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import RenderFields from '../../RenderFields';
|
||||
import withCondition from '../../withCondition';
|
||||
import { Props } from './types';
|
||||
import { getFieldPath } from '../getFieldPath';
|
||||
import { createNestedFieldPath } from '../../Form/createNestedFieldPath';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
@@ -34,7 +34,7 @@ const Row: React.FC<Props> = (props) => {
|
||||
indexPath={indexPath}
|
||||
fieldSchema={fields.map((field) => ({
|
||||
...field,
|
||||
path: getFieldPath(path, field),
|
||||
path: createNestedFieldPath(path, field),
|
||||
}))}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import RenderFields from '../../RenderFields';
|
||||
import withCondition from '../../withCondition';
|
||||
import { Props } from './types';
|
||||
import { fieldAffectsData, tabHasName } from '../../../../../fields/config/types';
|
||||
import { tabHasName } from '../../../../../fields/config/types';
|
||||
import FieldDescription from '../../FieldDescription';
|
||||
import toKebabCase from '../../../../../utilities/toKebabCase';
|
||||
import { useCollapsible } from '../../../elements/Collapsible/provider';
|
||||
@@ -12,6 +12,7 @@ import { getTranslation } from '../../../../../utilities/getTranslation';
|
||||
import { usePreferences } from '../../../utilities/Preferences';
|
||||
import { DocumentPreferences } from '../../../../../preferences/types';
|
||||
import { useDocumentInfo } from '../../../utilities/DocumentInfo';
|
||||
import { createNestedFieldPath } from '../../Form/createNestedFieldPath';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
@@ -123,10 +124,17 @@ const TabsField: React.FC<Props> = (props) => {
|
||||
readOnly={readOnly}
|
||||
permissions={tabHasName(activeTabConfig) ? permissions[activeTabConfig.name].fields : permissions}
|
||||
fieldTypes={fieldTypes}
|
||||
fieldSchema={activeTabConfig.fields.map((field) => ({
|
||||
...field,
|
||||
path: `${path ? `${path}.` : ''}${tabHasName(activeTabConfig) ? `${activeTabConfig.name}.` : ''}${fieldAffectsData(field) ? field.name : ''}`,
|
||||
}))}
|
||||
fieldSchema={activeTabConfig.fields.map((field) => {
|
||||
const pathSegments = [];
|
||||
|
||||
if (path) pathSegments.push(path);
|
||||
if (tabHasName(activeTabConfig)) pathSegments.push(activeTabConfig.name);
|
||||
|
||||
return {
|
||||
...field,
|
||||
path: createNestedFieldPath(pathSegments.join('.'), field),
|
||||
};
|
||||
})}
|
||||
indexPath={indexPath}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import { Field, fieldAffectsData } from '../../../../fields/config/types';
|
||||
|
||||
export const getFieldPath = (path: string, field: Field): string => {
|
||||
// prevents duplicate . on nesting non-named fields
|
||||
const dot = path && path.slice(-1) === '.' ? '' : '.';
|
||||
return `${path ? `${path}${dot}` : ''}${fieldAffectsData(field) ? field.name : ''}`;
|
||||
};
|
||||
Reference in New Issue
Block a user