From d4f3fba56e66a9316f2641f2f21196367c571db1 Mon Sep 17 00:00:00 2001
From: claire bontempo <68122737+hellobontempo@users.noreply.github.com>
Date: Wed, 25 May 2022 11:22:36 -0700
Subject: [PATCH] UI/Fix form validation issues (#15560)
* clean up validators
* fix getter overriding user input
* add changelog
* remove asString option
* move invalid check up
* remove asString everywhere
* revert input value defaults
* undo form disabling if validation errors
* address comments
* remove or
* add validation message to form, create pseudo loading icon
* whole alert disappears with refresh
* glimmerize alert-inline
* add tests
* rename variables for consistency
* spread attributes to glimmerized component
* address comments
* add validation test
---
changelog/15560.txt | 3 +
ui/app/components/mount-backend-form.js | 23 ++++--
ui/app/decorators/model-validations.js | 12 ++-
ui/app/models/secret-engine.js | 2 +-
ui/app/models/secret-v2.js | 2 +-
.../components/mount-backend-form.hbs | 7 +-
ui/app/utils/validators.js | 22 +++---
ui/lib/core/addon/components/alert-inline.hbs | 19 +++++
ui/lib/core/addon/components/alert-inline.js | 65 ++++++++++------
ui/lib/core/addon/components/form-field.js | 2 +-
.../templates/components/alert-inline.hbs | 8 --
.../components/alert-inline-test.js | 77 +++++++++++++++++--
.../unit/decorators/model-validations-test.js | 29 +++++++
ui/tests/unit/utils/validators-test.js | 44 ++++++++---
14 files changed, 245 insertions(+), 70 deletions(-)
create mode 100644 changelog/15560.txt
create mode 100644 ui/lib/core/addon/components/alert-inline.hbs
delete mode 100644 ui/lib/core/addon/templates/components/alert-inline.hbs
diff --git a/changelog/15560.txt b/changelog/15560.txt
new file mode 100644
index 000000000..387d2a848
--- /dev/null
+++ b/changelog/15560.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+ui: fix form validations ignoring default values and disabling submit button
+```
diff --git a/ui/app/components/mount-backend-form.js b/ui/app/components/mount-backend-form.js
index b23a7ffc5..263981141 100644
--- a/ui/app/components/mount-backend-form.js
+++ b/ui/app/components/mount-backend-form.js
@@ -47,7 +47,7 @@ export default Component.extend({
// validation related properties
modelValidations: null,
- isFormInvalid: false,
+ invalidFormAlert: null,
mountIssue: false,
@@ -88,10 +88,24 @@ export default Component.extend({
}
},
+ checkModelValidity(model) {
+ const { isValid, state, invalidFormMessage } = model.validate();
+ this.setProperties({
+ modelValidations: state,
+ invalidFormAlert: invalidFormMessage,
+ });
+
+ return isValid;
+ },
+
mountBackend: task(
waitFor(function* () {
const mountModel = this.mountModel;
const { type, path } = mountModel;
+ // only submit form if validations pass
+ if (!this.checkModelValidity(mountModel)) {
+ return;
+ }
let capabilities = null;
try {
capabilities = yield this.store.findRecord('capabilities', `${path}/config`);
@@ -120,7 +134,6 @@ export default Component.extend({
} catch (err) {
if (err.httpStatus === 403) {
this.mountIssue = true;
- this.set('isFormInvalid', this.mountIssue);
this.flashMessages.danger(
'You do not have access to the sys/mounts endpoint. The secret engine was not mounted.'
);
@@ -163,12 +176,8 @@ export default Component.extend({
actions: {
onKeyUp(name, value) {
this.mountModel.set(name, value);
- const { isValid, state } = this.mountModel.validate();
- this.setProperties({
- modelValidations: state,
- isFormInvalid: !isValid,
- });
},
+
onTypeChange(path, value) {
if (path === 'type') {
this.wizard.set('componentState', value);
diff --git a/ui/app/decorators/model-validations.js b/ui/app/decorators/model-validations.js
index fae6e8f70..8520811da 100644
--- a/ui/app/decorators/model-validations.js
+++ b/ui/app/decorators/model-validations.js
@@ -69,6 +69,7 @@ export function withModelValidations(validations) {
validate() {
let isValid = true;
const state = {};
+ let errorCount = 0;
for (const key in this._validations) {
const rules = this._validations[key];
@@ -110,9 +111,18 @@ export function withModelValidations(validations) {
}
}
}
+ errorCount += state[key].errors.length;
state[key].isValid = !state[key].errors.length;
}
- return { isValid, state };
+
+ return { isValid, state, invalidFormMessage: this.generateErrorCountMessage(errorCount) };
+ }
+
+ generateErrorCountMessage(errorCount) {
+ if (errorCount < 1) return null;
+ // returns count specific message: 'There is an error/are N errors with this form.'
+ let isPlural = errorCount > 1 ? `are ${errorCount} errors` : false;
+ return `There ${isPlural ? isPlural : 'is an error'} with this form.`;
}
};
};
diff --git a/ui/app/models/secret-engine.js b/ui/app/models/secret-engine.js
index a51983fd8..2fb064c37 100644
--- a/ui/app/models/secret-engine.js
+++ b/ui/app/models/secret-engine.js
@@ -12,7 +12,7 @@ const LIST_EXCLUDED_BACKENDS = ['system', 'identity'];
const validations = {
path: [{ type: 'presence', message: "Path can't be blank." }],
maxVersions: [
- { type: 'number', options: { asString: true }, message: 'Maximum versions must be a number.' },
+ { type: 'number', message: 'Maximum versions must be a number.' },
{ type: 'length', options: { min: 1, max: 16 }, message: 'You cannot go over 16 characters.' },
],
};
diff --git a/ui/app/models/secret-v2.js b/ui/app/models/secret-v2.js
index 1f95d6e3d..c4945fcce 100644
--- a/ui/app/models/secret-v2.js
+++ b/ui/app/models/secret-v2.js
@@ -8,7 +8,7 @@ import { withModelValidations } from 'vault/decorators/model-validations';
const validations = {
maxVersions: [
- { type: 'number', options: { asString: true }, message: 'Maximum versions must be a number.' },
+ { type: 'number', message: 'Maximum versions must be a number.' },
{ type: 'length', options: { min: 1, max: 16 }, message: 'You cannot go over 16 characters.' },
],
};
diff --git a/ui/app/templates/components/mount-backend-form.hbs b/ui/app/templates/components/mount-backend-form.hbs
index 10f2a8a47..4bc343cb7 100644
--- a/ui/app/templates/components/mount-backend-form.hbs
+++ b/ui/app/templates/components/mount-backend-form.hbs
@@ -67,7 +67,7 @@
type="submit"
data-test-mount-submit="true"
class="button is-primary {{if this.mountBackend.isRunning 'loading'}}"
- disabled={{or this.mountBackend.isRunning this.isFormInvalid}}
+ disabled={{this.mountBackend.isRunning}}
>
{{#if (eq this.mountType "auth")}}
Enable Method
@@ -81,6 +81,11 @@
Back
+ {{#if this.invalidFormAlert}}
+
+ {{/if}}
{{else}}