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