From e1ec520ec8933efe8e2ff9c00baa3fe1fd5b68aa Mon Sep 17 00:00:00 2001 From: Pierre-Gilles Leymarie <7365207+Pierre-Gilles@users.noreply.github.com> Date: Fri, 28 Feb 2025 15:57:38 +0100 Subject: [PATCH] MQTT : Add better validation errors on create device form (#2244) --- front/src/config/i18n/de.json | 7 +++++++ front/src/config/i18n/en.json | 7 +++++++ front/src/config/i18n/fr.json | 7 +++++++ .../all/mqtt/device-page/setup/FeatureTab.jsx | 15 +++++++++++++++ .../all/mqtt/device-page/setup/index.js | 14 ++++++++++++-- 5 files changed, 48 insertions(+), 2 deletions(-) diff --git a/front/src/config/i18n/de.json b/front/src/config/i18n/de.json index ddad44d06a..766bbbe04d 100644 --- a/front/src/config/i18n/de.json +++ b/front/src/config/i18n/de.json @@ -1298,6 +1298,13 @@ "notFound": "Angefordertes Gerät nicht gefunden.", "backToList": "Zurück zur Geräteliste", "saveError": "Fehler beim Sichern oder Löschen des Geräts", + "validationError": "Validierungsfehler: Das Gerät ist nicht korrekt ausgefüllt.", + "validationErrors": { + "name": "Das Feld \"Name\" ist erforderlich", + "min": "Das Minimalfeld ist erforderlich und muss eine ganze Zahl sein", + "max": "Das Maximalfeld ist erforderlich und muss eine ganze Zahl sein", + "external_id": "Das externe ID-Feld ist erforderlich und muss über alle Geräte hinweg eindeutig sein" + }, "saveConflictError": "Konflikt: Sind alle externen IDs wirklich eindeutig?", "mostRecentValueAt": "Zuletzt empfangener Wert {{mostRecentValueAt}}.", "noValueReceived": "Kein Wert empfangen." diff --git a/front/src/config/i18n/en.json b/front/src/config/i18n/en.json index b12cc24545..aeed7bd8bf 100644 --- a/front/src/config/i18n/en.json +++ b/front/src/config/i18n/en.json @@ -1298,6 +1298,13 @@ "notFound": "Requested device not found.", "backToList": "Back to device list", "saveError": "Error saving or deleting device", + "validationError": "Validation error : The device is not correctly filled.", + "validationErrors": { + "name": "The name field is required", + "min": "The minimum field is required and must be an integer", + "max": "The maximum field is required and must be an integer", + "external_id": "The external ID field is required and must be unique across all devices" + }, "saveConflictError": "Conflict: Are you sure all external IDs are unique?", "mostRecentValueAt": "Last value received {{mostRecentValueAt}}.", "noValueReceived": "No value received." diff --git a/front/src/config/i18n/fr.json b/front/src/config/i18n/fr.json index b7c2942dea..52a5d816ff 100644 --- a/front/src/config/i18n/fr.json +++ b/front/src/config/i18n/fr.json @@ -1426,6 +1426,13 @@ "notFound": "Appareil introuvable.", "backToList": "Retour à la liste des appareils", "saveError": "Erreur lors de l'enregistrement ou de la suppression de l'appareil", + "validationError": "Erreur de validation : L'appareil n'a pas été correctement rempli.", + "validationErrors": { + "name": "Le champ \"Nom\" est obligatoire", + "min": "Le champ \"Valeur minimum\" est obligatoire et doit être une valeur entière", + "max": "Le champ \"Valeur maximum\" est obligatoire et doit être une valeur entière", + "external_id": "Le champ \"ID Externe\" est obligatoire et doit être unique à travers tous les appareils" + }, "saveConflictError": "Conflit : êtes-vous sûr que tous les IDs externes sont uniques ?", "mostRecentValueAt": "Dernière valeur reçue {{mostRecentValueAt}}.", "noValueReceived": "Aucune valeur reçue." diff --git a/front/src/routes/integration/all/mqtt/device-page/setup/FeatureTab.jsx b/front/src/routes/integration/all/mqtt/device-page/setup/FeatureTab.jsx index 1e5e5e3cca..9cbcd70e98 100644 --- a/front/src/routes/integration/all/mqtt/device-page/setup/FeatureTab.jsx +++ b/front/src/routes/integration/all/mqtt/device-page/setup/FeatureTab.jsx @@ -36,6 +36,21 @@ const FeatureTab = ({ children, ...props }) => ( )} + {props.saveStatus === RequestStatus.ValidationError && ( +
+ + {props.erroredAttributes.length > 0 && ( +

+ {props.erroredAttributes.map(attribute => ( + <> +
+ - + + ))} +

+ )} +
+ )} {props.saveStatus === RequestStatus.ConflictError && (
diff --git a/front/src/routes/integration/all/mqtt/device-page/setup/index.js b/front/src/routes/integration/all/mqtt/device-page/setup/index.js index 1b605644bd..263696d290 100644 --- a/front/src/routes/integration/all/mqtt/device-page/setup/index.js +++ b/front/src/routes/integration/all/mqtt/device-page/setup/index.js @@ -210,16 +210,26 @@ class MqttDeviceSetupPage extends Component { } catch (e) { const status = get(e, 'response.status'); if (status === 409) { - this.setState({ + await this.setState({ saveStatus: RequestStatus.ConflictError, loading: false }); + } + if (status === 422) { + const properties = get(e, 'response.data.properties', []); + await this.setState({ + saveStatus: RequestStatus.ValidationError, + erroredAttributes: properties.map(p => p.attribute).filter(a => a !== 'selector'), + loading: false + }); } else { - this.setState({ + await this.setState({ saveStatus: RequestStatus.Error, loading: false }); } + // Scroll to top so the user sees the error + window.scrollTo(0, 0); } }