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:12:00 UTC
[airavata-django-portal] 07/08: AIRAVATA-3564 Adding validation to 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 0f94300ee1e3dc64efe013b3674e0ff350dfc657
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Fri Jun 3 15:38:55 2022 -0400
AIRAVATA-3564 Adding validation to extended user profile fields
---
.../users/ExtendedUserProfileContainer.vue | 11 +-
.../ExtendedUserProfileFieldEditor.vue | 168 +++++++++++++++------
2 files changed, 130 insertions(+), 49 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 66524084..e346c3cd 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
@@ -14,6 +14,8 @@
<div class="col">
<extended-user-profile-field-editor
:extendedUserProfileField="field"
+ @valid="recordValidChildComponent(field)"
+ @invalid="recordInvalidChildComponent(field)"
/>
</div>
</div>
@@ -36,7 +38,9 @@
</div>
<div class="row mt-4">
<div class="col">
- <b-button variant="primary" @click="save">Save</b-button>
+ <b-button variant="primary" @click="save" :disabled="!valid"
+ >Save</b-button
+ >
</div>
</div>
</div>
@@ -45,7 +49,9 @@
<script>
import { mapActions, mapGetters } from "vuex";
import ExtendedUserProfileFieldEditor from "./field-editors/ExtendedUserProfileFieldEditor.vue";
+import { mixins } from "django-airavata-common-ui";
export default {
+ mixins: [mixins.ValidationParent],
components: { ExtendedUserProfileFieldEditor },
data() {
return {};
@@ -105,6 +111,9 @@ export default {
},
computed: {
...mapGetters("extendedUserProfile", ["extendedUserProfileFields"]),
+ valid() {
+ return this.childComponentsAreValid;
+ },
},
};
</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
index e09a8d36..1e8f45ff 100644
--- 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
@@ -1,7 +1,10 @@
<template>
<b-card :title="title">
<b-form-group label="Name">
- <b-form-input v-model="name" />
+ <b-form-input v-model="name" :state="validateState($v.name)" />
+ <b-form-invalid-feedback :state="validateState($v.name)"
+ >This field is required.</b-form-invalid-feedback
+ >
</b-form-group>
<b-form-group label="Help text">
<b-form-input v-model="help_text" />
@@ -11,41 +14,56 @@
</b-form-group>
<b-card title="Options" v-if="extendedUserProfileField.supportsChoices">
<transition-group name="fade">
- <template v-for="(choice, index) in extendedUserProfileField.choices">
- <b-input-group :key="choice.key">
- <b-form-input
- :value="choice.display_text"
- @input="handleChoiceDisplayTextChanged(choice, $event)"
- />
- <b-input-group-append>
- <b-button
- @click="handleChoiceMoveUp(choice)"
- :disabled="index === 0"
- v-b-tooltip.hover.left
- title="Move Up"
- >
- <i class="fa fa-arrow-up" aria-hidden="true"></i>
- </b-button>
- <b-button
- @click="handleChoiceMoveDown(choice)"
- :disabled="
- index === extendedUserProfileField.choices.length - 1
+ <template
+ v-for="({ $model: choice, display_text: $v_display_text },
+ index) in $v.choices.$each.$iter"
+ >
+ <b-form-group :key="choice.key">
+ <b-input-group>
+ <b-form-input
+ :value="choice.display_text"
+ @input="
+ handleChoiceDisplayTextChanged(
+ choice,
+ $event,
+ $v_display_text
+ )
"
- v-b-tooltip.hover.left
- title="Move Down"
- >
- <i class="fa fa-arrow-down" aria-hidden="true"></i>
- </b-button>
- <b-button
- @click="handleChoiceDeleted(choice)"
- variant="danger"
- v-b-tooltip.hover.left
- title="Delete Option"
- >
- <i class="fa fa-trash" aria-hidden="true"></i>
- </b-button>
- </b-input-group-append>
- </b-input-group>
+ :state="validateState($v_display_text)"
+ />
+ <b-input-group-append>
+ <b-button
+ @click="handleChoiceMoveUp(choice)"
+ :disabled="index === 0"
+ v-b-tooltip.hover.left
+ title="Move Up"
+ >
+ <i class="fa fa-arrow-up" aria-hidden="true"></i>
+ </b-button>
+ <b-button
+ @click="handleChoiceMoveDown(choice)"
+ :disabled="
+ index === extendedUserProfileField.choices.length - 1
+ "
+ v-b-tooltip.hover.left
+ title="Move Down"
+ >
+ <i class="fa fa-arrow-down" aria-hidden="true"></i>
+ </b-button>
+ <b-button
+ @click="handleChoiceDeleted(choice)"
+ variant="danger"
+ v-b-tooltip.hover.left
+ title="Delete Option"
+ >
+ <i class="fa fa-trash" aria-hidden="true"></i>
+ </b-button>
+ </b-input-group-append>
+ </b-input-group>
+ <b-form-invalid-feedback :state="validateState($v_display_text)"
+ >This field is required.</b-form-invalid-feedback
+ >
+ </b-form-group>
</template>
<b-input-group :key="'other'" v-if="extendedUserProfileField.other">
<b-form-input placeholder="Please specify" disabled />
@@ -77,29 +95,33 @@
</b-form-checkbox>
</b-card>
- <template
- v-if="
- extendedUserProfileField.links &&
- extendedUserProfileField.links.length > 0
- "
- >
+ <template v-if="links && links.length > 0">
<transition-group name="fade">
<b-card
:title="`Link: ${link.label}`"
- v-for="link in extendedUserProfileField.links"
+ v-for="{ $model: link, label: $v_label, url: $v_url } in $v.links
+ .$each.$iter"
:key="link.key"
>
<b-form-group label="Label">
<b-form-input
:value="link.label"
- @input="handleLinkLabelChanged(link, $event)"
+ @input="handleLinkLabelChanged(link, $event, $v_label)"
+ :state="validateState($v_label)"
/>
+ <b-form-invalid-feedback :state="validateState($v_label)"
+ >This field is required.</b-form-invalid-feedback
+ >
</b-form-group>
<b-form-group label="URL">
<b-form-input
:value="link.url"
- @input="handleLinkURLChanged(link, $event)"
+ @input="handleLinkURLChanged(link, $event, $v_url)"
+ :state="validateState($v_url)"
/>
+ <b-form-invalid-feedback :state="validateState($v_url)"
+ >This field is required.</b-form-invalid-feedback
+ >
</b-form-group>
<b-form-group label="Show as link?">
<b-form-checkbox
@@ -142,8 +164,12 @@
</template>
<script>
-import { mapActions, mapGetters, mapMutations } from "vuex";
+import { mapGetters, mapMutations } from "vuex";
+import { validationMixin } from "vuelidate";
+import { required } from "vuelidate/lib/validators";
+import { errors } from "django-airavata-common-ui";
export default {
+ mixins: [validationMixin],
props: ["extendedUserProfileField"],
computed: {
...mapGetters("extendedUserProfile", ["extendedUserProfileFields"]),
@@ -153,6 +179,7 @@ export default {
},
set(value) {
this.setName({ value, field: this.extendedUserProfileField });
+ this.$v.name.$touch();
},
},
help_text: {
@@ -190,6 +217,39 @@ export default {
this.name
}`;
},
+ choices() {
+ return this.extendedUserProfileField.choices;
+ },
+ links() {
+ return this.extendedUserProfileField.links;
+ },
+ valid() {
+ return !this.$v.$invalid;
+ },
+ },
+ validations() {
+ return {
+ name: {
+ required,
+ },
+ choices: {
+ $each: {
+ display_text: {
+ required,
+ },
+ },
+ },
+ links: {
+ $each: {
+ label: {
+ required,
+ },
+ url: {
+ required,
+ },
+ },
+ },
+ };
},
methods: {
...mapMutations("extendedUserProfile", [
@@ -210,8 +270,9 @@ export default {
"updateFieldIndex",
"deleteField",
]),
- handleChoiceDisplayTextChanged(choice, display_text) {
+ handleChoiceDisplayTextChanged(choice, display_text, $v) {
this.updateChoiceDisplayText({ choice, display_text });
+ $v.$touch();
},
handleChoiceDeleted(choice) {
this.deleteChoice({ field: this.extendedUserProfileField, choice });
@@ -234,11 +295,13 @@ export default {
index,
});
},
- handleLinkLabelChanged(link, label) {
+ handleLinkLabelChanged(link, label, $v) {
this.updateLinkLabel({ link, label });
+ $v.$touch();
},
- handleLinkURLChanged(link, url) {
+ handleLinkURLChanged(link, url, $v) {
this.updateLinkURL({ link, url });
+ $v.$touch();
},
handleLinkDisplayLinkChanged(link, display_link) {
this.updateLinkDisplayLink({ link, display_link });
@@ -264,6 +327,15 @@ export default {
field: this.extendedUserProfileField,
});
},
+ validateState: errors.vuelidateHelpers.validateState,
+ },
+ watch: {
+ valid: {
+ handler(valid) {
+ this.$emit(valid ? "valid" : "invalid");
+ },
+ immediate: true,
+ },
},
};
</script>