feature: Filtering conversations and contacts with custom attributes (#3851)
This commit is contained in:
parent
e0d24e0a73
commit
52d1821cd3
16 changed files with 451 additions and 284 deletions
|
@ -22,6 +22,9 @@ checks:
|
||||||
enabled: true
|
enabled: true
|
||||||
config:
|
config:
|
||||||
threshold: 300
|
threshold: 300
|
||||||
|
method-lines:
|
||||||
|
config:
|
||||||
|
threshold: 50
|
||||||
exclude_patterns:
|
exclude_patterns:
|
||||||
- 'spec/'
|
- 'spec/'
|
||||||
- '**/specs/'
|
- '**/specs/'
|
||||||
|
@ -44,3 +47,4 @@ exclude_patterns:
|
||||||
- 'app/javascript/shared/constants/countries.js'
|
- 'app/javascript/shared/constants/countries.js'
|
||||||
- 'app/javascript/dashboard/components/widgets/conversation/advancedFilterItems/languages.js'
|
- 'app/javascript/dashboard/components/widgets/conversation/advancedFilterItems/languages.js'
|
||||||
- 'app/javascript/dashboard/routes/dashboard/contacts/contactFilterItems/index.js'
|
- 'app/javascript/dashboard/routes/dashboard/contacts/contactFilterItems/index.js'
|
||||||
|
- 'app/javascript/dashboard/components/widgets/FilterInput/FilterOperatorTypes.js'
|
||||||
|
|
|
@ -129,7 +129,7 @@
|
||||||
>
|
>
|
||||||
<conversation-advanced-filter
|
<conversation-advanced-filter
|
||||||
v-if="showAdvancedFilters"
|
v-if="showAdvancedFilters"
|
||||||
:filter-types="advancedFilterTypes"
|
:initial-filter-types="advancedFilterTypes"
|
||||||
:on-close="onToggleAdvanceFiltersModal"
|
:on-close="onToggleAdvanceFiltersModal"
|
||||||
@applyFilter="onApplyFilter"
|
@applyFilter="onApplyFilter"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -30,7 +30,7 @@ export default {
|
||||||
},
|
},
|
||||||
value: {
|
value: {
|
||||||
type: Date,
|
type: Date,
|
||||||
default: () => [],
|
default: [],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
export const OPERATOR_TYPES_1 = [
|
||||||
|
{
|
||||||
|
value: 'equal_to',
|
||||||
|
label: 'Equal to',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'not_equal_to',
|
||||||
|
label: 'Not equal to',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const OPERATOR_TYPES_2 = [
|
||||||
|
{
|
||||||
|
value: 'equal_to',
|
||||||
|
label: 'Equal to',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'not_equal_to',
|
||||||
|
label: 'Not equal to',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'is_present',
|
||||||
|
label: 'Is present',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'is_not_present',
|
||||||
|
label: 'Is not present',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const OPERATOR_TYPES_3 = [
|
||||||
|
{
|
||||||
|
value: 'equal_to',
|
||||||
|
label: 'Equal to',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'not_equal_to',
|
||||||
|
label: 'Not equal to',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'contains',
|
||||||
|
label: 'Contains',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'does_not_contain',
|
||||||
|
label: 'Does not contain',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const OPERATOR_TYPES_4 = [
|
||||||
|
{
|
||||||
|
value: 'equal_to',
|
||||||
|
label: 'Equal to',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'not_equal_to',
|
||||||
|
label: 'Not equal to',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'is_present',
|
||||||
|
label: 'Is present',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'is_not_present',
|
||||||
|
label: 'Is not present',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'is_greater_than',
|
||||||
|
label: 'Is greater than',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'is_lesser_than',
|
||||||
|
label: 'Is lesser than',
|
||||||
|
},
|
||||||
|
];
|
|
@ -3,6 +3,27 @@
|
||||||
<div class="filter">
|
<div class="filter">
|
||||||
<div class="filter-inputs">
|
<div class="filter-inputs">
|
||||||
<select
|
<select
|
||||||
|
v-if="groupedFilters"
|
||||||
|
v-model="attributeKey"
|
||||||
|
class="filter__question"
|
||||||
|
@change="resetFilter()"
|
||||||
|
>
|
||||||
|
<optgroup
|
||||||
|
v-for="(group, i) in filterGroups"
|
||||||
|
:key="i"
|
||||||
|
:label="group.name"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="attribute in group.attributes"
|
||||||
|
:key="attribute.key"
|
||||||
|
:value="attribute.key"
|
||||||
|
>
|
||||||
|
{{ attribute.name }}
|
||||||
|
</option>
|
||||||
|
</optgroup>
|
||||||
|
</select>
|
||||||
|
<select
|
||||||
|
v-else
|
||||||
v-model="attributeKey"
|
v-model="attributeKey"
|
||||||
class="filter__question"
|
class="filter__question"
|
||||||
@change="resetFilter()"
|
@change="resetFilter()"
|
||||||
|
@ -63,6 +84,14 @@
|
||||||
:option-height="104"
|
:option-height="104"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="inputType === 'date'" class="multiselect-wrap--small">
|
||||||
|
<input
|
||||||
|
v-model="values"
|
||||||
|
type="date"
|
||||||
|
:editable="false"
|
||||||
|
class="answer--text-input datepicker"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<input
|
<input
|
||||||
v-else
|
v-else
|
||||||
v-model="values"
|
v-model="values"
|
||||||
|
@ -132,6 +161,14 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
groupedFilters: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
filterGroups: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
attributeKey: {
|
attributeKey: {
|
|
@ -9,12 +9,13 @@
|
||||||
v-for="(filter, i) in appliedFilters"
|
v-for="(filter, i) in appliedFilters"
|
||||||
:key="i"
|
:key="i"
|
||||||
v-model="appliedFilters[i]"
|
v-model="appliedFilters[i]"
|
||||||
:filter-attributes="filterAttributes"
|
:filter-groups="filterGroups"
|
||||||
:input-type="getInputType(appliedFilters[i].attribute_key)"
|
:input-type="getInputType(appliedFilters[i].attribute_key)"
|
||||||
:operators="getOperators(appliedFilters[i].attribute_key)"
|
:operators="getOperators(appliedFilters[i].attribute_key)"
|
||||||
:dropdown-values="getDropdownValues(appliedFilters[i].attribute_key)"
|
:dropdown-values="getDropdownValues(appliedFilters[i].attribute_key)"
|
||||||
:show-query-operator="i !== appliedFilters.length - 1"
|
:show-query-operator="i !== appliedFilters.length - 1"
|
||||||
:show-user-input="showUserInput(appliedFilters[i].filter_operator)"
|
:show-user-input="showUserInput(appliedFilters[i].filter_operator)"
|
||||||
|
:grouped-filters="true"
|
||||||
:v="$v.appliedFilters.$each[i]"
|
:v="$v.appliedFilters.$each[i]"
|
||||||
@resetFilter="resetFilter(i, appliedFilters[i])"
|
@resetFilter="resetFilter(i, appliedFilters[i])"
|
||||||
@removeFilter="removeFilter(i)"
|
@removeFilter="removeFilter(i)"
|
||||||
|
@ -48,22 +49,24 @@
|
||||||
<script>
|
<script>
|
||||||
import alertMixin from 'shared/mixins/alertMixin';
|
import alertMixin from 'shared/mixins/alertMixin';
|
||||||
import { required, requiredIf } from 'vuelidate/lib/validators';
|
import { required, requiredIf } from 'vuelidate/lib/validators';
|
||||||
import FilterInputBox from '../FilterInput.vue';
|
import FilterInputBox from '../FilterInput/Index.vue';
|
||||||
import languages from './advancedFilterItems/languages';
|
import languages from './advancedFilterItems/languages';
|
||||||
import countries from '/app/javascript/shared/constants/countries.js';
|
import countries from 'shared/constants/countries.js';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
|
import { filterAttributeGroups } from './advancedFilterItems';
|
||||||
|
import filterMixin from 'shared/mixins/filterMixin';
|
||||||
|
import * as OPERATORS from 'dashboard/components/widgets/FilterInput/FilterOperatorTypes.js';
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
FilterInputBox,
|
FilterInputBox,
|
||||||
},
|
},
|
||||||
mixins: [alertMixin],
|
mixins: [alertMixin, filterMixin],
|
||||||
props: {
|
props: {
|
||||||
onClose: {
|
onClose: {
|
||||||
type: Function,
|
type: Function,
|
||||||
default: () => {},
|
default: () => {},
|
||||||
},
|
},
|
||||||
filterTypes: {
|
initialFilterTypes: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
|
@ -87,22 +90,21 @@ export default {
|
||||||
return {
|
return {
|
||||||
show: true,
|
show: true,
|
||||||
appliedFilters: [],
|
appliedFilters: [],
|
||||||
|
filterTypes: this.initialFilterTypes,
|
||||||
|
filterAttributeGroups,
|
||||||
|
filterGroups: [],
|
||||||
|
allCustomAttributes: [],
|
||||||
|
attributeModel: 'conversation_attribute',
|
||||||
|
filtersFori18n: 'FILTER',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
filterAttributes() {
|
|
||||||
return this.filterTypes.map(type => {
|
|
||||||
return {
|
|
||||||
key: type.attributeKey,
|
|
||||||
name: this.$t(`FILTER.ATTRIBUTES.${type.attributeI18nKey}`),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
getAppliedConversationFilters: 'getAppliedConversationFilters',
|
getAppliedConversationFilters: 'getAppliedConversationFilters',
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.setFilterAttributes();
|
||||||
this.$store.dispatch('campaigns/get');
|
this.$store.dispatch('campaigns/get');
|
||||||
if (this.getAppliedConversationFilters.length) {
|
if (this.getAppliedConversationFilters.length) {
|
||||||
this.appliedFilters = [...this.getAppliedConversationFilters];
|
this.appliedFilters = [...this.getAppliedConversationFilters];
|
||||||
|
@ -112,10 +114,41 @@ export default {
|
||||||
filter_operator: 'equal_to',
|
filter_operator: 'equal_to',
|
||||||
values: '',
|
values: '',
|
||||||
query_operator: 'and',
|
query_operator: 'and',
|
||||||
|
attribute_model: 'standard',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getOperatorTypes(key) {
|
||||||
|
switch (key) {
|
||||||
|
case 'list':
|
||||||
|
return OPERATORS.OPERATOR_TYPES_1;
|
||||||
|
case 'text':
|
||||||
|
return OPERATORS.OPERATOR_TYPES_3;
|
||||||
|
case 'number':
|
||||||
|
return OPERATORS.OPERATOR_TYPES_1;
|
||||||
|
case 'link':
|
||||||
|
return OPERATORS.OPERATOR_TYPES_1;
|
||||||
|
case 'date':
|
||||||
|
return OPERATORS.OPERATOR_TYPES_4;
|
||||||
|
case 'checkbox':
|
||||||
|
return OPERATORS.OPERATOR_TYPES_1;
|
||||||
|
default:
|
||||||
|
return OPERATORS.OPERATOR_TYPES_1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
customAttributeInputType(key) {
|
||||||
|
switch (key) {
|
||||||
|
case 'date':
|
||||||
|
return 'date';
|
||||||
|
default:
|
||||||
|
return 'plain_text';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getAttributeModel(key) {
|
||||||
|
const type = this.filterTypes.find(filter => filter.attributeKey === key);
|
||||||
|
return type.attributeModel;
|
||||||
|
},
|
||||||
getInputType(key) {
|
getInputType(key) {
|
||||||
const type = this.filterTypes.find(filter => filter.attributeKey === key);
|
const type = this.filterTypes.find(filter => filter.attributeKey === key);
|
||||||
return type.inputType;
|
return type.inputType;
|
||||||
|
|
|
@ -1,229 +1,144 @@
|
||||||
|
import {
|
||||||
|
OPERATOR_TYPES_1,
|
||||||
|
OPERATOR_TYPES_2,
|
||||||
|
OPERATOR_TYPES_3,
|
||||||
|
} from '../../FilterInput/FilterOperatorTypes';
|
||||||
|
|
||||||
const filterTypes = [
|
const filterTypes = [
|
||||||
{
|
{
|
||||||
attributeKey: 'status',
|
attributeKey: 'status',
|
||||||
attributeI18nKey: 'STATUS',
|
attributeI18nKey: 'STATUS',
|
||||||
inputType: 'multi_select',
|
inputType: 'multi_select',
|
||||||
dataType: 'text',
|
dataType: 'text',
|
||||||
filterOperators: [
|
filterOperators: OPERATOR_TYPES_1,
|
||||||
{
|
attributeModel: 'standard',
|
||||||
value: 'equal_to',
|
|
||||||
label: 'Equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'not_equal_to',
|
|
||||||
label: 'Not equal to',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
attribute_type: 'standard',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
attributeKey: 'assignee_id',
|
attributeKey: 'assignee_id',
|
||||||
attributeI18nKey: 'ASSIGNEE_NAME',
|
attributeI18nKey: 'ASSIGNEE_NAME',
|
||||||
inputType: 'search_select',
|
inputType: 'search_select',
|
||||||
dataType: 'text',
|
dataType: 'text',
|
||||||
filterOperators: [
|
filterOperators: OPERATOR_TYPES_2,
|
||||||
{
|
attributeModel: 'standard',
|
||||||
value: 'equal_to',
|
|
||||||
label: 'Equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'not_equal_to',
|
|
||||||
label: 'Not equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'is_present',
|
|
||||||
label: 'Is present',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'is_not_present',
|
|
||||||
label: 'Is not present',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
attribute_type: 'standard',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
attributeKey: 'inbox_id',
|
attributeKey: 'inbox_id',
|
||||||
attributeI18nKey: 'INBOX_NAME',
|
attributeI18nKey: 'INBOX_NAME',
|
||||||
inputType: 'search_select',
|
inputType: 'search_select',
|
||||||
dataType: 'text',
|
dataType: 'text',
|
||||||
filterOperators: [
|
filterOperators: OPERATOR_TYPES_2,
|
||||||
{
|
attributeModel: 'standard',
|
||||||
value: 'equal_to',
|
|
||||||
label: 'Equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'not_equal_to',
|
|
||||||
label: 'Not equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'is_present',
|
|
||||||
label: 'Is present',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'is_not_present',
|
|
||||||
label: 'Is not present',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
attribute_type: 'standard',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
attributeKey: 'team_id',
|
attributeKey: 'team_id',
|
||||||
attributeI18nKey: 'TEAM_NAME',
|
attributeI18nKey: 'TEAM_NAME',
|
||||||
inputType: 'search_select',
|
inputType: 'search_select',
|
||||||
dataType: 'number',
|
dataType: 'number',
|
||||||
filterOperators: [
|
filterOperators: OPERATOR_TYPES_2,
|
||||||
{
|
attributeModel: 'standard',
|
||||||
value: 'equal_to',
|
|
||||||
label: 'Equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'not_equal_to',
|
|
||||||
label: 'Not equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'is_present',
|
|
||||||
label: 'Is present',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'is_not_present',
|
|
||||||
label: 'Is not present',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
attribute_type: 'standard',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
attributeKey: 'display_id',
|
attributeKey: 'display_id',
|
||||||
attributeI18nKey: 'CONVERSATION_IDENTIFIER',
|
attributeI18nKey: 'CONVERSATION_IDENTIFIER',
|
||||||
inputType: 'plain_text',
|
inputType: 'plain_text',
|
||||||
dataType: 'Number',
|
dataType: 'Number',
|
||||||
filterOperators: [
|
filterOperators: OPERATOR_TYPES_3,
|
||||||
{
|
attributeModel: 'standard',
|
||||||
value: 'equal_to',
|
|
||||||
label: 'Equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'not_equal_to',
|
|
||||||
label: 'Not equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'contains',
|
|
||||||
label: 'Contains',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'does_not_contain',
|
|
||||||
label: 'Does not contain',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
attribute_type: 'standard',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
attributeKey: 'campaign_id',
|
attributeKey: 'campaign_id',
|
||||||
attributeI18nKey: 'CAMPAIGN_NAME',
|
attributeI18nKey: 'CAMPAIGN_NAME',
|
||||||
inputType: 'search_select',
|
inputType: 'search_select',
|
||||||
dataType: 'Number',
|
dataType: 'Number',
|
||||||
filterOperators: [
|
filterOperators: OPERATOR_TYPES_2,
|
||||||
{
|
attributeModel: 'standard',
|
||||||
value: 'equal_to',
|
|
||||||
label: 'Equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'not_equal_to',
|
|
||||||
label: 'Not equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'is_present',
|
|
||||||
label: 'Is present',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'is_not_present',
|
|
||||||
label: 'Is not present',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
attribute_type: 'standard',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
attributeKey: 'labels',
|
attributeKey: 'labels',
|
||||||
attributeI18nKey: 'LABELS',
|
attributeI18nKey: 'LABELS',
|
||||||
inputType: 'multi_select',
|
inputType: 'multi_select',
|
||||||
dataType: 'text',
|
dataType: 'text',
|
||||||
filterOperators: [
|
filterOperators: OPERATOR_TYPES_2,
|
||||||
{
|
attributeModel: 'standard',
|
||||||
value: 'equal_to',
|
|
||||||
label: 'Equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'not_equal_to',
|
|
||||||
label: 'Not equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'is_present',
|
|
||||||
label: 'Is present',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'is_not_present',
|
|
||||||
label: 'Is not present',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
attribute_type: 'standard',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
attributeKey: 'browser_language',
|
attributeKey: 'browser_language',
|
||||||
attributeI18nKey: 'BROWSER_LANGUAGE',
|
attributeI18nKey: 'BROWSER_LANGUAGE',
|
||||||
inputType: 'search_select',
|
inputType: 'search_select',
|
||||||
dataType: 'text',
|
dataType: 'text',
|
||||||
filterOperators: [
|
filterOperators: OPERATOR_TYPES_1,
|
||||||
{
|
attributeModel: 'additional',
|
||||||
value: 'equal_to',
|
|
||||||
label: 'Equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'not_equal_to',
|
|
||||||
label: 'Not equal to',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
attribute_type: 'additional_attributes',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
attributeKey: 'country_code',
|
attributeKey: 'country_code',
|
||||||
attributeI18nKey: 'COUNTRY_NAME',
|
attributeI18nKey: 'COUNTRY_NAME',
|
||||||
inputType: 'search_select',
|
inputType: 'search_select',
|
||||||
dataType: 'text',
|
dataType: 'text',
|
||||||
filterOperators: [
|
filterOperators: OPERATOR_TYPES_1,
|
||||||
{
|
attributeModel: 'additional',
|
||||||
value: 'equal_to',
|
|
||||||
label: 'Equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'not_equal_to',
|
|
||||||
label: 'Not equal to',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
attribute_type: 'additional_attributes',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
attributeKey: 'referer',
|
attributeKey: 'referer',
|
||||||
attributeI18nKey: 'REFERER_LINK',
|
attributeI18nKey: 'REFERER_LINK',
|
||||||
inputType: 'plain_text',
|
inputType: 'plain_text',
|
||||||
dataType: 'text',
|
dataType: 'text',
|
||||||
filterOperators: [
|
filterOperators: OPERATOR_TYPES_3,
|
||||||
|
attributeModel: 'additional',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const filterAttributeGroups = [
|
||||||
{
|
{
|
||||||
value: 'equal_to',
|
name: 'Standard Filters',
|
||||||
label: 'Equal to',
|
i18nGroup: 'STANDARD_FILTERS',
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
key: 'status',
|
||||||
|
i18nKey: 'STATUS',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'not_equal_to',
|
key: 'assignee_id',
|
||||||
label: 'Not equal to',
|
i18nKey: 'ASSIGNEE_NAME',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'contains',
|
key: 'inbox_id',
|
||||||
label: 'Contains',
|
i18nKey: 'INBOX_NAME',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'does_not_contain',
|
key: 'team_id',
|
||||||
label: 'Does not contain',
|
i18nKey: 'TEAM_NAME',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'display_id',
|
||||||
|
i18nKey: 'CONVERSATION_IDENTIFIER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'campaign_id',
|
||||||
|
i18nKey: 'CAMPAIGN_NAME',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'labels',
|
||||||
|
i18nKey: 'LABELS',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Additional Filters',
|
||||||
|
i18nGroup: 'ADDITIONAL_FILTERS',
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
key: 'browser_language',
|
||||||
|
i18nKey: 'BROWSER_LANGUAGE',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'country_code',
|
||||||
|
i18nKey: 'COUNTRY_NAME',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'referer',
|
||||||
|
i18nKey: 'REFERER_LINK',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
attribute_type: 'additional_attributes',
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,9 @@
|
||||||
"contains": "Contains",
|
"contains": "Contains",
|
||||||
"does_not_contain": "Does not contain",
|
"does_not_contain": "Does not contain",
|
||||||
"is_present": "Is present",
|
"is_present": "Is present",
|
||||||
"is_not_present": "Is not present"
|
"is_not_present": "Is not present",
|
||||||
|
"is_greater_than": "Is greater than",
|
||||||
|
"is_lesser_than": "Is lesser than"
|
||||||
},
|
},
|
||||||
"ATTRIBUTES": {
|
"ATTRIBUTES": {
|
||||||
"STATUS": "Status",
|
"STATUS": "Status",
|
||||||
|
@ -31,7 +33,17 @@
|
||||||
"LABELS": "Labels",
|
"LABELS": "Labels",
|
||||||
"BROWSER_LANGUAGE": "Browser Language",
|
"BROWSER_LANGUAGE": "Browser Language",
|
||||||
"COUNTRY_NAME": "Country Name",
|
"COUNTRY_NAME": "Country Name",
|
||||||
"REFERER_LINK": "Referer link"
|
"REFERER_LINK": "Referer link",
|
||||||
|
"CUSTOM_ATTRIBUTE_LIST": "List",
|
||||||
|
"CUSTOM_ATTRIBUTE_TEXT": "Text",
|
||||||
|
"CUSTOM_ATTRIBUTE_NUMBER": "Number",
|
||||||
|
"CUSTOM_ATTRIBUTE_LINK": "Link",
|
||||||
|
"CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox"
|
||||||
|
},
|
||||||
|
"GROUPS": {
|
||||||
|
"STANDARD_FILTERS": "Standard Filters",
|
||||||
|
"ADDITIONAL_FILTERS": "Additional Filters",
|
||||||
|
"CUSTOM_ATTRIBUTES": "Custom Attributes"
|
||||||
},
|
},
|
||||||
"CUSTOM_VIEWS": {
|
"CUSTOM_VIEWS": {
|
||||||
"ADD": {
|
"ADD": {
|
||||||
|
|
|
@ -20,7 +20,9 @@
|
||||||
"contains": "Contains",
|
"contains": "Contains",
|
||||||
"does_not_contain": "Does not contain",
|
"does_not_contain": "Does not contain",
|
||||||
"is_present": "Is present",
|
"is_present": "Is present",
|
||||||
"is_not_present": "Is not present"
|
"is_not_present": "Is not present",
|
||||||
|
"is_greater_than": "Is greater than",
|
||||||
|
"is_lesser_than": "Is lesser than"
|
||||||
},
|
},
|
||||||
"ATTRIBUTES": {
|
"ATTRIBUTES": {
|
||||||
"NAME": "Name",
|
"NAME": "Name",
|
||||||
|
@ -28,7 +30,17 @@
|
||||||
"PHONE_NUMBER": "Phone number",
|
"PHONE_NUMBER": "Phone number",
|
||||||
"IDENTIFIER": "Identifier",
|
"IDENTIFIER": "Identifier",
|
||||||
"CITY": "City",
|
"CITY": "City",
|
||||||
"COUNTRY": "Country"
|
"COUNTRY": "Country",
|
||||||
|
"CUSTOM_ATTRIBUTE_LIST": "List",
|
||||||
|
"CUSTOM_ATTRIBUTE_TEXT": "Text",
|
||||||
|
"CUSTOM_ATTRIBUTE_NUMBER": "Number",
|
||||||
|
"CUSTOM_ATTRIBUTE_LINK": "Link",
|
||||||
|
"CUSTOM_ATTRIBUTE_CHECKBOX": "Checkbox"
|
||||||
|
},
|
||||||
|
"GROUPS": {
|
||||||
|
"STANDARD_FILTERS": "Standard Filters",
|
||||||
|
"ADDITIONAL_FILTERS": "Additional Filters",
|
||||||
|
"CUSTOM_ATTRIBUTES": "Custom Attributes"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,8 @@
|
||||||
v-for="(filter, i) in appliedFilters"
|
v-for="(filter, i) in appliedFilters"
|
||||||
:key="i"
|
:key="i"
|
||||||
v-model="appliedFilters[i]"
|
v-model="appliedFilters[i]"
|
||||||
:filter-attributes="filterAttributes"
|
:filter-groups="filterGroups"
|
||||||
|
:grouped-filters="true"
|
||||||
:input-type="getInputType(appliedFilters[i].attribute_key)"
|
:input-type="getInputType(appliedFilters[i].attribute_key)"
|
||||||
:operators="getOperators(appliedFilters[i].attribute_key)"
|
:operators="getOperators(appliedFilters[i].attribute_key)"
|
||||||
:dropdown-values="getDropdownValues(appliedFilters[i].attribute_key)"
|
:dropdown-values="getDropdownValues(appliedFilters[i].attribute_key)"
|
||||||
|
@ -58,21 +59,23 @@
|
||||||
<script>
|
<script>
|
||||||
import alertMixin from 'shared/mixins/alertMixin';
|
import alertMixin from 'shared/mixins/alertMixin';
|
||||||
import { required } from 'vuelidate/lib/validators';
|
import { required } from 'vuelidate/lib/validators';
|
||||||
import FilterInputBox from '../../../../components/widgets/FilterInput.vue';
|
import FilterInputBox from '../../../../components/widgets/FilterInput/Index.vue';
|
||||||
import countries from '/app/javascript/shared/constants/countries.js';
|
import countries from 'shared/constants/countries.js';
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
|
import { filterAttributeGroups } from '../contactFilterItems';
|
||||||
|
import filterMixin from 'shared/mixins/filterMixin';
|
||||||
|
import * as OPERATORS from 'dashboard/components/widgets/FilterInput/FilterOperatorTypes.js';
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
FilterInputBox,
|
FilterInputBox,
|
||||||
},
|
},
|
||||||
mixins: [alertMixin],
|
mixins: [alertMixin, filterMixin],
|
||||||
props: {
|
props: {
|
||||||
onClose: {
|
onClose: {
|
||||||
type: Function,
|
type: Function,
|
||||||
default: () => {},
|
default: () => {},
|
||||||
},
|
},
|
||||||
filterTypes: {
|
initialFilterTypes: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
|
@ -91,17 +94,15 @@ export default {
|
||||||
return {
|
return {
|
||||||
show: true,
|
show: true,
|
||||||
appliedFilters: [],
|
appliedFilters: [],
|
||||||
|
filterTypes: this.initialFilterTypes,
|
||||||
|
filterGroups: [],
|
||||||
|
allCustomAttributes: [],
|
||||||
|
filterAttributeGroups,
|
||||||
|
attributeModel: 'contact_attribute',
|
||||||
|
filtersFori18n: 'CONTACTS_FILTER',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
filterAttributes() {
|
|
||||||
return this.filterTypes.map(type => {
|
|
||||||
return {
|
|
||||||
key: type.attributeKey,
|
|
||||||
name: this.$t(`CONTACTS_FILTER.ATTRIBUTES.${type.attributeI18nKey}`),
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
...mapGetters({
|
...mapGetters({
|
||||||
getAppliedContactFilters: 'contacts/getAppliedContactFilters',
|
getAppliedContactFilters: 'contacts/getAppliedContactFilters',
|
||||||
}),
|
}),
|
||||||
|
@ -110,6 +111,7 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.setFilterAttributes();
|
||||||
if (this.getAppliedContactFilters.length) {
|
if (this.getAppliedContactFilters.length) {
|
||||||
this.appliedFilters = [...this.getAppliedContactFilters];
|
this.appliedFilters = [...this.getAppliedContactFilters];
|
||||||
} else {
|
} else {
|
||||||
|
@ -118,10 +120,41 @@ export default {
|
||||||
filter_operator: 'equal_to',
|
filter_operator: 'equal_to',
|
||||||
values: '',
|
values: '',
|
||||||
query_operator: 'and',
|
query_operator: 'and',
|
||||||
|
attribute_model: 'standard',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
getOperatorTypes(key) {
|
||||||
|
switch (key) {
|
||||||
|
case 'list':
|
||||||
|
return OPERATORS.OPERATOR_TYPES_1;
|
||||||
|
case 'text':
|
||||||
|
return OPERATORS.OPERATOR_TYPES_3;
|
||||||
|
case 'number':
|
||||||
|
return OPERATORS.OPERATOR_TYPES_1;
|
||||||
|
case 'link':
|
||||||
|
return OPERATORS.OPERATOR_TYPES_1;
|
||||||
|
case 'date':
|
||||||
|
return OPERATORS.OPERATOR_TYPES_4;
|
||||||
|
case 'checkbox':
|
||||||
|
return OPERATORS.OPERATOR_TYPES_1;
|
||||||
|
default:
|
||||||
|
return OPERATORS.OPERATOR_TYPES_1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
customAttributeInputType(key) {
|
||||||
|
switch (key) {
|
||||||
|
case 'date':
|
||||||
|
return 'date';
|
||||||
|
default:
|
||||||
|
return 'plain_text';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getAttributeModel(key) {
|
||||||
|
const type = this.filterTypes.find(filter => filter.attributeKey === key);
|
||||||
|
return type.attributeModel;
|
||||||
|
},
|
||||||
getInputType(key) {
|
getInputType(key) {
|
||||||
const type = this.filterTypes.find(filter => filter.attributeKey === key);
|
const type = this.filterTypes.find(filter => filter.attributeKey === key);
|
||||||
return type.inputType;
|
return type.inputType;
|
||||||
|
|
|
@ -64,7 +64,7 @@
|
||||||
<contacts-advanced-filters
|
<contacts-advanced-filters
|
||||||
v-if="showFiltersModal"
|
v-if="showFiltersModal"
|
||||||
:on-close="onToggleFilters"
|
:on-close="onToggleFilters"
|
||||||
:filter-types="contactFilterItems"
|
:initial-filter-types="contactFilterItems"
|
||||||
@applyFilter="onApplyFilter"
|
@applyFilter="onApplyFilter"
|
||||||
@clearFilters="clearFilters"
|
@clearFilters="clearFilters"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,27 +1,14 @@
|
||||||
|
import {
|
||||||
|
OPERATOR_TYPES_1,
|
||||||
|
OPERATOR_TYPES_3,
|
||||||
|
} from 'dashboard/components/widgets/FilterInput/FilterOperatorTypes.js';
|
||||||
const filterTypes = [
|
const filterTypes = [
|
||||||
{
|
{
|
||||||
attributeKey: 'name',
|
attributeKey: 'name',
|
||||||
attributeI18nKey: 'NAME',
|
attributeI18nKey: 'NAME',
|
||||||
inputType: 'plain_text',
|
inputType: 'plain_text',
|
||||||
dataType: 'text',
|
dataType: 'text',
|
||||||
filterOperators: [
|
filterOperators: OPERATOR_TYPES_1,
|
||||||
{
|
|
||||||
value: 'equal_to',
|
|
||||||
label: 'Equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'not_equal_to',
|
|
||||||
label: 'Not equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'contains',
|
|
||||||
label: 'Contains',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'does_not_contain',
|
|
||||||
label: 'Does not contain',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
attribute_type: 'standard',
|
attribute_type: 'standard',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -29,24 +16,7 @@ const filterTypes = [
|
||||||
attributeI18nKey: 'EMAIL',
|
attributeI18nKey: 'EMAIL',
|
||||||
inputType: 'plain_text',
|
inputType: 'plain_text',
|
||||||
dataType: 'text',
|
dataType: 'text',
|
||||||
filterOperators: [
|
filterOperators: OPERATOR_TYPES_3,
|
||||||
{
|
|
||||||
value: 'equal_to',
|
|
||||||
label: 'Equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'not_equal_to',
|
|
||||||
label: 'Not equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'contains',
|
|
||||||
label: 'Contains',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'does_not_contain',
|
|
||||||
label: 'Does not contain',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
attribute_type: 'standard',
|
attribute_type: 'standard',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -54,24 +24,7 @@ const filterTypes = [
|
||||||
attributeI18nKey: 'PHONE_NUMBER',
|
attributeI18nKey: 'PHONE_NUMBER',
|
||||||
inputType: 'plain_text',
|
inputType: 'plain_text',
|
||||||
dataType: 'text',
|
dataType: 'text',
|
||||||
filterOperators: [
|
filterOperators: OPERATOR_TYPES_3,
|
||||||
{
|
|
||||||
value: 'equal_to',
|
|
||||||
label: 'Equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'not_equal_to',
|
|
||||||
label: 'Not equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'contains',
|
|
||||||
label: 'Contains',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'does_not_contain',
|
|
||||||
label: 'Does not contain',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
attribute_type: 'standard',
|
attribute_type: 'standard',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -79,16 +32,7 @@ const filterTypes = [
|
||||||
attributeI18nKey: 'IDENTIFIER',
|
attributeI18nKey: 'IDENTIFIER',
|
||||||
inputType: 'plain_text',
|
inputType: 'plain_text',
|
||||||
dataType: 'number',
|
dataType: 'number',
|
||||||
filterOperators: [
|
filterOperators: OPERATOR_TYPES_1,
|
||||||
{
|
|
||||||
value: 'equal_to',
|
|
||||||
label: 'Equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'not_equal_to',
|
|
||||||
label: 'Not equal to',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
attribute_type: 'standard',
|
attribute_type: 'standard',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -96,16 +40,7 @@ const filterTypes = [
|
||||||
attributeI18nKey: 'COUNTRY',
|
attributeI18nKey: 'COUNTRY',
|
||||||
inputType: 'search_select',
|
inputType: 'search_select',
|
||||||
dataType: 'number',
|
dataType: 'number',
|
||||||
filterOperators: [
|
filterOperators: OPERATOR_TYPES_1,
|
||||||
{
|
|
||||||
value: 'equal_to',
|
|
||||||
label: 'Equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'not_equal_to',
|
|
||||||
label: 'Not equal to',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
attribute_type: 'standard',
|
attribute_type: 'standard',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -113,26 +48,42 @@ const filterTypes = [
|
||||||
attributeI18nKey: 'CITY',
|
attributeI18nKey: 'CITY',
|
||||||
inputType: 'plain_text',
|
inputType: 'plain_text',
|
||||||
dataType: 'Number',
|
dataType: 'Number',
|
||||||
filterOperators: [
|
filterOperators: OPERATOR_TYPES_3,
|
||||||
{
|
|
||||||
value: 'equal_to',
|
|
||||||
label: 'Equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'not_equal_to',
|
|
||||||
label: 'Not equal to',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'contains',
|
|
||||||
label: 'Contains',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: 'does_not_contain',
|
|
||||||
label: 'Does not contain',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
attribute_type: 'standard',
|
attribute_type: 'standard',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const filterAttributeGroups = [
|
||||||
|
{
|
||||||
|
name: 'Standard Filters',
|
||||||
|
i18nGroup: 'STANDARD_FILTERS',
|
||||||
|
attributes: [
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
i18nKey: 'NAME',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'email',
|
||||||
|
i18nKey: 'EMAIL',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'phone_number',
|
||||||
|
i18nKey: 'PHONE_NUMBER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'identifier',
|
||||||
|
i18nKey: 'IDENTIFIER',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'country_code',
|
||||||
|
i18nKey: 'COUNTRY',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'city',
|
||||||
|
i18nKey: 'CITY',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export default filterTypes;
|
export default filterTypes;
|
||||||
|
|
44
app/javascript/shared/mixins/filterMixin.js
Normal file
44
app/javascript/shared/mixins/filterMixin.js
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
// import groupBy from 'lodash.groupby';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
setFilterAttributes() {
|
||||||
|
const allCustomAttributes = this.$store.getters[
|
||||||
|
'attributes/getAttributesByModel'
|
||||||
|
](this.attributeModel);
|
||||||
|
const customAttributesFormatted = {
|
||||||
|
name: this.$t(`${this.filtersFori18n}.GROUPS.CUSTOM_ATTRIBUTES`),
|
||||||
|
attributes: allCustomAttributes.map(attr => {
|
||||||
|
return {
|
||||||
|
key: attr.attribute_key,
|
||||||
|
name: attr.attribute_display_name,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
const allFilterGroups = this.filterAttributeGroups.map(group => {
|
||||||
|
return {
|
||||||
|
name: this.$t(`${this.filtersFori18n}.GROUPS.${group.i18nGroup}`),
|
||||||
|
attributes: group.attributes.map(attribute => {
|
||||||
|
return {
|
||||||
|
key: attribute.key,
|
||||||
|
name: this.$t(
|
||||||
|
`${this.filtersFori18n}.ATTRIBUTES.${attribute.i18nKey}`
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const customAttributeTypes = allCustomAttributes.map(attr => {
|
||||||
|
return {
|
||||||
|
attributeKey: attr.attribute_key,
|
||||||
|
attributeI18nKey: `CUSTOM_ATTRIBUTE_${attr.attribute_display_type.toUpperCase()}`,
|
||||||
|
inputType: this.customAttributeInputType(attr.attribute_display_type),
|
||||||
|
filterOperators: this.getOperatorTypes(attr.attribute_display_type),
|
||||||
|
attributeModel: 'custom_attributes',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
this.filterTypes = [...this.filterTypes, ...customAttributeTypes];
|
||||||
|
this.filterGroups = [...allFilterGroups, customAttributesFormatted];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
9
app/javascript/shared/mixins/specs/MockComponent.vue
Normal file
9
app/javascript/shared/mixins/specs/MockComponent.vue
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<template>
|
||||||
|
<div class="test"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'MockComponent',
|
||||||
|
};
|
||||||
|
</script>
|
29
app/javascript/shared/mixins/specs/filterFixtures.js
Normal file
29
app/javascript/shared/mixins/specs/filterFixtures.js
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
export const filterGroups = [
|
||||||
|
{
|
||||||
|
name: 'Standard Filters',
|
||||||
|
attributes: [
|
||||||
|
{ key: 'status', name: 'Status' },
|
||||||
|
{ key: 'assignee_id', name: 'Assignee Name' },
|
||||||
|
{ key: 'inbox_id', name: 'Inbox Name' },
|
||||||
|
{ key: 'team_id', name: 'Team Name' },
|
||||||
|
{ key: 'display_id', name: 'Conversation Identifier' },
|
||||||
|
{ key: 'campaign_id', name: 'Campaign Name' },
|
||||||
|
{ key: 'labels', name: 'Labels' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Additional Filters',
|
||||||
|
attributes: [
|
||||||
|
{ key: 'browser_language', name: 'Browser Language' },
|
||||||
|
{ key: 'country_code', name: 'Country Name' },
|
||||||
|
{ key: 'referer', name: 'Referer link' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Custom Attributes',
|
||||||
|
attributes: [
|
||||||
|
{ key: 'signed_up_at', name: 'Signed Up At' },
|
||||||
|
{ key: 'test', name: 'Test' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
13
app/javascript/shared/mixins/specs/filterMixin.spec.js
Normal file
13
app/javascript/shared/mixins/specs/filterMixin.spec.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import filterMixin from '../filterMixin';
|
||||||
|
import { shallowMount } from '@vue/test-utils';
|
||||||
|
import MockComponent from './MockComponent.vue';
|
||||||
|
|
||||||
|
describe('Test mixin function', () => {
|
||||||
|
const wrapper = shallowMount(MockComponent, {
|
||||||
|
mixins: [filterMixin],
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return proper value from bool', () => {
|
||||||
|
expect(wrapper.vm.setFilterAttributes).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in a new issue