diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/index.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/index.js index a0c802680b..5647088770 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/index.js @@ -631,6 +631,8 @@ const FormModal = () => { toggleConfirmModal(); }, [toggleConfirmModal]); + console.log({ modifiedData }); + const handleSubmit = async (e, shouldContinue = isCreating) => { e.preventDefault(); diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/attributes/baseForm.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/attributes/baseForm.js index 4f582ee494..90e4fdf314 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/attributes/baseForm.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/attributes/baseForm.js @@ -234,6 +234,35 @@ const baseForm = { ], }; }, + string: () => { + return { + items: [ + [nameField], + [ + { + label: { id: getTrad('modalForm.attribute.text.type-selection') }, + name: 'type', + size: 12, + type: 'booleanBox', + options: [ + { + headerId: getTrad('form.attribute.text.option.short-text'), + descriptionId: getTrad('form.attribute.text.option.short-text.description'), + value: 'string', + }, + { + headerId: getTrad('form.attribute.text.option.long-text'), + descriptionId: getTrad('form.attribute.text.option.long-text.description'), + value: 'text', + }, + ], + validations: {}, + }, + ], + [uiHelpers.spacerMedium], + ], + }; + }, text: () => { return { items: [ diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/attributes/index.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/attributes/index.js index 0a3ad14063..96d8bae11f 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/attributes/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/attributes/index.js @@ -1,3 +1,4 @@ // eslint-disable-next-line import/prefer-default-export export { default as attributesForm } from './form'; export { default as commonBaseForm } from './commonBaseForm'; +export { default as attributeTypes } from './types'; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/attributes/types.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/attributes/types.js new file mode 100644 index 0000000000..4c6a2232d5 --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/attributes/types.js @@ -0,0 +1,321 @@ +import * as yup from 'yup'; +// import { get } from 'lodash'; +// import { isEmpty } from 'lodash'; +import { translatedErrors as errorsTrads } from 'strapi-helper-plugin'; +import getTrad from '../../../../utils/getTrad'; +import { + alreadyUsedAttributeNames, + createTextShape, + getUsedContentTypeAttributeNames, + isMinSuperiorThanMax, + isNameAllowed, + validators, + NAME_REGEX, +} from './validation/common'; + +const types = { + date: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + type: validators.type(), + }; + + return yup.object(shape); + }, + datetime: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + type: validators.type(), + }; + + return yup.object(shape); + }, + time: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + type: validators.type(), + }; + + return yup.object(shape); + }, + default: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + type: validators.type(), + }; + + return yup.object(shape); + }, + biginteger: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + type: validators.type(), + default: yup + .string() + .nullable() + .matches(/^\d*$/), + unique: validators.unique(), + required: validators.required(), + + max: yup + .string() + .nullable() + .matches(/^\d*$/, errorsTrads.regex), + min: yup + .string() + .nullable() + .test(isMinSuperiorThanMax) + .matches(/^\d*$/, errorsTrads.regex), + }; + + return yup.object(shape); + }, + boolean: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + default: yup.boolean().nullable(), + required: validators.required(), + unique: validators.unique(), + }; + + return yup.object(shape); + }, + component: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + type: validators.type(), + required: validators.required(), + max: validators.max(), + min: validators.min(), + component: yup.string().required(errorsTrads.required), + }; + + return yup.object(shape); + }, + decimal: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + type: validators.type(), + default: yup.number(), + required: validators.required(), + max: yup.number(), + min: yup.number().test(isMinSuperiorThanMax), + }; + + return yup.object(shape); + }, + dynamiczone: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + type: validators.type(), + required: validators.required(), + max: validators.max(), + min: validators.min(), + }; + + return yup.object(shape); + }, + email: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + type: validators.type(), + default: yup + .string() + .email() + .nullable(), + unique: validators.unique(), + required: validators.required(), + maxLength: validators.maxLength(), + minLength: validators.minLength(), + }; + + return yup.object(shape); + }, + enumeration: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const usedNames = getUsedContentTypeAttributeNames( + contentTypeSchema, + isEdition, + initialData.name + ); + + const ENUM_REGEX = new RegExp('^[_A-Za-z][_0-9A-Za-z]*$'); + + const shape = { + name: yup + .string() + .test(alreadyUsedAttributeNames(usedNames)) + .test(isNameAllowed(reservedNames)) + .matches(ENUM_REGEX, errorsTrads.regex) + .required(errorsTrads.required), + type: validators.type(), + default: validators.default(), + unique: validators.unique(), + required: validators.required(), + enum: yup + .array() + .of(yup.string()) + .min(1, errorsTrads.min) + .test({ + name: 'areEnumValuesUnique', + message: getTrad('error.validation.enum-duplicate'), + test: values => { + const filtered = [...new Set(values)]; + + return filtered.length === values.length; + }, + }) + .test({ + name: 'valuesMatchesRegex', + message: errorsTrads.regex, + test: values => { + return values.every(val => val === '' || ENUM_REGEX.test(val)); + }, + }) + .test({ + name: 'doesNotHaveEmptyValues', + message: getTrad('error.validation.enum-empty-string'), + test: values => !values.some(val => val === ''), + }), + enumName: yup.string().nullable(), + }; + + return yup.object(shape); + }, + float: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + type: validators.type(), + required: validators.required(), + default: yup.number(), + max: yup.number(), + min: yup.number().test(isMinSuperiorThanMax), + }; + + return yup.object(shape); + }, + integer: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + type: validators.type(), + default: yup.number().integer(), + unique: validators.unique(), + required: validators.required(), + max: validators.max(), + min: validators.min(), + }; + + return yup.object(shape); + }, + json: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + type: validators.type(), + required: validators.required(), + unique: validators.unique(), + }; + + return yup.object(shape); + }, + media: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + type: validators.type(), + multiple: yup.boolean(), + required: validators.required(), + allowedTypes: yup + .array() + .of(yup.string().oneOf(['images', 'videos', 'files'])) + .min(1) + .nullable(), + }; + + return yup.object(shape); + }, + password: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + type: validators.type(), + default: validators.default(), + unique: validators.unique(), + required: validators.required(), + maxLength: validators.maxLength(), + minLength: validators.minLength(), + }; + + return yup.object(shape); + }, + relation: ( + contentTypeSchema, + initialData, + isEdition, + reservedNames, + data, + alreadyTakenTargetAttributes + ) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + target: yup.string().required(errorsTrads.required), + nature: yup.string().required(), + dominant: yup.boolean().nullable(), + unique: yup.boolean().nullable(), + targetAttribute: yup.lazy(() => { + let schema = yup.string().test(isNameAllowed(reservedNames)); + const initialForbiddenName = [...alreadyTakenTargetAttributes, data.name]; + + let forbiddenTargetAttributeName = isEdition + ? initialForbiddenName.filter(val => val !== initialData.targetAttribute) + : initialForbiddenName; + + if (!['oneWay', 'manyWay'].includes(data.nature)) { + schema = schema.matches(NAME_REGEX, errorsTrads.regex); + } + + return schema + .test({ + name: 'forbiddenTargetAttributeName', + message: getTrad('error.validation.relation.targetAttribute-taken'), + test: value => { + if (!value) { + return false; + } + + return !forbiddenTargetAttributeName.includes(value); + }, + }) + .required(errorsTrads.required); + }), + }; + + return yup.object(shape); + }, + richtext: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + type: validators.type(), + default: validators.default(), + unique: validators.unique(), + required: validators.required(), + maxLength: validators.maxLength(), + minLength: validators.minLength(), + }; + + return yup.object(shape); + }, + string: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = createTextShape(contentTypeSchema, initialData, isEdition, reservedNames); + + return yup.object(shape); + }, + text: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = createTextShape(contentTypeSchema, initialData, isEdition, reservedNames); + + return yup.object(shape); + }, + uid: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = createTextShape(contentTypeSchema, initialData, isEdition, reservedNames); + + return yup.object(shape); + }, +}; + +export default types; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/attributes/validation/common.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/attributes/validation/common.js new file mode 100644 index 0000000000..2c84b50b6b --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/attributes/validation/common.js @@ -0,0 +1,159 @@ +import * as yup from 'yup'; +import { get, toNumber } from 'lodash'; +import { translatedErrors as errorsTrads } from 'strapi-helper-plugin'; +import getTrad from '../../../../../utils/getTrad'; + +const NAME_REGEX = new RegExp('^[A-Za-z][_0-9A-Za-z]*$'); + +const alreadyUsedAttributeNames = usedNames => { + return { + name: 'attributeNameAlreadyUsed', + message: errorsTrads.unique, + test: value => { + if (!value) { + return false; + } + + return !usedNames.includes(value); + }, + }; +}; + +const getUsedContentTypeAttributeNames = (ctShema, isEdition, attributeNameToEdit) => { + const attributes = get(ctShema, ['schema', 'attributes'], {}); + + return Object.keys(attributes).filter(attr => { + if (isEdition) { + return attr !== attributeNameToEdit; + } + + return true; + }); +}; + +const isNameAllowed = reservedNames => { + return { + name: 'forbiddenAttributeName', + message: getTrad('error.attributeName.reserved-name'), + test: value => { + if (!value) { + return false; + } + + return !reservedNames.includes(value); + }, + }; +}; + +const validators = { + default: () => yup.string().nullable(), + max: () => + yup + .number() + .integer() + .positive() + .nullable(), + min: () => + yup + .number() + .integer() + .positive() + .when('max', (max, schema) => { + if (max) { + return schema.max(max, getTrad('error.validation.minSupMax')); + } + + return schema; + }) + .nullable(), + maxLength: () => + yup + .number() + .integer() + .nullable(), + minLength: () => + yup + .number() + .integer() + .when('maxLength', (maxLength, schema) => { + if (maxLength) { + return schema.max(maxLength, getTrad('error.validation.minSupMax')); + } + + return schema; + }) + .nullable(), + name: (contentTypeSchema, initialData, isEdition, reservedNames) => { + const usedNames = getUsedContentTypeAttributeNames( + contentTypeSchema, + isEdition, + initialData.name + ); + + return yup + .string() + .test(alreadyUsedAttributeNames(usedNames)) + .test(isNameAllowed(reservedNames)) + .matches(NAME_REGEX, errorsTrads.regex) + .required(errorsTrads.required); + }, + required: () => yup.boolean(), + type: () => yup.string().required(errorsTrads.required), + unique: () => yup.boolean().nullable(), +}; + +const createTextShape = (contentTypeSchema, initialData, isEdition, reservedNames) => { + const shape = { + name: validators.name(contentTypeSchema, initialData, isEdition, reservedNames), + type: validators.type(), + default: validators.default(), + unique: validators.unique(), + required: validators.required(), + maxLength: validators.maxLength(), + minLength: validators.minLength(), + regex: yup + .string() + .test({ + name: 'isValidRegExpPattern', + message: getTrad('error.validation.regex'), + test: value => { + return new RegExp(value) !== null; + }, + }) + .nullable(), + }; + + return shape; +}; + +const isMinSuperiorThanMax = { + name: 'isMinSuperiorThanMax', + message: getTrad('error.validation.minSupMax'), + test(value) { + if (!value) { + return false; + } + + const { max } = this.parent; + + if (!max) { + return false; + } + + if (Number.isNaN(toNumber(value))) { + return true; + } + + return toNumber(max) >= toNumber(value); + }, +}; + +export { + alreadyUsedAttributeNames, + createTextShape, + getUsedContentTypeAttributeNames, + isMinSuperiorThanMax, + isNameAllowed, + validators, + NAME_REGEX, +}; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/forms/index.js b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/forms/index.js index 1966b03496..5bec668e11 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/forms/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/containers/FormModal/utils/forms/index.js @@ -1,85 +1,11 @@ -import * as yup from 'yup'; -import { get, isEmpty, toLower, trim, toNumber } from 'lodash'; -import { translatedErrors as errorsTrads } from 'strapi-helper-plugin'; -import getTrad from '../../../../utils/getTrad'; +import { get, toLower } from 'lodash'; import { nameToSlug } from '../createUid'; -import { attributesForm, commonBaseForm } from '../attributes'; +import { attributesForm, attributeTypes, commonBaseForm } from '../attributes'; import { categoryForm, createCategorySchema } from '../category'; import { contentTypeForm, createContentTypeSchema } from '../contentType'; import { createComponentSchema, componentForm } from '../component'; import { dynamiczoneForm } from '../dynamicZone'; -import { NAME_REGEX, ENUM_REGEX } from './regexes'; - -/* eslint-disable indent */ -/* eslint-disable prefer-arrow-callback */ - -yup.addMethod(yup.mixed, 'defined', function() { - return this.test('defined', errorsTrads.required, value => value !== undefined); -}); - -yup.addMethod(yup.string, 'unique', function( - message, - alreadyTakenAttributes, - validator, - category = '' -) { - return this.test('unique', message, function(string) { - if (!string) { - return false; - } - - return !alreadyTakenAttributes.includes( - typeof validator === 'function' ? validator(string, category) : string.toLowerCase() - ); - }); -}); - -yup.addMethod(yup.array, 'hasNotEmptyValues', function(message) { - return this.test('hasNotEmptyValues', message, function(array) { - return !array.some(value => { - return isEmpty(value); - }); - }); -}); - -yup.addMethod(yup.string, 'isAllowed', function(message, reservedNames) { - return this.test('isAllowed', message, function(string) { - if (!string) { - return false; - } - - return !reservedNames.includes(toLower(trim(string))); - }); -}); - -yup.addMethod(yup.string, 'isInferior', function(message, max) { - return this.test('isInferior', message, function(min) { - if (!min) { - return false; - } - - if (Number.isNaN(toNumber(min))) { - return true; - } - - return toNumber(max) >= toNumber(min); - }); -}); - -yup.addMethod(yup.array, 'matchesEnumRegex', function(message) { - return this.test('matchesEnumRegex', message, function(array) { - return array.every(value => { - return ENUM_REGEX.test(value); - }); - }); -}); - -yup.addMethod(yup.string, 'isValidRegExpPattern', function(message) { - return this.test('isValidRegExpPattern', message, function(string) { - return new RegExp(string) !== null; - }); -}); const forms = { attribute: { @@ -93,235 +19,25 @@ const forms = { alreadyTakenTargetContentTypeAttributes, reservedNames ) { - const alreadyTakenAttributes = Object.keys( - get(currentSchema, ['schema', 'attributes'], {}) - ).filter(attribute => { - if (isEditing) { - return attribute !== attributeToEditName; - } - - return true; - }); - - // For relations - let targetAttributeAlreadyTakenValue = dataToValidate.name - ? [...alreadyTakenAttributes, dataToValidate.name] - : alreadyTakenAttributes; - - if ( - isEditing && - attributeType === 'relation' && - dataToValidate.target === currentSchema.uid - ) { - targetAttributeAlreadyTakenValue = targetAttributeAlreadyTakenValue.filter( - attribute => attribute !== initialData.targetAttribute + try { + return attributeTypes[attributeType]( + currentSchema, + initialData, + isEditing, + reservedNames.attributes, + dataToValidate, + alreadyTakenTargetContentTypeAttributes ); - } + } catch (err) { + console.log(err); + console.log(attributeType); - // Common yup shape for most attributes - const commonShape = { - name: yup - .string() - .unique(errorsTrads.unique, alreadyTakenAttributes) - .matches(NAME_REGEX, errorsTrads.regex) - .isAllowed(getTrad('error.attributeName.reserved-name'), reservedNames.attributes) - .required(errorsTrads.required), - type: yup.string().required(errorsTrads.required), - default: yup.string().nullable(), - unique: yup.boolean().nullable(), - required: yup.boolean(), - }; - const numberTypeShape = { - max: yup.lazy(() => { - let schema = yup.number(); - - if ( - attributeType === 'integer' || - attributeType === 'biginteger' || - attributeType === 'dynamiczone' - ) { - schema = schema.integer(); - } - - if (attributeType === 'dynamiczone') { - schema = schema.positive(); - } - - return schema.nullable(); - }), - min: yup.lazy(() => { - let schema = yup.number(); - - if ( - attributeType === 'integer' || - attributeType === 'biginteger' || - attributeType === 'dynamiczone' - ) { - schema = schema.integer(); - } - - if (attributeType === 'dynamiczone') { - schema = schema.positive(); - } - - return schema - .nullable() - .when('max', (max, schema) => { - if (max) { - return schema.max(max, getTrad('error.validation.minSupMax')); - } - - return schema; - }) - .nullable(); - }), - }; - const fieldsThatSupportMaxAndMinLengthShape = { - maxLength: yup - .number() - .integer() - .nullable(), - minLength: yup - .number() - .integer() - .when('maxLength', (maxLength, schema) => { - if (maxLength) { - return schema.max(maxLength, getTrad('error.validation.minSupMax')); - } - - return schema; - }) - .nullable(), - }; - - switch (attributeType) { - case 'component': - return yup.object().shape({ - ...commonShape, - component: yup.string().required(errorsTrads.required), - ...numberTypeShape, - }); - case 'dynamiczone': - return yup.object().shape({ - ...commonShape, - ...numberTypeShape, - }); - case 'enumeration': - return yup.object().shape({ - name: yup - .string() - .isAllowed(getTrad('error.attributeName.reserved-name'), reservedNames.attributes) - .unique(errorsTrads.unique, alreadyTakenAttributes) - .matches(ENUM_REGEX, errorsTrads.regex) - .required(errorsTrads.required), - type: yup.string().required(errorsTrads.required), - default: yup.string().nullable(), - unique: yup.boolean().nullable(), - required: yup.boolean(), - enum: yup - .array() - .of(yup.string()) - .min(1, errorsTrads.min) - .test({ - name: 'areEnumValuesUnique', - message: getTrad('error.validation.enum-duplicate'), - test: values => { - const filtered = [...new Set(values)]; - - return filtered.length === values.length; - }, - }) - .matchesEnumRegex(errorsTrads.regex) - .hasNotEmptyValues('Empty strings are not allowed', dataToValidate.enum), - enumName: yup.string().nullable(), - }); - case 'text': - return yup.object().shape({ - ...commonShape, - ...fieldsThatSupportMaxAndMinLengthShape, - regex: yup - .string() - .isValidRegExpPattern(getTrad('error.validation.regex')) - .nullable(), - }); - case 'number': - case 'integer': - case 'biginteger': - case 'float': - case 'decimal': { - if (dataToValidate.type === 'biginteger') { - return yup.object().shape({ - ...commonShape, - default: yup - .string() - .nullable() - .matches(/^\d*$/), - min: yup - .string() - .nullable() - .matches(/^\d*$/) - .when('max', (max, schema) => { - if (max) { - return schema.isInferior(getTrad('error.validation.minSupMax'), max); - } - - return schema; - }), - - max: yup - .string() - .nullable() - .matches(/^\d*$/), - }); - } - - let defaultType = yup.number(); - - if (dataToValidate.type === 'integer') { - defaultType = yup.number().integer('component.Input.error.validation.integer'); - } - - return yup.object().shape({ - ...commonShape, - default: defaultType.nullable(), - ...numberTypeShape, - }); - } - case 'relation': - return yup.object().shape({ - name: yup - .string() - .isAllowed(getTrad('error.attributeName.reserved-name'), reservedNames.attributes) - .matches(NAME_REGEX, errorsTrads.regex) - .unique(errorsTrads.unique, alreadyTakenAttributes) - .required(errorsTrads.required), - targetAttribute: yup.lazy(() => { - let schema = yup - .string() - .isAllowed(getTrad('error.attributeName.reserved-name'), reservedNames.attributes); - - if (!['oneWay', 'manyWay'].includes(dataToValidate.nature)) { - schema = schema.matches(NAME_REGEX, errorsTrads.regex); - } - - return schema - .unique(errorsTrads.unique, targetAttributeAlreadyTakenValue) - .unique( - getTrad('error.validation.relation.targetAttribute-taken'), - alreadyTakenTargetContentTypeAttributes - ) - .required(errorsTrads.required); - }), - target: yup.string().required(errorsTrads.required), - nature: yup.string().required(), - dominant: yup.boolean().nullable(), - unique: yup.boolean().nullable(), - }); - default: - return yup.object().shape({ - ...commonShape, - ...fieldsThatSupportMaxAndMinLengthShape, - }); + return attributeTypes.default( + currentSchema, + initialData, + isEditing, + reservedNames.attributes + ); } }, form: { diff --git a/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json b/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json index ac1a2c2b28..9911bd1279 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json +++ b/packages/strapi-plugin-content-type-builder/admin/src/translations/en.json @@ -54,6 +54,7 @@ "error.validation.enum-duplicate": "Duplicate values are not allowed", "error.validation.minSupMax": "Can't be superior", "error.validation.regex": "Regex pattern is invalid", + "error.validation.enum-empty-string": "Empty strings are not allowed", "error.validation.relation.targetAttribute-taken": "This name exists in the target", "form.attribute.component.option.add": "Add a component", "form.attribute.component.option.create": "Create a new component",