From 804ad98235ec598e9aebdf3c4e33e9d43f238ac7 Mon Sep 17 00:00:00 2001 From: ducica Date: Wed, 8 Nov 2023 07:53:34 +0100 Subject: [PATCH] validation during publish --- .../components/FormFeedback/FormFeedback.jsx | 20 +++++++-- .../semantic-ui/js/oarepo_ui/forms/hooks.js | 44 ++++++++++--------- 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/oarepo_ui/theme/assets/semantic-ui/js/oarepo_ui/forms/components/FormFeedback/FormFeedback.jsx b/oarepo_ui/theme/assets/semantic-ui/js/oarepo_ui/forms/components/FormFeedback/FormFeedback.jsx index 7a697a42..8590eeec 100644 --- a/oarepo_ui/theme/assets/semantic-ui/js/oarepo_ui/forms/components/FormFeedback/FormFeedback.jsx +++ b/oarepo_ui/theme/assets/semantic-ui/js/oarepo_ui/forms/components/FormFeedback/FormFeedback.jsx @@ -20,18 +20,19 @@ const CustomMessage = ({ children, ...uiProps }) => { }; export const FormFeedback = () => { const { values } = useFormikContext(); - const validationErrors = getIn(values, "validationErrors", {}); + const BEvalidationErrors = getIn(values, "BEvalidationErrors", {}); + const FEvalidationErrors = getIn(values, "FEvalidationErrors", {}); let httpError = getIn(values, "httpErrors", ""); if (httpError?.response?.data) { httpError = httpError?.response?.data.message; } const successMessage = getIn(values, "successMessage", ""); - if (!_isEmpty(validationErrors)) + if (!_isEmpty(BEvalidationErrors)) return ( - {validationErrors?.errorMessage} + {BEvalidationErrors?.errorMessage} - {validationErrors?.errors?.map((error, index) => ( + {BEvalidationErrors?.errors?.map((error, index) => ( {`${titleCase( error.field )}: ${error.messages[0]}`} @@ -39,6 +40,17 @@ export const FormFeedback = () => { ); + if (!_isEmpty(FEvalidationErrors)) + return ( + + {FEvalidationErrors?.errorMessage} + + {FEvalidationErrors?.errors?.map((error, index) => ( + {error} + ))} + + + ); if (httpError) return ( diff --git a/oarepo_ui/theme/assets/semantic-ui/js/oarepo_ui/forms/hooks.js b/oarepo_ui/theme/assets/semantic-ui/js/oarepo_ui/forms/hooks.js index f11bc57c..d980e6dd 100644 --- a/oarepo_ui/theme/assets/semantic-ui/js/oarepo_ui/forms/hooks.js +++ b/oarepo_ui/theme/assets/semantic-ui/js/oarepo_ui/forms/hooks.js @@ -8,21 +8,24 @@ import _isEmpty from "lodash/isEmpty"; import { i18next } from "@translations/oarepo_ui/i18next"; import { relativeUrl } from "../util"; -// maybe it makes sense to collocate it here as this is the only place it is used for now -export const translateFEtoBEValidationErrors = (feValidationObject) => { - const beValidationArray = []; - - for (const field in feValidationObject.metadata) { - if (feValidationObject.metadata.hasOwnProperty(field)) { - const errorMessage = feValidationObject.metadata[field]; - const beError = { - field: `metadata.${field}`, - messages: [errorMessage], - }; - beValidationArray.push(beError); +const extractFEErrorMessages = (obj) => { + const errorMessages = []; + + const traverse = (obj) => { + for (const key in obj) { + if (typeof obj[key] === "string") { + errorMessages.push(obj[key]); + } else if (Array.isArray(obj[key])) { + obj[key].forEach((item) => traverse(item)); + } else if (typeof obj[key] === "object") { + traverse(obj[key]); + } } - } - return beValidationArray; + }; + + traverse(obj); + const uniqueErrorMessages = [...new Set(errorMessages)]; + return uniqueErrorMessages; }; export const useFormConfig = () => { @@ -57,7 +60,8 @@ export const useDepositApiClient = ( serializer, internalFieldsArray = [ "errors", - "validationErrors", + "BEvalidationErrors", + "FEvalidationErrors", "httpErrors", "successMessage", ], @@ -123,7 +127,7 @@ export const useDepositApiClient = ( setFieldError(error.field, error.messages[0]) ); // here I am setting the state to be used by FormFeedback componene that plugs into the formik's context. - setFieldValue("validationErrors", { + setFieldValue("BEvalidationErrors", { errors: response.errors, errorMessage: i18next.t( "Draft saved with validation errors. Fields listed below that failed validation were not saved to the server" @@ -152,11 +156,11 @@ export const useDepositApiClient = ( const saveResult = await save(); if (!saveResult) return; // imperative form validation, if fails exit - const validationErrors = await validateForm(); + const FEvalidationErrors = await validateForm(); // show also front end validation errors grouped on the top similar to BE validation errors for consistency - if (!_isEmpty(validationErrors)) { - setFieldValue("validationErrors", { - errors: translateFEtoBEValidationErrors(validationErrors), + if (!_isEmpty(FEvalidationErrors)) { + setFieldValue("FEvalidationErrors", { + errors: extractFEErrorMessages(FEvalidationErrors.metadata), errorMessage: i18next.t( "Draft was saved but could not be published due to following validation errors" ),