mirror of
https://github.com/strapi/strapi.git
synced 2025-09-26 00:39:49 +00:00
Split attributes yup validations
Signed-off-by: soupette <cyril.lpz@gmail.com>
This commit is contained in:
parent
29e74e9f9f
commit
5366e8f930
@ -631,6 +631,8 @@ const FormModal = () => {
|
|||||||
toggleConfirmModal();
|
toggleConfirmModal();
|
||||||
}, [toggleConfirmModal]);
|
}, [toggleConfirmModal]);
|
||||||
|
|
||||||
|
console.log({ modifiedData });
|
||||||
|
|
||||||
const handleSubmit = async (e, shouldContinue = isCreating) => {
|
const handleSubmit = async (e, shouldContinue = isCreating) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
@ -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: () => {
|
text: () => {
|
||||||
return {
|
return {
|
||||||
items: [
|
items: [
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
// eslint-disable-next-line import/prefer-default-export
|
// eslint-disable-next-line import/prefer-default-export
|
||||||
export { default as attributesForm } from './form';
|
export { default as attributesForm } from './form';
|
||||||
export { default as commonBaseForm } from './commonBaseForm';
|
export { default as commonBaseForm } from './commonBaseForm';
|
||||||
|
export { default as attributeTypes } from './types';
|
||||||
|
@ -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;
|
@ -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,
|
||||||
|
};
|
@ -1,85 +1,11 @@
|
|||||||
import * as yup from 'yup';
|
import { get, toLower } from 'lodash';
|
||||||
import { get, isEmpty, toLower, trim, toNumber } from 'lodash';
|
|
||||||
import { translatedErrors as errorsTrads } from 'strapi-helper-plugin';
|
|
||||||
import getTrad from '../../../../utils/getTrad';
|
|
||||||
import { nameToSlug } from '../createUid';
|
import { nameToSlug } from '../createUid';
|
||||||
|
|
||||||
import { attributesForm, commonBaseForm } from '../attributes';
|
import { attributesForm, attributeTypes, commonBaseForm } from '../attributes';
|
||||||
import { categoryForm, createCategorySchema } from '../category';
|
import { categoryForm, createCategorySchema } from '../category';
|
||||||
import { contentTypeForm, createContentTypeSchema } from '../contentType';
|
import { contentTypeForm, createContentTypeSchema } from '../contentType';
|
||||||
import { createComponentSchema, componentForm } from '../component';
|
import { createComponentSchema, componentForm } from '../component';
|
||||||
import { dynamiczoneForm } from '../dynamicZone';
|
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 = {
|
const forms = {
|
||||||
attribute: {
|
attribute: {
|
||||||
@ -93,235 +19,25 @@ const forms = {
|
|||||||
alreadyTakenTargetContentTypeAttributes,
|
alreadyTakenTargetContentTypeAttributes,
|
||||||
reservedNames
|
reservedNames
|
||||||
) {
|
) {
|
||||||
const alreadyTakenAttributes = Object.keys(
|
try {
|
||||||
get(currentSchema, ['schema', 'attributes'], {})
|
return attributeTypes[attributeType](
|
||||||
).filter(attribute => {
|
currentSchema,
|
||||||
if (isEditing) {
|
initialData,
|
||||||
return attribute !== attributeToEditName;
|
isEditing,
|
||||||
}
|
reservedNames.attributes,
|
||||||
|
dataToValidate,
|
||||||
return true;
|
alreadyTakenTargetContentTypeAttributes
|
||||||
});
|
|
||||||
|
|
||||||
// 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
|
|
||||||
);
|
);
|
||||||
}
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
console.log(attributeType);
|
||||||
|
|
||||||
// Common yup shape for most attributes
|
return attributeTypes.default(
|
||||||
const commonShape = {
|
currentSchema,
|
||||||
name: yup
|
initialData,
|
||||||
.string()
|
isEditing,
|
||||||
.unique(errorsTrads.unique, alreadyTakenAttributes)
|
reservedNames.attributes
|
||||||
.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,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
"error.validation.enum-duplicate": "Duplicate values are not allowed",
|
"error.validation.enum-duplicate": "Duplicate values are not allowed",
|
||||||
"error.validation.minSupMax": "Can't be superior",
|
"error.validation.minSupMax": "Can't be superior",
|
||||||
"error.validation.regex": "Regex pattern is invalid",
|
"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",
|
"error.validation.relation.targetAttribute-taken": "This name exists in the target",
|
||||||
"form.attribute.component.option.add": "Add a component",
|
"form.attribute.component.option.add": "Add a component",
|
||||||
"form.attribute.component.option.create": "Create a new component",
|
"form.attribute.component.option.create": "Create a new component",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user