diff --git a/resources/js/components/dropzone.js b/resources/js/components/dropzone.js index 1cac09b4a..93e93a251 100644 --- a/resources/js/components/dropzone.js +++ b/resources/js/components/dropzone.js @@ -181,10 +181,7 @@ export class Dropzone extends Component { if (this.readyState === XMLHttpRequest.DONE && this.status === 200) { upload.markSuccess(component.successMessage); } else if (this.readyState === XMLHttpRequest.DONE && this.status >= 400) { - const content = this.responseText; - const data = content.startsWith('{') ? JSON.parse(content) : {message: content}; - const message = data?.message || data?.error || content; - upload.markError(message); + upload.markError(window.$http.formatErrorResponseText(this.responseText)); } }, }); diff --git a/resources/js/services/http.js b/resources/js/services/http.js index 49d5b6df4..d95e4a59a 100644 --- a/resources/js/services/http.js +++ b/resources/js/services/http.js @@ -207,3 +207,32 @@ async function performDelete(url, data = null) { } export {performDelete as delete}; + +/** + * Parse the response text for an error response to a user + * presentable string. Handles a range of errors responses including + * validation responses & server response text. + * @param {String} text + * @returns {String} + */ +export function formatErrorResponseText(text) { + const data = text.startsWith('{') ? JSON.parse(text) : {message: text}; + if (!data) { + return text; + } + + if (data.message || data.error) { + return data.message || data.error; + } + + const values = Object.values(data); + const isValidation = values.every(val => { + return Array.isArray(val) || val.every(x => typeof x === 'string'); + }); + + if (isValidation) { + return values.flat().join(' '); + } + + return text; +} diff --git a/resources/sass/_components.scss b/resources/sass/_components.scss index fc4ddeba4..18d1bc18f 100644 --- a/resources/sass/_components.scss +++ b/resources/sass/_components.scss @@ -321,6 +321,10 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group { background-color: var(--color-primary); transition: width ease-in-out 240ms; } +.dropzone-file-item-label { + line-height: 1.2; + margin-bottom: .2rem; +} .dropzone-file-item-label, .dropzone-file-item-status { align-items: center;