diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 364a185326..10c11ef46d 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -212,7 +212,7 @@ module.exports = { '/3.0.0-beta.x/guides/scheduled-publication', '/3.0.0-beta.x/guides/slug', '/3.0.0-beta.x/guides/send-email', - '/3.0.0-beta.x/guides/registering-field-in-admin', + '/3.0.0-beta.x/guides/registering-a-field-in-admin', '/3.0.0-beta.x/guides/count-graphql', ], }, diff --git a/packages/strapi-plugin-content-manager/admin/src/components/Inputs/index.js b/packages/strapi-plugin-content-manager/admin/src/components/Inputs/index.js index aa82db1063..904951aea9 100644 --- a/packages/strapi-plugin-content-manager/admin/src/components/Inputs/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/components/Inputs/index.js @@ -61,7 +61,15 @@ function Inputs({ autoFocus, keys, layout, name, onBlur }) { const disabled = useMemo(() => !get(metadatas, 'editable', true), [metadatas]); const type = useMemo(() => get(attribute, 'type', null), [attribute]); const regexpString = useMemo(() => get(attribute, 'regex', null), [attribute]); - const validations = omit(attribute, [ + const value = get(modifiedData, keys, null); + const temporaryErrorIdUntilBuffetjsSupportsFormattedMessage = 'app.utils.defaultMessage'; + const errorId = get( + formErrors, + [keys, 'id'], + temporaryErrorIdUntilBuffetjsSupportsFormattedMessage + ); + + let validationsToOmit = [ 'type', 'model', 'via', @@ -70,7 +78,20 @@ function Inputs({ autoFocus, keys, layout, name, onBlur }) { 'plugin', 'enum', 'regex', - ]); + ]; + + // Remove the required validation for the password type unless the form is already submitted + // So the error is properly displayed in the password input + if (type === 'password' && errorId !== 'components.Input.error.validation.required') { + validationsToOmit = [...validationsToOmit, 'required']; + } + + // Remove the minLength validation when the user clears the input so it is not displayed + if (type === 'password' && !value) { + validationsToOmit = [...validationsToOmit, 'minLength']; + } + + const validations = omit(attribute, validationsToOmit); if (regexpString) { const regexp = new RegExp(regexpString); @@ -81,17 +102,11 @@ function Inputs({ autoFocus, keys, layout, name, onBlur }) { } const { description, visible } = metadatas; - const value = get(modifiedData, keys, null); if (visible === false) { return null; } - const temporaryErrorIdUntilBuffetjsSupportsFormattedMessage = 'app.utils.defaultMessage'; - const errorId = get( - formErrors, - [keys, 'id'], - temporaryErrorIdUntilBuffetjsSupportsFormattedMessage - ); + const isRequired = get(validations, ['required'], false); if (type === 'relation') { diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/index.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/index.js index aca308405e..7d9d127f60 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/index.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/index.js @@ -142,9 +142,13 @@ const EditViewDataManagerProvider = ({ allLayoutData, children, redirectToPrevio }; const checkFormErrors = async (dataToSet = {}) => { - const schema = createYupSchema(currentContentTypeLayout, { - components: get(allLayoutData, 'components', {}), - }); + const schema = createYupSchema( + currentContentTypeLayout, + { + components: get(allLayoutData, 'components', {}), + }, + isCreatingEntry + ); let errors = {}; const updatedData = cloneDeep(modifiedData); @@ -186,6 +190,15 @@ const EditViewDataManagerProvider = ({ allLayoutData, children, redirectToPrevio inputValue = null; } + if (type === 'password' && !value) { + dispatch({ + type: 'REMOVE_PASSWORD_FIELD', + keys: name.split('.'), + }); + + return; + } + // Allow to reset enum if (type === 'select-one' && value === '') { inputValue = null; @@ -207,9 +220,13 @@ const EditViewDataManagerProvider = ({ allLayoutData, children, redirectToPrevio e.preventDefault(); // Create yup schema - const schema = createYupSchema(currentContentTypeLayout, { - components: get(allLayoutData, 'components', {}), - }); + const schema = createYupSchema( + currentContentTypeLayout, + { + components: get(allLayoutData, 'components', {}), + }, + isCreatingEntry + ); try { // Validate the form using yup diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/reducer.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/reducer.js index c922057e9d..9978d48344 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/reducer.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/reducer.js @@ -161,6 +161,9 @@ const reducer = (state, action) => { return state.updateIn(componentPathToRemove, () => null); } + case 'REMOVE_PASSWORD_FIELD': { + return state.removeIn(['modifiedData', ...action.keys]); + } case 'REMOVE_REPEATABLE_FIELD': { const componentPathToRemove = ['modifiedData', ...action.keys]; diff --git a/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/utils/schema.js b/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/utils/schema.js index 63a6e64870..60128320dc 100644 --- a/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/utils/schema.js +++ b/packages/strapi-plugin-content-manager/admin/src/containers/EditViewDataManagerProvider/utils/schema.js @@ -56,7 +56,7 @@ yup.addMethod(yup.string, 'isSuperior', function(message, min) { const getAttributes = data => get(data, ['schema', 'attributes'], {}); -const createYupSchema = (model, { components }) => { +const createYupSchema = (model, { components }, isCreatingEntry = true) => { const attributes = getAttributes(model); return yup.object().shape( @@ -68,7 +68,7 @@ const createYupSchema = (model, { components }) => { attribute.type !== 'component' && attribute.type !== 'dynamiczone' ) { - const formatted = createYupSchemaAttribute(attribute.type, attribute); + const formatted = createYupSchemaAttribute(attribute.type, attribute, isCreatingEntry); acc[current] = formatted; } @@ -166,7 +166,7 @@ const createYupSchema = (model, { components }) => { ); }; -const createYupSchemaAttribute = (type, validations) => { +const createYupSchemaAttribute = (type, validations, isCreatingEntry) => { let schema = yup.mixed(); let regex = get(validations, 'regex', null); @@ -231,9 +231,18 @@ const createYupSchemaAttribute = (type, validations) => { validationValue === 0 ) { switch (validation) { - case 'required': - schema = schema.required(errorsTrads.required); + case 'required': { + if (type === 'password' && isCreatingEntry) { + schema = schema.required(errorsTrads.required); + } + + if (type !== 'password') { + schema = schema.required(errorsTrads.required); + } + break; + } + case 'max': { if (type === 'biginteger') { schema = schema.isInferior(errorsTrads.max, validationValue);