feat: Add support for List and Checkbox in Custom Attributes (#3439)
This commit is contained in:
parent
0530e9491c
commit
da8f9d0337
9 changed files with 388 additions and 94 deletions
|
@ -2,77 +2,113 @@
|
||||||
<div class="custom-attribute">
|
<div class="custom-attribute">
|
||||||
<div class="title-wrap">
|
<div class="title-wrap">
|
||||||
<h4 class="text-block-title title error">
|
<h4 class="text-block-title title error">
|
||||||
<span class="attribute-name" :class="{ error: $v.editedValue.$error }">
|
<div v-if="isAttributeTypeCheckbox" class="checkbox-wrap">
|
||||||
{{ label }}
|
<input
|
||||||
</span>
|
v-model="editedValue"
|
||||||
|
class="checkbox"
|
||||||
|
type="checkbox"
|
||||||
|
@change="onUpdate"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="name-button__wrap">
|
||||||
|
<span
|
||||||
|
class="attribute-name"
|
||||||
|
:class="{ error: $v.editedValue.$error }"
|
||||||
|
>
|
||||||
|
{{ label }}
|
||||||
|
</span>
|
||||||
|
<woot-button
|
||||||
|
v-if="showActions"
|
||||||
|
v-tooltip.left="$t('CUSTOM_ATTRIBUTES.ACTIONS.DELETE')"
|
||||||
|
variant="link"
|
||||||
|
size="medium"
|
||||||
|
color-scheme="secondary"
|
||||||
|
icon="ion-trash-a"
|
||||||
|
class-names="delete-button"
|
||||||
|
@click="onDelete"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
<div v-show="isEditing">
|
<div v-if="notAttributeTypeCheckboxAndList">
|
||||||
<div class="input-group small">
|
<div v-show="isEditing">
|
||||||
<input
|
<div class="input-group small">
|
||||||
ref="inputfield"
|
<input
|
||||||
v-model="editedValue"
|
ref="inputfield"
|
||||||
:type="inputType"
|
v-model="editedValue"
|
||||||
class="input-group-field"
|
:type="inputType"
|
||||||
autofocus="true"
|
class="input-group-field"
|
||||||
:class="{ error: $v.editedValue.$error }"
|
autofocus="true"
|
||||||
@blur="$v.editedValue.$touch"
|
:class="{ error: $v.editedValue.$error }"
|
||||||
@keyup.enter="onUpdate"
|
@blur="$v.editedValue.$touch"
|
||||||
/>
|
@keyup.enter="onUpdate"
|
||||||
<div class="input-group-button">
|
/>
|
||||||
<woot-button size="small" icon="ion-checkmark" @click="onUpdate" />
|
<div class="input-group-button">
|
||||||
|
<woot-button size="small" icon="ion-checkmark" @click="onUpdate" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span v-if="shouldShowErrorMessage" class="error-message">
|
||||||
|
{{ errorMessage }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-show="!isEditing"
|
||||||
|
class="value--view"
|
||||||
|
:class="{ 'is-editable': showActions }"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
v-if="isAttributeTypeLink"
|
||||||
|
:href="value"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
class="value"
|
||||||
|
>
|
||||||
|
{{ value || '---' }}
|
||||||
|
</a>
|
||||||
|
<p v-else class="value">
|
||||||
|
{{ formattedValue || '---' }}
|
||||||
|
</p>
|
||||||
|
<div class="action-buttons__wrap">
|
||||||
|
<woot-button
|
||||||
|
v-if="showActions"
|
||||||
|
v-tooltip="$t('CUSTOM_ATTRIBUTES.ACTIONS.COPY')"
|
||||||
|
variant="link"
|
||||||
|
size="small"
|
||||||
|
color-scheme="secondary"
|
||||||
|
icon="ion-clipboard"
|
||||||
|
class-names="edit-button"
|
||||||
|
@click="onCopy"
|
||||||
|
/>
|
||||||
|
<woot-button
|
||||||
|
v-if="showActions"
|
||||||
|
v-tooltip.right="$t('CUSTOM_ATTRIBUTES.ACTIONS.EDIT')"
|
||||||
|
variant="link"
|
||||||
|
size="small"
|
||||||
|
color-scheme="secondary"
|
||||||
|
icon="ion-compose"
|
||||||
|
class-names="edit-button"
|
||||||
|
@click="onEdit"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span v-if="shouldShowErrorMessage" class="error-message">
|
|
||||||
{{ errorMessage }}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div v-if="isAttributeTypeList">
|
||||||
v-show="!isEditing"
|
<multiselect-dropdown
|
||||||
class="value--view"
|
:options="listOptions"
|
||||||
:class="{ 'is-editable': showActions }"
|
:selected-item="selectedItem"
|
||||||
>
|
:has-thumbnail="false"
|
||||||
<a
|
:multiselector-placeholder="
|
||||||
v-if="isAttributeTypeLink"
|
$t('CUSTOM_ATTRIBUTES.FORM.ATTRIBUTE_TYPE.LIST.PLACEHOLDER')
|
||||||
:href="value"
|
"
|
||||||
target="_blank"
|
:no-search-result="
|
||||||
rel="noopener noreferrer"
|
$t('CUSTOM_ATTRIBUTES.FORM.ATTRIBUTE_TYPE.LIST.NO_RESULT')
|
||||||
class="value"
|
"
|
||||||
>
|
:input-placeholder="
|
||||||
{{ value || '---' }}
|
$t(
|
||||||
</a>
|
'CUSTOM_ATTRIBUTES.FORM.ATTRIBUTE_TYPE.LIST.SEARCH_INPUT_PLACEHOLDER'
|
||||||
<p v-else class="value">
|
)
|
||||||
{{ formattedValue || '---' }}
|
"
|
||||||
</p>
|
@click="onUpdateListValue"
|
||||||
<woot-button
|
|
||||||
v-if="showActions"
|
|
||||||
v-tooltip="$t('CUSTOM_ATTRIBUTES.ACTIONS.COPY')"
|
|
||||||
variant="link"
|
|
||||||
size="small"
|
|
||||||
color-scheme="secondary"
|
|
||||||
icon="ion-clipboard"
|
|
||||||
class-names="edit-button"
|
|
||||||
@click="onCopy"
|
|
||||||
/>
|
|
||||||
<woot-button
|
|
||||||
v-if="showActions"
|
|
||||||
v-tooltip="$t('CUSTOM_ATTRIBUTES.ACTIONS.EDIT')"
|
|
||||||
variant="link"
|
|
||||||
size="small"
|
|
||||||
color-scheme="secondary"
|
|
||||||
icon="ion-compose"
|
|
||||||
class-names="edit-button"
|
|
||||||
@click="onEdit"
|
|
||||||
/>
|
|
||||||
<woot-button
|
|
||||||
v-if="showActions"
|
|
||||||
v-tooltip="$t('CUSTOM_ATTRIBUTES.ACTIONS.DELETE')"
|
|
||||||
variant="link"
|
|
||||||
size="small"
|
|
||||||
color-scheme="secondary"
|
|
||||||
icon="ion-trash-a"
|
|
||||||
class-names="edit-button"
|
|
||||||
@click="onDelete"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -82,13 +118,18 @@
|
||||||
import format from 'date-fns/format';
|
import format from 'date-fns/format';
|
||||||
import { required, url } from 'vuelidate/lib/validators';
|
import { required, url } from 'vuelidate/lib/validators';
|
||||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||||
|
import MultiselectDropdown from 'shared/components/ui/MultiselectDropdown.vue';
|
||||||
|
|
||||||
const DATE_FORMAT = 'yyyy-MM-dd';
|
const DATE_FORMAT = 'yyyy-MM-dd';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
components: {
|
||||||
|
MultiselectDropdown,
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
label: { type: String, required: true },
|
label: { type: String, required: true },
|
||||||
value: { type: [String, Number], default: '' },
|
values: { type: Array, default: () => [] },
|
||||||
|
value: { type: [String, Number, Boolean], default: '' },
|
||||||
showActions: { type: Boolean, default: false },
|
showActions: { type: Boolean, default: false },
|
||||||
attributeType: { type: String, default: 'text' },
|
attributeType: { type: String, default: 'text' },
|
||||||
attributeKey: { type: String, required: true },
|
attributeKey: { type: String, required: true },
|
||||||
|
@ -115,9 +156,28 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
listOptions() {
|
||||||
|
return this.values.map((value, index) => ({
|
||||||
|
id: index + 1,
|
||||||
|
name: value,
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
selectedItem() {
|
||||||
|
const id = this.values.indexOf(this.editedValue) + 1;
|
||||||
|
return { id, name: this.editedValue };
|
||||||
|
},
|
||||||
|
isAttributeTypeCheckbox() {
|
||||||
|
return this.attributeType === 'checkbox';
|
||||||
|
},
|
||||||
|
isAttributeTypeList() {
|
||||||
|
return this.attributeType === 'list';
|
||||||
|
},
|
||||||
isAttributeTypeLink() {
|
isAttributeTypeLink() {
|
||||||
return this.attributeType === 'link';
|
return this.attributeType === 'link';
|
||||||
},
|
},
|
||||||
|
notAttributeTypeCheckboxAndList() {
|
||||||
|
return !this.isAttributeTypeCheckbox && !this.isAttributeTypeList;
|
||||||
|
},
|
||||||
inputType() {
|
inputType() {
|
||||||
return this.isAttributeTypeLink ? 'url' : this.attributeType;
|
return this.isAttributeTypeLink ? 'url' : this.attributeType;
|
||||||
},
|
},
|
||||||
|
@ -156,6 +216,12 @@ export default {
|
||||||
this.focusInput();
|
this.focusInput();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
onUpdateListValue(value) {
|
||||||
|
if (value) {
|
||||||
|
this.editedValue = value.name;
|
||||||
|
this.onUpdate();
|
||||||
|
}
|
||||||
|
},
|
||||||
onUpdate() {
|
onUpdate() {
|
||||||
const updatedValue =
|
const updatedValue =
|
||||||
this.attributeType === 'date'
|
this.attributeType === 'date'
|
||||||
|
@ -194,8 +260,23 @@ export default {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.checkbox-wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.checkbox {
|
||||||
|
margin: 0 var(--space-small) 0 0;
|
||||||
|
}
|
||||||
|
.name-button__wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
.attribute-name {
|
.attribute-name {
|
||||||
|
width: 100%;
|
||||||
&.error {
|
&.error {
|
||||||
color: var(--r-400);
|
color: var(--r-400);
|
||||||
}
|
}
|
||||||
|
@ -206,22 +287,34 @@ export default {
|
||||||
.edit-button {
|
.edit-button {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.delete-button {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
width: var(--space-normal);
|
||||||
|
}
|
||||||
.value--view {
|
.value--view {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
&.is-editable:hover {
|
&.is-editable:hover {
|
||||||
.value {
|
.value {
|
||||||
background: var(--color-background);
|
background: var(--color-background);
|
||||||
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
.edit-button {
|
.edit-button {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.action-buttons__wrap {
|
||||||
|
display: flex;
|
||||||
|
max-width: var(--space-larger);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.value {
|
.value {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
min-width: var(--space-mega);
|
min-width: var(--space-mega);
|
||||||
border-radius: var(--border-radius-small);
|
border-radius: var(--border-radius-small);
|
||||||
|
margin-bottom: 0;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
padding: var(--space-micro) var(--space-smaller);
|
padding: var(--space-micro) var(--space-smaller);
|
||||||
}
|
}
|
||||||
|
@ -235,4 +328,17 @@ export default {
|
||||||
margin-top: -1.6rem;
|
margin-top: -1.6rem;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
::v-deep {
|
||||||
|
.selector-wrap {
|
||||||
|
margin: 0;
|
||||||
|
top: var(--space-smaller);
|
||||||
|
.selector-name {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.name {
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -27,7 +27,12 @@
|
||||||
"TYPE": {
|
"TYPE": {
|
||||||
"LABEL": "Type",
|
"LABEL": "Type",
|
||||||
"PLACEHOLDER": "Please select a type",
|
"PLACEHOLDER": "Please select a type",
|
||||||
"ERROR": "Type is required"
|
"ERROR": "Type is required",
|
||||||
|
"LIST": {
|
||||||
|
"LABEL": "List Values",
|
||||||
|
"PLACEHOLDER": "Please enter value and press enter key",
|
||||||
|
"ERROR": "Must have at least one value"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"KEY": {
|
"KEY": {
|
||||||
"LABEL": "Key",
|
"LABEL": "Key",
|
||||||
|
@ -58,6 +63,12 @@
|
||||||
"EDIT": {
|
"EDIT": {
|
||||||
"TITLE": "Edit Custom Attribute",
|
"TITLE": "Edit Custom Attribute",
|
||||||
"UPDATE_BUTTON_TEXT": "Update",
|
"UPDATE_BUTTON_TEXT": "Update",
|
||||||
|
"TYPE": {
|
||||||
|
"LIST": {
|
||||||
|
"LABEL": "List Values",
|
||||||
|
"PLACEHOLDER": "Please enter values and press enter key"
|
||||||
|
}
|
||||||
|
},
|
||||||
"API": {
|
"API": {
|
||||||
"SUCCESS_MESSAGE": "Custom Attribute updated successfully",
|
"SUCCESS_MESSAGE": "Custom Attribute updated successfully",
|
||||||
"ERROR_MESSAGE": "There was an error updating custom attribute, please try again"
|
"ERROR_MESSAGE": "There was an error updating custom attribute, please try again"
|
||||||
|
|
|
@ -279,6 +279,13 @@
|
||||||
"TITLE": "Add attributes",
|
"TITLE": "Add attributes",
|
||||||
"PLACEHOLDER": "Search attributes",
|
"PLACEHOLDER": "Search attributes",
|
||||||
"NO_RESULT": "No attributes found"
|
"NO_RESULT": "No attributes found"
|
||||||
|
},
|
||||||
|
"ATTRIBUTE_TYPE": {
|
||||||
|
"LIST": {
|
||||||
|
"PLACEHOLDER": "Select value",
|
||||||
|
"SEARCH_INPUT_PLACEHOLDER": "Search value",
|
||||||
|
"NO_RESULT": "No result found"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"VALIDATIONS": {
|
"VALIDATIONS": {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
:key="attribute.id"
|
:key="attribute.id"
|
||||||
:attribute-key="attribute.attribute_key"
|
:attribute-key="attribute.attribute_key"
|
||||||
:attribute-type="attribute.attribute_display_type"
|
:attribute-type="attribute.attribute_display_type"
|
||||||
|
:values="attribute.attribute_values"
|
||||||
:label="attribute.attribute_display_name"
|
:label="attribute.attribute_display_name"
|
||||||
:icon="attribute.icon"
|
:icon="attribute.icon"
|
||||||
emoji=""
|
emoji=""
|
||||||
|
|
|
@ -30,6 +30,15 @@
|
||||||
@input="onDisplayNameChange"
|
@input="onDisplayNameChange"
|
||||||
@blur="$v.displayName.$touch"
|
@blur="$v.displayName.$touch"
|
||||||
/>
|
/>
|
||||||
|
<woot-input
|
||||||
|
v-model="attributeKey"
|
||||||
|
:label="$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.LABEL')"
|
||||||
|
type="text"
|
||||||
|
:class="{ error: $v.attributeKey.$error }"
|
||||||
|
:error="$v.attributeKey.$error ? keyErrorMessage : ''"
|
||||||
|
:placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.PLACEHOLDER')"
|
||||||
|
@blur="$v.attributeKey.$touch"
|
||||||
|
/>
|
||||||
<label :class="{ error: $v.description.$error }">
|
<label :class="{ error: $v.description.$error }">
|
||||||
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.DESC.LABEL') }}
|
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.DESC.LABEL') }}
|
||||||
<textarea
|
<textarea
|
||||||
|
@ -54,15 +63,29 @@
|
||||||
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.TYPE.ERROR') }}
|
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.TYPE.ERROR') }}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<woot-input
|
<div v-if="isAttributeTypeList" class="multiselect--wrap">
|
||||||
v-model="attributeKey"
|
<label>
|
||||||
:label="$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.LABEL')"
|
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.TYPE.LIST.LABEL') }}
|
||||||
type="text"
|
</label>
|
||||||
:class="{ error: $v.attributeKey.$error }"
|
<multiselect
|
||||||
:error="$v.attributeKey.$error ? keyErrorMessage : ''"
|
ref="tagInput"
|
||||||
:placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.PLACEHOLDER')"
|
v-model="values"
|
||||||
@blur="$v.attributeKey.$touch"
|
:placeholder="
|
||||||
/>
|
$t('ATTRIBUTES_MGMT.ADD.FORM.TYPE.LIST.PLACEHOLDER')
|
||||||
|
"
|
||||||
|
label="name"
|
||||||
|
track-by="name"
|
||||||
|
:class="{ invalid: isMultiselectInvalid }"
|
||||||
|
:options="options"
|
||||||
|
:multiple="true"
|
||||||
|
:taggable="true"
|
||||||
|
@close="onTouch"
|
||||||
|
@tag="addTagValue"
|
||||||
|
/>
|
||||||
|
<label v-show="isMultiselectInvalid" class="error-message">
|
||||||
|
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.TYPE.LIST.ERROR') }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<woot-submit-button
|
<woot-submit-button
|
||||||
:disabled="isButtonDisabled"
|
:disabled="isButtonDisabled"
|
||||||
|
@ -103,7 +126,10 @@ export default {
|
||||||
attributeKey: '',
|
attributeKey: '',
|
||||||
models: ATTRIBUTE_MODELS,
|
models: ATTRIBUTE_MODELS,
|
||||||
types: ATTRIBUTE_TYPES,
|
types: ATTRIBUTE_TYPES,
|
||||||
|
values: [],
|
||||||
|
options: [],
|
||||||
show: true,
|
show: true,
|
||||||
|
isTouched: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -111,11 +137,21 @@ export default {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
uiFlags: 'getUIFlags',
|
uiFlags: 'getUIFlags',
|
||||||
}),
|
}),
|
||||||
|
isMultiselectInvalid() {
|
||||||
|
return this.isTouched && this.values.length === 0;
|
||||||
|
},
|
||||||
|
isTagInputInvalid() {
|
||||||
|
return this.isAttributeTypeList && this.values.length === 0;
|
||||||
|
},
|
||||||
|
attributeListValues() {
|
||||||
|
return this.values.map(item => item.name);
|
||||||
|
},
|
||||||
isButtonDisabled() {
|
isButtonDisabled() {
|
||||||
return (
|
return (
|
||||||
this.$v.displayName.$invalid ||
|
this.$v.displayName.$invalid ||
|
||||||
this.$v.description.$invalid ||
|
this.$v.description.$invalid ||
|
||||||
this.uiFlags.isCreating
|
this.uiFlags.isCreating ||
|
||||||
|
this.isTagInputInvalid
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
keyErrorMessage() {
|
keyErrorMessage() {
|
||||||
|
@ -124,6 +160,9 @@ export default {
|
||||||
}
|
}
|
||||||
return this.$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.ERROR');
|
return this.$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.ERROR');
|
||||||
},
|
},
|
||||||
|
isAttributeTypeList() {
|
||||||
|
return this.attributeType === 6;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
validations: {
|
validations: {
|
||||||
|
@ -149,6 +188,16 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
addTagValue(tagValue) {
|
||||||
|
const tag = {
|
||||||
|
name: tagValue,
|
||||||
|
};
|
||||||
|
this.values.push(tag);
|
||||||
|
this.$refs.tagInput.$el.focus();
|
||||||
|
},
|
||||||
|
onTouch() {
|
||||||
|
this.isTouched = true;
|
||||||
|
},
|
||||||
onDisplayNameChange() {
|
onDisplayNameChange() {
|
||||||
this.attributeKey = convertToSlug(this.displayName);
|
this.attributeKey = convertToSlug(this.displayName);
|
||||||
},
|
},
|
||||||
|
@ -164,6 +213,7 @@ export default {
|
||||||
attribute_model: this.attributeModel,
|
attribute_model: this.attributeModel,
|
||||||
attribute_display_type: this.attributeType,
|
attribute_display_type: this.attributeType,
|
||||||
attribute_key: this.attributeKey,
|
attribute_key: this.attributeKey,
|
||||||
|
attribute_values: this.attributeListValues,
|
||||||
});
|
});
|
||||||
this.alertMessage = this.$t('ATTRIBUTES_MGMT.ADD.API.SUCCESS_MESSAGE');
|
this.alertMessage = this.$t('ATTRIBUTES_MGMT.ADD.API.SUCCESS_MESSAGE');
|
||||||
this.onClose();
|
this.onClose();
|
||||||
|
@ -183,4 +233,30 @@ export default {
|
||||||
padding: 0 var(--space-small) var(--space-small) 0;
|
padding: 0 var(--space-small) var(--space-small) 0;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
.multiselect--wrap {
|
||||||
|
margin-bottom: var(--space-normal);
|
||||||
|
.error-message {
|
||||||
|
color: var(--r-400);
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
font-weight: var(--font-weight-normal);
|
||||||
|
}
|
||||||
|
.invalid {
|
||||||
|
::v-deep {
|
||||||
|
.multiselect__tags {
|
||||||
|
border: 1px solid var(--r-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
::v-deep {
|
||||||
|
.multiselect {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.multiselect__content-wrapper {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.multiselect--active .multiselect__tags {
|
||||||
|
border-radius: var(--border-radius-normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -16,6 +16,16 @@
|
||||||
:placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.NAME.PLACEHOLDER')"
|
:placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.NAME.PLACEHOLDER')"
|
||||||
@blur="$v.displayName.$touch"
|
@blur="$v.displayName.$touch"
|
||||||
/>
|
/>
|
||||||
|
<woot-input
|
||||||
|
v-model.trim="attributeKey"
|
||||||
|
:label="$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.LABEL')"
|
||||||
|
type="text"
|
||||||
|
:class="{ error: $v.attributeKey.$error }"
|
||||||
|
:error="$v.attributeKey.$error ? keyErrorMessage : ''"
|
||||||
|
:placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.PLACEHOLDER')"
|
||||||
|
readonly
|
||||||
|
@blur="$v.attributeKey.$touch"
|
||||||
|
/>
|
||||||
<label :class="{ error: $v.description.$error }">
|
<label :class="{ error: $v.description.$error }">
|
||||||
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.DESC.LABEL') }}
|
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.DESC.LABEL') }}
|
||||||
<textarea
|
<textarea
|
||||||
|
@ -40,22 +50,29 @@
|
||||||
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.TYPE.ERROR') }}
|
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.TYPE.ERROR') }}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<woot-input
|
<div v-if="isAttributeTypeList" class="multiselect--wrap">
|
||||||
v-model.trim="attributeKey"
|
<label>
|
||||||
:label="$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.LABEL')"
|
{{ $t('ATTRIBUTES_MGMT.EDIT.TYPE.LIST.LABEL') }}
|
||||||
type="text"
|
</label>
|
||||||
:class="{ error: $v.attributeKey.$error }"
|
<multiselect
|
||||||
:error="$v.attributeKey.$error ? keyErrorMessage : ''"
|
ref="tagInput"
|
||||||
:placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.PLACEHOLDER')"
|
v-model="values"
|
||||||
readonly
|
:placeholder="$t('ATTRIBUTES_MGMT.ADD.FORM.TYPE.LIST.PLACEHOLDER')"
|
||||||
@blur="$v.attributeKey.$touch"
|
label="name"
|
||||||
/>
|
track-by="name"
|
||||||
|
:class="{ invalid: isMultiselectInvalid }"
|
||||||
|
:options="options"
|
||||||
|
:multiple="true"
|
||||||
|
:taggable="true"
|
||||||
|
@tag="addTagValue"
|
||||||
|
/>
|
||||||
|
<label v-show="isMultiselectInvalid" class="error-message">
|
||||||
|
{{ $t('ATTRIBUTES_MGMT.ADD.FORM.TYPE.LIST.ERROR') }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<woot-button
|
<woot-button :is-loading="isUpdating" :disabled="isButtonDisabled">
|
||||||
:is-loading="isUpdating"
|
|
||||||
:disabled="$v.description.$invalid"
|
|
||||||
>
|
|
||||||
{{ $t('ATTRIBUTES_MGMT.EDIT.UPDATE_BUTTON_TEXT') }}
|
{{ $t('ATTRIBUTES_MGMT.EDIT.UPDATE_BUTTON_TEXT') }}
|
||||||
</woot-button>
|
</woot-button>
|
||||||
<woot-button variant="clear" @click.prevent="onClose">
|
<woot-button variant="clear" @click.prevent="onClose">
|
||||||
|
@ -92,6 +109,9 @@ export default {
|
||||||
types: ATTRIBUTE_TYPES,
|
types: ATTRIBUTE_TYPES,
|
||||||
show: true,
|
show: true,
|
||||||
attributeKey: '',
|
attributeKey: '',
|
||||||
|
values: [],
|
||||||
|
options: [],
|
||||||
|
isTouched: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
validations: {
|
validations: {
|
||||||
|
@ -116,6 +136,22 @@ export default {
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
uiFlags: 'attributes/getUIFlags',
|
uiFlags: 'attributes/getUIFlags',
|
||||||
}),
|
}),
|
||||||
|
setAttributeListValue() {
|
||||||
|
return this.selectedAttribute.attribute_values.map(values => ({
|
||||||
|
name: values,
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
updatedAttributeListValues() {
|
||||||
|
return this.values.map(item => item.name);
|
||||||
|
},
|
||||||
|
isButtonDisabled() {
|
||||||
|
return this.$v.description.$invalid || this.isMultiselectInvalid;
|
||||||
|
},
|
||||||
|
isMultiselectInvalid() {
|
||||||
|
return (
|
||||||
|
this.isAttributeTypeList && this.isTouched && this.values.length === 0
|
||||||
|
);
|
||||||
|
},
|
||||||
pageTitle() {
|
pageTitle() {
|
||||||
return `${this.$t('ATTRIBUTES_MGMT.EDIT.TITLE')} - ${
|
return `${this.$t('ATTRIBUTES_MGMT.EDIT.TITLE')} - ${
|
||||||
this.selectedAttribute.attribute_display_name
|
this.selectedAttribute.attribute_display_name
|
||||||
|
@ -134,6 +170,9 @@ export default {
|
||||||
}
|
}
|
||||||
return this.$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.ERROR');
|
return this.$t('ATTRIBUTES_MGMT.ADD.FORM.KEY.ERROR');
|
||||||
},
|
},
|
||||||
|
isAttributeTypeList() {
|
||||||
|
return this.attributeType === 6;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.setFormValues();
|
this.setFormValues();
|
||||||
|
@ -142,11 +181,19 @@ export default {
|
||||||
onClose() {
|
onClose() {
|
||||||
this.$emit('on-close');
|
this.$emit('on-close');
|
||||||
},
|
},
|
||||||
|
addTagValue(tagValue) {
|
||||||
|
const tag = {
|
||||||
|
name: tagValue,
|
||||||
|
};
|
||||||
|
this.values.push(tag);
|
||||||
|
this.$refs.tagInput.$el.focus();
|
||||||
|
},
|
||||||
setFormValues() {
|
setFormValues() {
|
||||||
this.displayName = this.selectedAttribute.attribute_display_name;
|
this.displayName = this.selectedAttribute.attribute_display_name;
|
||||||
this.description = this.selectedAttribute.attribute_description;
|
this.description = this.selectedAttribute.attribute_description;
|
||||||
this.attributeType = this.selectedAttributeType;
|
this.attributeType = this.selectedAttributeType;
|
||||||
this.attributeKey = this.selectedAttribute.attribute_key;
|
this.attributeKey = this.selectedAttribute.attribute_key;
|
||||||
|
this.values = this.setAttributeListValue;
|
||||||
},
|
},
|
||||||
async editAttributes() {
|
async editAttributes() {
|
||||||
this.$v.$touch();
|
this.$v.$touch();
|
||||||
|
@ -158,6 +205,7 @@ export default {
|
||||||
id: this.selectedAttribute.id,
|
id: this.selectedAttribute.id,
|
||||||
attribute_description: this.description,
|
attribute_description: this.description,
|
||||||
attribute_display_name: this.displayName,
|
attribute_display_name: this.displayName,
|
||||||
|
attribute_values: this.updatedAttributeListValues,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.alertMessage = this.$t('ATTRIBUTES_MGMT.EDIT.API.SUCCESS_MESSAGE');
|
this.alertMessage = this.$t('ATTRIBUTES_MGMT.EDIT.API.SUCCESS_MESSAGE');
|
||||||
|
@ -178,4 +226,30 @@ export default {
|
||||||
padding: 0 var(--space-small) var(--space-small) 0;
|
padding: 0 var(--space-small) var(--space-small) 0;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
.multiselect--wrap {
|
||||||
|
margin-bottom: var(--space-normal);
|
||||||
|
.error-message {
|
||||||
|
color: var(--r-400);
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
font-weight: var(--font-weight-normal);
|
||||||
|
}
|
||||||
|
.invalid {
|
||||||
|
::v-deep {
|
||||||
|
.multiselect__tags {
|
||||||
|
border: 1px solid var(--r-400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
::v-deep {
|
||||||
|
.multiselect {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.multiselect__content-wrapper {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.multiselect--active .multiselect__tags {
|
||||||
|
border-radius: var(--border-radius-normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -26,4 +26,12 @@ export const ATTRIBUTE_TYPES = [
|
||||||
id: 5,
|
id: 5,
|
||||||
option: 'Date',
|
option: 'Date',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
option: 'List',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
option: 'Checkbox',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
>
|
>
|
||||||
<div class="selector-user-wrap">
|
<div class="selector-user-wrap">
|
||||||
<Thumbnail
|
<Thumbnail
|
||||||
v-if="hasValue"
|
v-if="hasValue && hasThumbnail"
|
||||||
:src="selectedItem.thumbnail"
|
:src="selectedItem.thumbnail"
|
||||||
size="24px"
|
size="24px"
|
||||||
:status="selectedItem.availability_status"
|
:status="selectedItem.availability_status"
|
||||||
|
@ -48,6 +48,7 @@
|
||||||
v-if="showSearchDropdown"
|
v-if="showSearchDropdown"
|
||||||
:options="options"
|
:options="options"
|
||||||
:selected-item="selectedItem"
|
:selected-item="selectedItem"
|
||||||
|
:has-thumbnail="hasThumbnail"
|
||||||
:input-placeholder="inputPlaceholder"
|
:input-placeholder="inputPlaceholder"
|
||||||
:no-search-result="noSearchResult"
|
:no-search-result="noSearchResult"
|
||||||
@click="onClickSelectItem"
|
@click="onClickSelectItem"
|
||||||
|
@ -75,9 +76,13 @@ export default {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
|
hasThumbnail: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
multiselectorTitle: {
|
multiselectorTitle: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'Select',
|
default: '',
|
||||||
},
|
},
|
||||||
multiselectorPlaceholder: {
|
multiselectorPlaceholder: {
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -116,6 +121,7 @@ export default {
|
||||||
|
|
||||||
onClickSelectItem(value) {
|
onClickSelectItem(value) {
|
||||||
this.$emit('click', value);
|
this.$emit('click', value);
|
||||||
|
this.onCloseDropdown();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
>
|
>
|
||||||
<div class="user-wrap">
|
<div class="user-wrap">
|
||||||
<Thumbnail
|
<Thumbnail
|
||||||
|
v-if="hasThumbnail"
|
||||||
:src="option.thumbnail"
|
:src="option.thumbnail"
|
||||||
size="24px"
|
size="24px"
|
||||||
:username="option.name"
|
:username="option.name"
|
||||||
|
@ -76,6 +77,10 @@ export default {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
|
hasThumbnail: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
inputPlaceholder: {
|
inputPlaceholder: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'Search',
|
default: 'Search',
|
||||||
|
|
Loading…
Reference in a new issue