Prevent saving content type when dynamic zone does not have components. (#12123)

* Add min validation for dynamiczone

Signed-off-by: soupette <cyril@strapi.io>

* Add toast when schema is not valid

Signed-off-by: soupette <cyril@strapi.io>

* Fix PR feedback

Signed-off-by: soupette <cyril@strapi.io>
This commit is contained in:
cyril lopez 2022-01-10 11:55:58 +01:00 committed by GitHub
parent 8493f62b55
commit a666e0a4b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 66 additions and 1 deletions

View File

@ -28,6 +28,7 @@ import retrieveComponentsFromSchema from './utils/retrieveComponentsFromSchema';
import retrieveNestedComponents from './utils/retrieveNestedComponents';
import { retrieveComponentsThatHaveComponents } from './utils/retrieveComponentsThatHaveComponents';
import { getComponentsToPost, formatMainDataType, sortContentType } from './utils/cleanData';
import validateSchema from './utils/validateSchema';
import {
ADD_ATTRIBUTE,
@ -440,6 +441,21 @@ const DataManagerProvider = ({
initialData.contentType
);
const isValidSchema = validateSchema(contentType);
if (!isValidSchema) {
toggleNotification({
type: 'warning',
message: {
id: getTrad('notification.error.dynamiczone-min.validation'),
defaultMessage:
'At least one component is required in a dynamic zone to be able to save a content type',
},
});
return;
}
body.contentType = contentType;
trackUsage('willSaveContentType');

View File

@ -0,0 +1,11 @@
const validateSchema = schema => {
const dynamicZoneAttributes = Object.values(schema.attributes).filter(
({ type }) => type === 'dynamiczone'
);
return dynamicZoneAttributes.every(
({ components }) => Array.isArray(components) && components.length > 0
);
};
export default validateSchema;

View File

@ -166,6 +166,7 @@
"modelPage.attribute.relation-polymorphic": "Relation (polymorphic)",
"modelPage.attribute.relationWith": "Relation with",
"none": "None",
"notification.error.dynamiczone-min.validation": "At least one component is required in a dynamic zone to be able to save a content type",
"notification.info.autoreaload-disable": "The autoReload feature is required to use this plugin. Start your server with `strapi develop`",
"notification.info.creating.notSaved": "Please save your work before creating a new collection type or component",
"plugin.description.long": "Modelize the data structure of your API. Create new fields and relations in just a minute. The files are automatically created and updated in your project.",

View File

@ -43,6 +43,42 @@ describe('Type validators', () => {
});
});
describe('Dynamiczone type validator', () => {
test('Components cannot be empty', () => {
const attributes = {
dz: {
type: 'dynamiczone',
components: [],
},
};
const validator = getTypeValidator(attributes.dz, {
types: ['dynamiczone'],
modelType: 'collectionType',
attributes,
});
expect(validator.isValidSync(attributes.dz)).toBeFalsy();
});
test('Components must have at least one item', () => {
const attributes = {
dz: {
type: 'dynamiczone',
components: ['compoA', 'compoB'],
},
};
const validator = getTypeValidator(attributes.dz, {
types: ['dynamiczone'],
modelType: 'collectionType',
attributes,
});
expect(validator.isValidSync(attributes.dz)).toBeTruthy();
});
});
describe('UID type validator', () => {
test('Target field can be null', () => {
const attributes = {

View File

@ -258,7 +258,8 @@ const getTypeShape = (attribute, { modelType, attributes } = {}) => {
components: yup
.array()
.of(yup.string().required())
.test('isArray', '${path} must be an array', value => Array.isArray(value)),
.test('isArray', '${path} must be an array', value => Array.isArray(value))
.min(1),
min: yup.number(),
max: yup.number(),
};