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 2022/06/03 20:11:54 UTC

[airavata-django-portal] 01/08: AIRAVATA-3564 Save common extended user profile fields

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

machristie pushed a commit to branch AIRAVATA-3562
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit 5b7b9b712265108e86f1ab58d371a45986be27f4
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Tue May 24 12:33:25 2022 -0400

    AIRAVATA-3564 Save common extended user profile fields
---
 .../users/ExtendedUserProfileContainer.vue         | 75 +++--------------
 .../ExtendedUserProfileFieldEditor.vue             | 98 ++++++++++++++++++++++
 .../src/store/modules/extendedUserProfile.js       | 35 ++++++++
 .../js/models/ExtendedUserProfileField.js          | 24 ++++++
 .../js/components/ExtendedUserProfileEditor.vue    | 16 ++--
 ... ExtendedUserProfileMultiChoiceValueEditor.vue} |  8 +-
 ...ExtendedUserProfileSingleChoiceValueEditor.vue} |  8 +-
 ....vue => ExtendedUserProfileTextValueEditor.vue} |  8 +-
 ...xtendedUserProfileUserAgreementValueEditor.vue} |  8 +-
 ...itor.vue => ExtendedUserProfileValueEditor.vue} |  0
 .../js/store/modules/extendedUserProfile.js        |  2 +-
 11 files changed, 192 insertions(+), 90 deletions(-)

diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/ExtendedUserProfileContainer.vue b/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/ExtendedUserProfileContainer.vue
index e813f737..2bd39ae6 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/ExtendedUserProfileContainer.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/ExtendedUserProfileContainer.vue
@@ -7,61 +7,7 @@
     </div>
     <div v-for="field in extendedUserProfileFields" class="row" :key="field.id">
       <div class="col">
-        <b-card :title="'Field: ' + field.name">
-          <b-form-group label="Name">
-            <b-form-input v-model="field.name" />
-          </b-form-group>
-          <b-form-group label="Help text">
-            <b-form-input v-model="field.help_text" />
-          </b-form-group>
-          <b-form-group label="Required">
-            <b-form-checkbox v-model="field.required" />
-          </b-form-group>
-          <b-form-group label="Type">
-            <b-form-select
-              v-model="field.field_type"
-              :options="fieldTypeOptions"
-            />
-          </b-form-group>
-          <b-card
-            title="Options"
-            v-if="
-              field.field_type === 'single_choice' ||
-              field.field_type === 'multi_choice'
-            "
-          >
-            <template v-for="choice in field.choices">
-              <b-input-group :key="choice.id">
-                <b-form-input v-model="choice.display_text" />
-                <b-input-group-append>
-                  <b-button @click="deleteOption(field, choice)"
-                    >Delete</b-button
-                  >
-                </b-input-group-append>
-              </b-input-group>
-            </template>
-            <b-button @click="addOption(field)">Add Option</b-button>
-          </b-card>
-          <template v-if="field.links && field.links.length > 0">
-            <b-card title="Links" v-for="link in field.links" :key="link.id">
-              <b-form-group label="Label">
-                <b-form-input v-model="link.label" />
-              </b-form-group>
-              <b-form-group label="URL">
-                <b-form-input v-model="link.url" />
-              </b-form-group>
-              <b-form-group label="Show as link?">
-                <b-form-checkbox v-model="link.display_link" />
-              </b-form-group>
-              <b-form-group label="Show inline?">
-                <b-form-checkbox v-model="link.display_inline" />
-              </b-form-group>
-            </b-card>
-          </template>
-          <b-button v-if="!field.links" @click="addLink(field)"
-            >Add Link</b-button
-          >
-        </b-card>
+        <extended-user-profile-field-editor :extendedUserProfileField="field" />
       </div>
     </div>
     <div class="row">
@@ -79,7 +25,9 @@
 
 <script>
 import { mapActions, mapGetters } from "vuex";
