You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ma...@apache.org on 2021/06/08 21:07:16 UTC

[airavata-django-portal] 04/04: AIRAVATA-3455 user profile editor form validation

This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch AIRAVATA-3319-handle-missing-name-and-email-attributes-from-cilo
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit 125fd07daf33219ac37daec086089aa54e3e9901
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Tue Jun 8 17:06:16 2021 -0400

    AIRAVATA-3455 user profile editor form validation
---
 django_airavata/apps/auth/package.json             |  3 +-
 .../js/components/UserProfileEditor.vue            | 51 +++++++++++++++++++---
 django_airavata/apps/auth/yarn.lock                |  5 +++
 .../static/common/js/errors/vuelidateHelpers.js    |  4 ++
 django_airavata/static/common/js/index.js          |  4 +-
 5 files changed, 60 insertions(+), 7 deletions(-)

diff --git a/django_airavata/apps/auth/package.json b/django_airavata/apps/auth/package.json
index 35f28ac..ad7b2fe 100644
--- a/django_airavata/apps/auth/package.json
+++ b/django_airavata/apps/auth/package.json
@@ -15,7 +15,8 @@
     "bootstrap-vue": "2.0.0-rc.26",
     "django-airavata-api": "link:../api/",
     "django-airavata-common-ui": "link:../../static/common/",
-    "vue": "^2.5.21"
+    "vue": "^2.5.21",
+    "vuelidate": "^0.7.6"
   },
   "devDependencies": {
     "@vue/cli-plugin-babel": "^3.1.1",
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/UserProfileEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/UserProfileEditor.vue
index 55eca90..506114c 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/components/UserProfileEditor.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/components/UserProfileEditor.vue
@@ -4,13 +4,28 @@
       <b-form-input disabled :value="user.username" />
     </b-form-group>
     <b-form-group label="First Name">
-      <b-form-input v-model="user.first_name" @keydown.native.enter="save" />
+      <b-form-input
+        v-model="$v.user.first_name.$model"
+        @keydown.native.enter="save"
+        :state="validateState($v.user.first_name)"
+      />
     </b-form-group>
     <b-form-group label="Last Name">
-      <b-form-input v-model="user.last_name" @keydown.native.enter="save" />
+      <b-form-input
+        v-model="$v.user.last_name.$model"
+        @keydown.native.enter="save"
+        :state="validateState($v.user.last_name)"
+      />
     </b-form-group>
     <b-form-group label="Email">
-      <b-form-input v-model="user.email" @keydown.native.enter="save" />
+      <b-form-input
+        v-model="$v.user.email.$model"
+        @keydown.native.enter="save"
+        :state="validateState($v.user.email)"
+      />
+      <b-form-invalid-feedback v-if="!$v.user.email.email">
+        {{ user.email }} is not a valid email address.
+      </b-form-invalid-feedback>
       <b-alert class="mt-1" show v-if="user.pending_email_change"
         >Once you verify your email address at
         <strong>{{ user.pending_email_change.email_address }}</strong
@@ -21,14 +36,21 @@
         ></b-alert
       >
     </b-form-group>
-    <b-button variant="primary" @click="save">Save</b-button>
+    <b-button variant="primary" @click="save" :disabled="$v.$invalid"
+      >Save</b-button
+    >
   </b-card>
 </template>
 
 <script>
 import { models } from "django-airavata-api";
+import { errors } from "django-airavata-common-ui";
+import { validationMixin } from "vuelidate";
+import { email, required } from "vuelidate/lib/validators";
+
 export default {
   name: "user-profile-editor",
+  mixins: [validationMixin],
   props: {
     value: {
       type: models.User,
@@ -40,13 +62,32 @@ export default {
       user: this.cloneValue(),
     };
   },
+  validations() {
+    return {
+      user: {
+        first_name: {
+          required,
+        },
+        last_name: {
+          required,
+        },
+        email: {
+          required,
+          email,
+        },
+      },
+    };
+  },
   methods: {
     cloneValue() {
       return JSON.parse(JSON.stringify(this.value));
     },
     save() {
-      this.$emit("save", this.user);
+      if (!this.$v.$invalid) {
+        this.$emit("save", this.user);
+      }
     },
+    validateState: errors.vuelidateHelpers.validateState,
   },
   watch: {
     value() {
diff --git a/django_airavata/apps/auth/yarn.lock b/django_airavata/apps/auth/yarn.lock
index 8631cdf..f24af85 100644
--- a/django_airavata/apps/auth/yarn.lock
+++ b/django_airavata/apps/auth/yarn.lock
@@ -8361,6 +8361,11 @@ vue@^2.5.21, vue@^2.5.22:
   resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.12.tgz#f5ebd4fa6bd2869403e29a896aed4904456c9123"
   integrity sha512-uhmLFETqPPNyuLLbsKz6ioJ4q7AZHzD8ZVFNATNyICSZouqP2Sz0rotWQC8UNBF6VGSCs5abnKJoStA6JbCbfg==
 
+vuelidate@^0.7.6:
+  version "0.7.6"
+  resolved "https://registry.yarnpkg.com/vuelidate/-/vuelidate-0.7.6.tgz#84100c13b943470660d0416642845cd2a1edf4b2"
+  integrity sha512-suzIuet1jGcyZ4oUSW8J27R2tNrJ9cIfklAh63EbAkFjE380iv97BAiIeolRYoB9bF9usBXCu4BxftWN1Dkn3g==
+
 watchpack-chokidar2@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz#9948a1866cbbd6cb824dea13a7ed691f6c8ddff0"
diff --git a/django_airavata/static/common/js/errors/vuelidateHelpers.js b/django_airavata/static/common/js/errors/vuelidateHelpers.js
new file mode 100644
index 0000000..3f43183
--- /dev/null
+++ b/django_airavata/static/common/js/errors/vuelidateHelpers.js
@@ -0,0 +1,4 @@
+export function validateState(validation) {
+  const { $dirty, $error } = validation;
+  return $dirty ? !$error : null;
+}
diff --git a/django_airavata/static/common/js/index.js b/django_airavata/static/common/js/index.js
index 0e69a1b..ac905a9 100644
--- a/django_airavata/static/common/js/index.js
+++ b/django_airavata/static/common/js/index.js
@@ -26,6 +26,7 @@ import ValidatedFormGroup from "./components/ValidatedFormGroup";
 
 import GlobalErrorHandler from "./errors/GlobalErrorHandler";
 import ValidationErrors from "./errors/ValidationErrors";
+import * as vuelidateHelpers from "./errors/vuelidateHelpers.js";
 
 import ListLayout from "./layouts/ListLayout.vue";
 
@@ -63,12 +64,13 @@ const components = {
   UnsavedChangesGuard,
   Uppy,
   ValidatedForm,
-  ValidatedFormGroup
+  ValidatedFormGroup,
 };
 
 const errors = {
   GlobalErrorHandler,
   ValidationErrors,
+  vuelidateHelpers,
 };
 
 const layouts = {