feat: Support Regex validation for custom attributes (#7856)

This allows a user to add/update a custom regex and a cue while defining custom attributes(Only applicable for type- text).
While adding/editing custom attributes, the values are validated against the attribute definition regex, and if it is incorrect, a cue message or default error message is shown and restricts invalid values from being saved.

Fixes: #6866
This commit is contained in:
Surabhi Suman
2024-01-23 19:31:57 +05:30
committed by GitHub
parent 834c219b9b
commit 4b40c61201
20 changed files with 247 additions and 22 deletions

View File

@@ -11,6 +11,8 @@
emoji=""
:value="attribute.value"
:show-actions="true"
:attribute-regex="attribute.regex_pattern"
:regex-cue="attribute.regex_cue"
:class="attributeClass"
@update="onUpdate"
@delete="onDelete"

View File

@@ -86,6 +86,30 @@
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.TYPE.LIST.ERROR') }}
</label>
</div>
<div v-if="isAttributeTypeText">
<input
v-model="regexEnabled"
type="checkbox"
@input="toggleRegexEnabled"
/>
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.ENABLE_REGEX.LABEL') }}
</div>
<woot-input
v-if="isAttributeTypeText && isRegexEnabled"
v-model="regexPattern"
:label="$t('ATTRIBUTES_MGMT.ADD.FORM.REGEX_PATTERN.LABEL')"
type="text"
:placeholder="
$t('ATTRIBUTES_MGMT.ADD.FORM.REGEX_PATTERN.PLACEHOLDER')
"
/>
<woot-input
v-if="isAttributeTypeText && isRegexEnabled"
v-model="regexCue"
:label="$t('ATTRIBUTES_MGMT.ADD.FORM.REGEX_CUE.LABEL')"
type="text"
:placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.REGEX_CUE.PLACEHOLDER')"
/>
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full">
<woot-submit-button
:disabled="isButtonDisabled"
@@ -124,6 +148,9 @@ export default {
attributeModel: 0,
attributeType: 0,
attributeKey: '',
regexPattern: null,
regexCue: null,
regexEnabled: false,
models: ATTRIBUTE_MODELS,
types: ATTRIBUTE_TYPES,
values: [],
@@ -163,6 +190,12 @@ export default {
isAttributeTypeList() {
return this.attributeType === 6;
},
isAttributeTypeText() {
return this.attributeType === 0;
},
isRegexEnabled() {
return this.regexEnabled;
},
},
validations: {
@@ -201,11 +234,18 @@ export default {
onDisplayNameChange() {
this.attributeKey = convertToAttributeSlug(this.displayName);
},
toggleRegexEnabled() {
this.regexEnabled = !this.regexEnabled;
},
async addAttributes() {
this.$v.$touch();
if (this.$v.$invalid) {
return;
}
if (!this.regexEnabled) {
this.regexPattern = null;
this.regexCue = null;
}
try {
await this.$store.dispatch('attributes/create', {
attribute_display_name: this.displayName,
@@ -214,6 +254,10 @@ export default {
attribute_display_type: this.attributeType,
attribute_key: this.attributeKey,
attribute_values: this.attributeListValues,
regex_pattern: this.regexPattern
? new RegExp(this.regexPattern).toString()
: null,
regex_cue: this.regexCue,
});
this.alertMessage = this.$t('ATTRIBUTES_MGMT.ADD.API.SUCCESS_MESSAGE');
this.onClose();

View File

@@ -70,6 +70,30 @@
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.TYPE.LIST.ERROR') }}
</label>
</div>
<div v-if="isAttributeTypeText">
<input
v-model="regexEnabled"
type="checkbox"
@input="toggleRegexEnabled"
/>
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.ENABLE_REGEX.LABEL') }}
</div>
<woot-input
v-if="isAttributeTypeText && isRegexEnabled"
v-model="regexPattern"
:label="$t('ATTRIBUTES_MGMT.ADD.FORM.REGEX_PATTERN.LABEL')"
type="text"
:placeholder="
$t('ATTRIBUTES_MGMT.ADD.FORM.REGEX_PATTERN.PLACEHOLDER')
"
/>
<woot-input
v-if="isAttributeTypeText && isRegexEnabled"
v-model="regexCue"
:label="$t('ATTRIBUTES_MGMT.ADD.FORM.REGEX_CUE.LABEL')"
type="text"
:placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.REGEX_CUE.PLACEHOLDER')"
/>
</div>
<div class="flex flex-row justify-end gap-2 py-2 px-0 w-full">
<woot-button :is-loading="isUpdating" :disabled="isButtonDisabled">
@@ -88,9 +112,10 @@ import { mapGetters } from 'vuex';
import { required, minLength } from 'vuelidate/lib/validators';
import { ATTRIBUTE_TYPES } from './constants';
import alertMixin from 'shared/mixins/alertMixin';
import customAttributeMixin from '../../../../mixins/customAttributeMixin';
export default {
components: {},
mixins: [alertMixin],
mixins: [alertMixin, customAttributeMixin],
props: {
selectedAttribute: {
type: Object,
@@ -106,6 +131,9 @@ export default {
displayName: '',
description: '',
attributeType: 0,
regexPattern: null,
regexCue: null,
regexEnabled: false,
types: ATTRIBUTE_TYPES,
show: true,
attributeKey: '',
@@ -152,6 +180,7 @@ export default {
this.isAttributeTypeList && this.isTouched && this.values.length === 0
);
},
pageTitle() {
return `${this.$t('ATTRIBUTES_MGMT.EDIT.TITLE')} - ${
this.selectedAttribute.attribute_display_name
@@ -173,6 +202,12 @@ export default {
isAttributeTypeList() {
return this.attributeType === 6;
},
isAttributeTypeText() {
return this.attributeType === 0;
},
isRegexEnabled() {
return this.regexEnabled;
},
},
mounted() {
this.setFormValues();
@@ -189,10 +224,16 @@ export default {
this.$refs.tagInput.$el.focus();
},
setFormValues() {
const regexPattern = this.selectedAttribute.regex_pattern
? this.getRegexp(this.selectedAttribute.regex_pattern).source
: null;
this.displayName = this.selectedAttribute.attribute_display_name;
this.description = this.selectedAttribute.attribute_description;
this.attributeType = this.selectedAttributeType;
this.attributeKey = this.selectedAttribute.attribute_key;
this.regexPattern = regexPattern;
this.regexCue = this.selectedAttribute.regex_cue;
this.regexEnabled = regexPattern != null;
this.values = this.setAttributeListValue;
},
async editAttributes() {
@@ -200,14 +241,21 @@ export default {
if (this.$v.$invalid) {
return;
}
if (!this.regexEnabled) {
this.regexPattern = null;
this.regexCue = null;
}
try {
await this.$store.dispatch('attributes/update', {
id: this.selectedAttribute.id,
attribute_description: this.description,
attribute_display_name: this.displayName,
attribute_values: this.updatedAttributeListValues,
regex_pattern: this.regexPattern
? new RegExp(this.regexPattern).toString()
: null,
regex_cue: this.regexCue,
});
this.alertMessage = this.$t('ATTRIBUTES_MGMT.EDIT.API.SUCCESS_MESSAGE');
this.onClose();
} catch (error) {
@@ -218,6 +266,9 @@ export default {
this.showAlert(this.alertMessage);
}
},
toggleRegexEnabled() {
this.regexEnabled = !this.regexEnabled;
},
},
};
</script>