mirror of
https://github.com/strapi/strapi.git
synced 2025-11-03 03:17:11 +00:00
Fix CTM dz min max validations
This commit is contained in:
parent
4ad9fdef52
commit
e29bd761e4
@ -43,6 +43,15 @@
|
||||
"full_name": {
|
||||
"type": "string",
|
||||
"required": true
|
||||
},
|
||||
"dz": {
|
||||
"type": "dynamiczone",
|
||||
"components": [
|
||||
"default.dish",
|
||||
"default.openingtimes",
|
||||
"default.restaurantservice"
|
||||
],
|
||||
"min": 2
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,12 +18,6 @@
|
||||
"price": {
|
||||
"type": "float"
|
||||
},
|
||||
"address": {
|
||||
"model": "address"
|
||||
},
|
||||
"addresses": {
|
||||
"collection": "address"
|
||||
},
|
||||
"picture": {
|
||||
"model": "file",
|
||||
"via": "related",
|
||||
|
||||
@ -25,7 +25,7 @@ const ComponentWrapper = styled.div`
|
||||
content: '&';
|
||||
position: absolute;
|
||||
top: -30px;
|
||||
left: 22px;
|
||||
left: 24.5px;
|
||||
height: 100%;
|
||||
width: 2px;
|
||||
background-color: #e6f0fb;
|
||||
|
||||
@ -10,7 +10,7 @@ const Label = styled.div`
|
||||
content: '•';
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
left: 21.25px;
|
||||
left: 21.5px;
|
||||
font-size: 15px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
|
||||
@ -72,6 +72,10 @@ const DynamicZone = ({ max, min, name }) => {
|
||||
get(dynamicZoneErrors, [0, 'id'], '').includes('min');
|
||||
|
||||
const hasRequiredError = hasError && !hasMinError;
|
||||
const hasMaxError =
|
||||
hasError &&
|
||||
get(dynamicZoneErrors, [0, 'id'], '') ===
|
||||
'components.Input.error.validation.max';
|
||||
|
||||
return (
|
||||
<DynamicZoneWrapper>
|
||||
@ -144,9 +148,14 @@ const DynamicZone = ({ max, min, name }) => {
|
||||
}
|
||||
}}
|
||||
/>
|
||||
{hasRequiredError && !isOpen && (
|
||||
{hasRequiredError && !isOpen && !hasMaxError && (
|
||||
<div className="error-label">Component is required</div>
|
||||
)}
|
||||
{hasMaxError && !isOpen && (
|
||||
<div className="error-label">
|
||||
<FormattedMessage id="components.Input.error.validation.max" />
|
||||
</div>
|
||||
)}
|
||||
{hasMinError && !isOpen && (
|
||||
<div className="error-label">
|
||||
<FormattedMessage
|
||||
|
||||
@ -128,7 +128,8 @@ const BannerWrapper = styled.button`
|
||||
svg {
|
||||
font-size: 10px;
|
||||
path {
|
||||
fill: #292b2c;
|
||||
// fill: #292b2c;
|
||||
fill: #4B515A;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -139,14 +140,18 @@ const BannerWrapper = styled.button`
|
||||
}
|
||||
|
||||
${({ hasErrors, isOpen }) => {
|
||||
let fill = '#B4B6BA';
|
||||
// let fill = '#B4B6BA';
|
||||
let fill = '#ABB3C2';
|
||||
let trashFill = '#4B515A';
|
||||
|
||||
if (isOpen) {
|
||||
fill = '#007EFF';
|
||||
trashFill = '#007EFF';
|
||||
}
|
||||
|
||||
if (hasErrors) {
|
||||
fill = '#F64D0A';
|
||||
fill = '#FAA684';
|
||||
trashFill = '#F64D0A';
|
||||
}
|
||||
|
||||
return `
|
||||
@ -155,6 +160,13 @@ const BannerWrapper = styled.button`
|
||||
fill: ${fill} !important;
|
||||
}
|
||||
}
|
||||
.trash-icon {
|
||||
svg {
|
||||
path {
|
||||
fill: ${trashFill} !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
}}
|
||||
|
||||
|
||||
@ -33,10 +33,13 @@ const EditViewDataManagerProvider = ({
|
||||
initialData,
|
||||
isLoading,
|
||||
modifiedData,
|
||||
modifiedDZName,
|
||||
shouldShowLoadingState,
|
||||
shouldCheckErrors,
|
||||
} = reducerState.toJS();
|
||||
|
||||
console.log({ formErrors });
|
||||
|
||||
const currentContentTypeLayout = get(allLayoutData, ['contentType'], {});
|
||||
const abortController = new AbortController();
|
||||
const { signal } = abortController;
|
||||
@ -167,6 +170,17 @@ const EditViewDataManagerProvider = ({
|
||||
await schema.validate(updatedData, { abortEarly: false });
|
||||
} catch (err) {
|
||||
errors = getYupInnerErrors(err);
|
||||
|
||||
if (modifiedDZName) {
|
||||
errors = Object.keys(errors).reduce((acc, current) => {
|
||||
const dzName = current.split('.')[0];
|
||||
|
||||
if (dzName !== modifiedDZName) {
|
||||
acc[current] = errors[current];
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
}
|
||||
|
||||
dispatch({
|
||||
@ -313,10 +327,17 @@ const EditViewDataManagerProvider = ({
|
||||
|
||||
const removeComponentFromDynamicZone = (dynamicZoneName, index) => {
|
||||
emitEvent('removeComponentFromDynamicZone');
|
||||
|
||||
const doesDZHaveError = Object.keys(formErrors).some(
|
||||
key => key.split('.')[0] === dynamicZoneName
|
||||
);
|
||||
const shouldCheckErrors = !isEmpty(formErrors) && doesDZHaveError;
|
||||
|
||||
dispatch({
|
||||
type: 'REMOVE_COMPONENT_FROM_DYNAMIC_ZONE',
|
||||
dynamicZoneName,
|
||||
index,
|
||||
shouldCheckErrors,
|
||||
});
|
||||
};
|
||||
const removeComponentFromField = (keys, componentUid) => {
|
||||
|
||||
@ -9,6 +9,7 @@ const initialState = fromJS({
|
||||
modifiedData: {},
|
||||
shouldShowLoadingState: false,
|
||||
shouldCheckErrors: false,
|
||||
modifiedDZName: null,
|
||||
});
|
||||
|
||||
const reducer = (state, action) => {
|
||||
@ -57,6 +58,7 @@ const reducer = (state, action) => {
|
||||
|
||||
return fromJS([defaultDataStructure]);
|
||||
})
|
||||
.update('modifiedDZName', () => action.keys[0])
|
||||
.update('shouldCheckErrors', v => {
|
||||
if (action.shouldCheckErrors === true) {
|
||||
return !v;
|
||||
@ -152,11 +154,15 @@ const reducer = (state, action) => {
|
||||
});
|
||||
}
|
||||
case 'REMOVE_COMPONENT_FROM_DYNAMIC_ZONE':
|
||||
return state.deleteIn([
|
||||
'modifiedData',
|
||||
action.dynamicZoneName,
|
||||
action.index,
|
||||
]);
|
||||
return state
|
||||
.update('shouldCheckErrors', v => {
|
||||
if (action.shouldCheckErrors) {
|
||||
return !v;
|
||||
}
|
||||
|
||||
return v;
|
||||
})
|
||||
.deleteIn(['modifiedData', action.dynamicZoneName, action.index]);
|
||||
case 'REMOVE_COMPONENT_FROM_FIELD': {
|
||||
const componentPathToRemove = ['modifiedData', ...action.keys];
|
||||
|
||||
@ -190,7 +196,9 @@ const reducer = (state, action) => {
|
||||
.update('isLoading', () => false)
|
||||
.update('modifiedData', () => fromJS(action.contentTypeDataStructure));
|
||||
case 'SET_ERRORS':
|
||||
return state.update('formErrors', () => fromJS(action.errors));
|
||||
return state
|
||||
.update('modifiedDZName', () => null)
|
||||
.update('formErrors', () => fromJS(action.errors));
|
||||
case 'SUBMIT_ERRORS':
|
||||
return state
|
||||
.update('formErrors', () => fromJS(action.errors))
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { get, isBoolean, isNaN } from 'lodash';
|
||||
import { get, isBoolean, isEmpty, isNaN } from 'lodash';
|
||||
import * as yup from 'yup';
|
||||
import { translatedErrors as errorsTrads } from 'strapi-helper-plugin';
|
||||
|
||||
@ -10,6 +10,15 @@ yup.addMethod(yup.mixed, 'defined', function() {
|
||||
);
|
||||
});
|
||||
|
||||
yup.addMethod(yup.array, 'notEmptyMin', function(min) {
|
||||
return this.test('notEmptyMin', errorsTrads.min, value => {
|
||||
if (isEmpty(value)) {
|
||||
return true;
|
||||
}
|
||||
return value.length > min;
|
||||
});
|
||||
});
|
||||
|
||||
const getAttributes = data => get(data, ['schema', 'attributes'], {});
|
||||
|
||||
const createYupSchema = (model, { components }) => {
|
||||
@ -110,7 +119,7 @@ const createYupSchema = (model, { components }) => {
|
||||
}
|
||||
} else {
|
||||
if (min) {
|
||||
dynamicZoneSchema = dynamicZoneSchema.min(min, errorsTrads.min);
|
||||
dynamicZoneSchema = dynamicZoneSchema.notEmptyMin(min);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -108,6 +108,10 @@ const forms = {
|
||||
schema = schema.integer();
|
||||
}
|
||||
|
||||
if (attributeType === 'dynamiczone') {
|
||||
schema = schema.positive();
|
||||
}
|
||||
|
||||
return schema.nullable();
|
||||
}),
|
||||
min: yup.lazy(() => {
|
||||
@ -121,14 +125,15 @@ const forms = {
|
||||
schema = schema.integer();
|
||||
}
|
||||
|
||||
if (attributeType === 'dynamiczone') {
|
||||
schema = schema.positive();
|
||||
}
|
||||
|
||||
return schema
|
||||
.nullable()
|
||||
.when('max', (max, schema) => {
|
||||
if (max) {
|
||||
return schema.lessThan(
|
||||
max,
|
||||
getTrad('error.validation.minSupMax')
|
||||
);
|
||||
return schema.max(max, getTrad('error.validation.minSupMax'));
|
||||
} else {
|
||||
return schema;
|
||||
}
|
||||
@ -146,7 +151,7 @@ const forms = {
|
||||
.integer()
|
||||
.when('maxLength', (maxLength, schema) => {
|
||||
if (maxLength) {
|
||||
return schema.lessThan(
|
||||
return schema.max(
|
||||
maxLength,
|
||||
getTrad('error.validation.minSupMax')
|
||||
);
|
||||
|
||||
@ -41,6 +41,7 @@
|
||||
"contentType.collectionName.description": "Useful when the name of your Content Type and your table name differ",
|
||||
"contentType.collectionName.label": "Collection name",
|
||||
"contentType.displayName.label": "Display name",
|
||||
"error.validation.minSupMax": "Can't be superior",
|
||||
"form.attribute.component.option.add": "Add a component",
|
||||
"form.attribute.component.option.create": "Create a new component",
|
||||
"form.attribute.component.option.create.description": "A component is shared across types and components, it will be available and accessible everywhere.",
|
||||
@ -96,6 +97,7 @@
|
||||
"form.button.save": "Save",
|
||||
"form.button.select-component": "Select a component",
|
||||
"from": "from",
|
||||
|
||||
"injected-components.content-manager.edit-settings-view.link.content-types": "Edit the content type",
|
||||
"injected-components.content-manager.edit-settings-view.link.components": "Edit the component",
|
||||
"menu.section.components.name.plural": "Components",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user