+import ExtendedUserProfileFieldEditor from "./field-editors/ExtendedUserProfileFieldEditor.vue";
 export default {
+  components: { ExtendedUserProfileFieldEditor },
   data() {
     return {
       fields: [],
@@ -89,7 +37,10 @@ export default {
     this.loadExtendedUserProfileFields();
   },
   methods: {
-    ...mapActions("extendedUserProfile", ["loadExtendedUserProfileFields"]),
+    ...mapActions("extendedUserProfile", [
+      "loadExtendedUserProfileFields",
+      "saveExtendedUserProfileFields",
+    ]),
     addField() {
       // TODO: post an empty field to the API
       this.fields.push({
@@ -138,18 +89,12 @@ export default {
       const i = field.links.indexOf(link);
       field.links.splice(i, 1);
     },
-    save() {},
+    save() {
+      this.saveExtendedUserProfileFields();
+    },
   },
   computed: {
     ...mapGetters("extendedUserProfile", ["extendedUserProfileFields"]),
-    fieldTypeOptions() {
-      return [
-        { value: "text", text: "Text" },
-        { value: "single_choice", text: "Single Choice" },
-        { value: "multi_choice", text: "Multi Choice" },
-        { value: "user_agreement", text: "User Agreement" },
-      ];
-    },
   },
 };
 </script>
diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/field-editors/ExtendedUserProfileFieldEditor.vue b/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/field-editors/ExtendedUserProfileFieldEditor.vue
new file mode 100644
index 00000000..5b19426b
--- /dev/null
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/users/field-editors/ExtendedUserProfileFieldEditor.vue
@@ -0,0 +1,98 @@
+<template>
+  <b-card :title="'Field: ' + name">
+    <b-form-group label="Name">
+      <b-form-input v-model="name" />
+    </b-form-group>
+    <b-form-group label="Help text">
+      <b-form-input v-model="help_text" />
+    </b-form-group>
+    <b-form-group label="Required">
+      <b-form-checkbox v-model="required" />
+    </b-form-group>
+    <!-- <b-card
+            title="Options"
+            v-if="
+              field.field_type === 'single_choice' ||
+              field.field_type === 'multi_choice'
+            "
+          >
+            <template v-for="choice in field.choices">
+              <b-input-group :key="choice.id">
+                <b-form-input v-model="choice.display_text" />
+                <b-input-group-append>
+                  <b-button @click="deleteOption(field, choice)"
+                    >Delete</b-button
+                  >
+                </b-input-group-append>
+              </b-input-group>
+            </template>
+            <b-button @click="addOption(field)">Add Option</b-button>
+          </b-card>
+          <template v-if="field.links && field.links.length > 0">
+            <b-card title="Links" v-for="link in field.links" :key="link.id">
+              <b-form-group label="Label">
+                <b-form-input v-model="link.label" />
+              </b-form-group>
+              <b-form-group label="URL">
+                <b-form-input v-model="link.url" />
+              </b-form-group>
+              <b-form-group label="Show as link?">
+                <b-form-checkbox v-model="link.display_link" />
+              </b-form-group>
+              <b-form-group label="Show inline?">
+                <b-form-checkbox v-model="link.display_inline" />
+              </b-form-group>
+            </b-card>
+          </template>
+          <b-button v-if="!field.links" @click="addLink(field)"
+            >Add Link</b-button
+          > -->
+  </b-card>
+</template>
+
+<script>
+import { mapMutations } from "vuex";
+export default {
+  props: ["extendedUserProfileField"],
+  computed: {
+    name: {
+      get() {
+        return this.extendedUserProfileField.name;
+      },
+      set(value) {
+        this.setName({ value, field: this.extendedUserProfileField });
+      },
+    },
+    help_text: {
+      get() {
+        return this.extendedUserProfileField.help_text;
+      },
+      set(value) {
+        this.setHelpText({ value, field: this.extendedUserProfileField });
+      },
+    },
+    required: {
+      get() {
+        return this.extendedUserProfileField.required;
+      },
+      set(value) {
+        this.setRequired({ value, field: this.extendedUserProfileField });
+      },
+    },
+    // TODO: probably don't need these
+    fieldTypeOptions() {
+      return [
+        { value: "text", text: "Text" },
+        { value: "single_choice", text: "Single Choice" },
+        { value: "multi_choice", text: "Multi Choice" },
+        { value: "user_agreement", text: "User Agreement" },
+      ];
+    },
+  },
+  methods: {
+    ...mapMutations("extendedUserProfile", ["setName", "setHelpText", "setRequired"]),
+  },
+};
+</script>
+
+<style></style>
diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/store/modules/extendedUserProfile.js b/django_airavata/apps/admin/static/django_airavata_admin/src/store/modules/extendedUserProfile.js
index 2e3eefc2..decd3d89 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/store/modules/extendedUserProfile.js
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/store/modules/extendedUserProfile.js
@@ -13,12 +13,47 @@ const actions = {
     const extendedUserProfileFields = await services.ExtendedUserProfileFieldService.list();
     commit("setExtendedUserProfileFields", { extendedUserProfileFields });
   },
+  async saveExtendedUserProfileFields({ dispatch, state }) {
+    for (const field of state.extendedUserProfileFields) {
+      // Create or update each field
+      if (field.id) {
+        await services.ExtendedUserProfileFieldService.update({
+          lookup: field.id,
+          data: field,
+        });
+      } else {
+        await services.ExtendedUserProfileFieldService.create({ data: field });
+      }
+    }
+    // Reload the fields
+    dispatch("loadExtendedUserProfileFields");
+  },
 };
 
+function getField(state, field) {
+  const extendedUserProfileField = state.extendedUserProfileFields.find(
+    (f) => f === field
+  );
+  return extendedUserProfileField;
+}
+function setFieldProp(state, field, prop, value) {
+  const extendedUserProfileField = getField(state, field);
+  extendedUserProfileField[prop] = value;
+}
+
 const mutations = {
   setExtendedUserProfileFields(state, { extendedUserProfileFields }) {
     state.extendedUserProfileFields = extendedUserProfileFields;
   },
+  setName(state, { value, field }) {
+    setFieldProp(state, field, "name", value);
+  },
+  setHelpText(state, { value, field }) {
+    setFieldProp(state, field, "help_text", value);
+  },
+  setRequired(state, { value, field }) {
+    setFieldProp(state, field, "required", value);
+  },
 };
 
 export default {
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/models/ExtendedUserProfileField.js b/django_airavata/apps/api/static/django_airavata_api/js/models/ExtendedUserProfileField.js
index 2eec7ac8..bef33e41 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/models/ExtendedUserProfileField.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/models/ExtendedUserProfileField.js
@@ -37,4 +37,28 @@ export default class ExtendedUserProfileField extends BaseModel {
   constructor(data = {}) {
     super(FIELDS, data);
   }
+  toJSON() {
+    const copy = Object.assign({}, this);
+    // Remove unnecessary properties
+    switch (this.field_type) {
+      case "text":
+        delete copy["other"];
+        delete copy["choices"];
+        delete copy["checkbox_label"];
+        break;
+      case "single_choice":
+      case "multi_choice":
+        delete copy["checkbox_label"];
+        break;
+      case "user_agreement":
+        delete copy["other"];
+        delete copy["choices"];
+        break;
+      default:
+        // eslint-disable-next-line no-console
+        console.error("Unrecognized field type", this.field_type);
+        break;
+    }
+    return copy;
+  }
 }
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileEditor.vue
index 0b0b08d8..aaf9fc7f 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileEditor.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileEditor.vue
@@ -15,10 +15,10 @@
 
 <script>
 import { mapGetters } from "vuex";
-import ExtendedUserProfileMultiChoiceFieldEditor from "./ExtendedUserProfileMultiChoiceFieldEditor.vue";
-import ExtendedUserProfileSingleChoiceFieldEditor from "./ExtendedUserProfileSingleChoiceFieldEditor.vue";
-import ExtendedUserProfileTextFieldEditor from "./ExtendedUserProfileTextFieldEditor.vue";
-import ExtendedUserProfileUserAgreementFieldEditor from "./ExtendedUserProfileUserAgreementFieldEditor.vue";
+import ExtendedUserProfileMultiChoiceValueEditor from "./ExtendedUserProfileMultiChoiceValueEditor.vue";
+import ExtendedUserProfileSingleChoiceValueEditor from "./ExtendedUserProfileSingleChoiceValueEditor.vue";
+import ExtendedUserProfileTextValueEditor from "./ExtendedUserProfileTextValueEditor.vue";
+import ExtendedUserProfileUserAgreementValueEditor from "./ExtendedUserProfileUserAgreementValueEditor.vue";
 import { mixins } from "django-airavata-common-ui";
 export default {
   mixins: [mixins.ValidationParent],
@@ -31,10 +31,10 @@ export default {
   methods: {
     getEditor(extendedUserProfileField) {
       const fieldTypeEditors = {
-        text: ExtendedUserProfileTextFieldEditor,
-        single_choice: ExtendedUserProfileSingleChoiceFieldEditor,
-        multi_choice: ExtendedUserProfileMultiChoiceFieldEditor,
-        user_agreement: ExtendedUserProfileUserAgreementFieldEditor,
+        text: ExtendedUserProfileTextValueEditor,
+        single_choice: ExtendedUserProfileSingleChoiceValueEditor,
+        multi_choice: ExtendedUserProfileMultiChoiceValueEditor,
+        user_agreement: ExtendedUserProfileUserAgreementValueEditor,
       };
 
       if (extendedUserProfileField.field_type in fieldTypeEditors) {
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileMultiChoiceFieldEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileMultiChoiceValueEditor.vue
similarity index 94%
rename from django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileMultiChoiceFieldEditor.vue
rename to django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileMultiChoiceValueEditor.vue
index 9e99fb7f..9905c89f 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileMultiChoiceFieldEditor.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileMultiChoiceValueEditor.vue
@@ -1,5 +1,5 @@
 <template>
-  <extended-user-profile-field-editor v-bind="$props">
+  <extended-user-profile-value-editor v-bind="$props">
     <b-form-checkbox-group
       v-model="value"
       :options="options"
@@ -29,7 +29,7 @@
         >Please specify a value for 'Other'.</b-form-invalid-feedback
       >
     </template>
-  </extended-user-profile-field-editor>
+  </extended-user-profile-value-editor>
 </template>
 
 <script>
@@ -37,11 +37,11 @@ import { mapGetters, mapMutations } from "vuex";
 import { validationMixin } from "vuelidate";
 import { required, requiredIf } from "vuelidate/lib/validators";
 import { errors } from "django-airavata-common-ui";
-import ExtendedUserProfileFieldEditor from "./ExtendedUserProfileFieldEditor.vue";
+import ExtendedUserProfileValueEditor from "./ExtendedUserProfileValueEditor.vue";
 const OTHER_OPTION = new Object(); // sentinel value
 export default {
   mixins: [validationMixin],
-  components: { ExtendedUserProfileFieldEditor },
+  components: { ExtendedUserProfileValueEditor },
   props: ["extendedUserProfileField"],
   data() {
     return {
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileSingleChoiceFieldEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileSingleChoiceValueEditor.vue
similarity index 94%
rename from django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileSingleChoiceFieldEditor.vue
rename to django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileSingleChoiceValueEditor.vue
index 7bc1f26d..1ca3ef48 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileSingleChoiceFieldEditor.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileSingleChoiceValueEditor.vue
@@ -1,5 +1,5 @@
 <template>
-  <extended-user-profile-field-editor v-bind="$props">
+  <extended-user-profile-value-editor v-bind="$props">
     <b-form-select
       v-model="value"
       :options="options"
@@ -33,7 +33,7 @@
         >Please specify a value for 'Other'.</b-form-invalid-feedback
       >
     </template>
-  </extended-user-profile-field-editor>
+  </extended-user-profile-value-editor>
 </template>
 
 <script>
@@ -41,12 +41,12 @@ import { mapGetters, mapMutations } from "vuex";
 import { validationMixin } from "vuelidate";
 import { required, requiredIf } from "vuelidate/lib/validators";
 import { errors } from "django-airavata-common-ui";
-import ExtendedUserProfileFieldEditor from "./ExtendedUserProfileFieldEditor.vue";
+import ExtendedUserProfileValueEditor from "./ExtendedUserProfileValueEditor.vue";
 const OTHER_OPTION = new Object(); // sentinel value
 
 export default {
   mixins: [validationMixin],
-  components: { ExtendedUserProfileFieldEditor },
+  components: { ExtendedUserProfileValueEditor },
   props: ["extendedUserProfileField"],
   data() {
     return {
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileTextFieldEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileTextValueEditor.vue
similarity index 86%
rename from django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileTextFieldEditor.vue
rename to django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileTextValueEditor.vue
index 3e2a8e69..644ed825 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileTextFieldEditor.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileTextValueEditor.vue
@@ -1,10 +1,10 @@
 <template>
-  <extended-user-profile-field-editor v-bind="$props">
+  <extended-user-profile-value-editor v-bind="$props">
     <b-form-input v-model="value" :state="validateState($v.value)" />
     <b-form-invalid-feedback :state="validateState($v.value)"
       >This field is required.</b-form-invalid-feedback
     >
-  </extended-user-profile-field-editor>
+  </extended-user-profile-value-editor>
 </template>
 
 <script>
@@ -12,10 +12,10 @@ import { mapGetters, mapMutations } from "vuex";
 import { validationMixin } from "vuelidate";
 import { requiredIf } from "vuelidate/lib/validators";
 import { errors } from "django-airavata-common-ui";
-import ExtendedUserProfileFieldEditor from "./ExtendedUserProfileFieldEditor.vue";
+import ExtendedUserProfileValueEditor from "./ExtendedUserProfileValueEditor.vue";
 export default {
   mixins: [validationMixin],
-  components: { ExtendedUserProfileFieldEditor },
+  components: { ExtendedUserProfileValueEditor },
   props: ["extendedUserProfileField"],
   computed: {
     ...mapGetters("extendedUserProfile", ["getTextValue"]),
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileUserAgreementFieldEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileUserAgreementValueEditor.vue
similarity index 89%
rename from django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileUserAgreementFieldEditor.vue
rename to django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileUserAgreementValueEditor.vue
index d0fe40a4..035044d0 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileUserAgreementFieldEditor.vue
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileUserAgreementValueEditor.vue
@@ -1,5 +1,5 @@
 <template>
-  <extended-user-profile-field-editor v-bind="$props">
+  <extended-user-profile-value-editor v-bind="$props">
     <b-form-checkbox
       v-model="value"
       :unchecked-value="false"
@@ -11,18 +11,18 @@
     <b-form-invalid-feedback :state="validateState($v.value)"
       >This field is required.</b-form-invalid-feedback
     >
-  </extended-user-profile-field-editor>
+  </extended-user-profile-value-editor>
 </template>
 
 <script>
 import { mapGetters, mapMutations } from "vuex";
 import { validationMixin } from "vuelidate";
 import { errors } from "django-airavata-common-ui";
-import ExtendedUserProfileFieldEditor from "./ExtendedUserProfileFieldEditor.vue";
+import ExtendedUserProfileValueEditor from "./ExtendedUserProfileValueEditor.vue";
 
 export default {
   mixins: [validationMixin],
-  components: { ExtendedUserProfileFieldEditor },
+  components: { ExtendedUserProfileValueEditor },
   props: ["extendedUserProfileField"],
   computed: {
     ...mapGetters("extendedUserProfile", ["getUserAgreementValue"]),
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileFieldEditor.vue b/django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileValueEditor.vue
similarity index 100%
rename from django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileFieldEditor.vue
rename to django_airavata/apps/auth/static/django_airavata_auth/js/components/ExtendedUserProfileValueEditor.vue
diff --git a/django_airavata/apps/auth/static/django_airavata_auth/js/store/modules/extendedUserProfile.js b/django_airavata/apps/auth/static/django_airavata_auth/js/store/modules/extendedUserProfile.js
index 6e264490..9fef5c74 100644
--- a/django_airavata/apps/auth/static/django_airavata_auth/js/store/modules/extendedUserProfile.js
+++ b/django_airavata/apps/auth/static/django_airavata_auth/js/store/modules/extendedUserProfile.js
@@ -176,7 +176,7 @@ const mutations = {
       });
     }
   },
-  updateExperimentInputValue(state, { extendedUserProfileValue }) {
+  updateExtendedUserProfileValue(state, { extendedUserProfileValue }) {
     const index = state.extendedUserProfileValues.findIndex(
       (v) =>
         v.ext_user_profile_field ===