feature: Filtering conversations and contacts with custom attributes (#3851)

This commit is contained in:
Fayaz Ahmed 2022-02-01 13:13:55 +05:30 committed by GitHub
parent e0d24e0a73
commit 52d1821cd3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 451 additions and 284 deletions

View file

@ -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'

View file

@ -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"
/> />

View file

@ -30,7 +30,7 @@ export default {
}, },
value: { value: {
type: Date, type: Date,
default: () => [], default: [],
}, },
}, },

View file

@ -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',
},
];

View file

@ -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: {

View file

@ -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;

View file

@ -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 = [
{
name: 'Standard Filters',
i18nGroup: 'STANDARD_FILTERS',
attributes: [
{ {
value: 'equal_to', key: 'status',
label: 'Equal to', 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',
}, },
]; ];

View file

@ -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": {

View file

@ -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"
} }
} }
} }

View file

@ -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;

View file

@ -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"
/> />

View file

@ -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;

View 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];
},
},
};

View file

@ -0,0 +1,9 @@
<template>
<div class="test"></div>
</template>
<script>
export default {
name: 'MockComponent',
};
</script>

View 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' },
],
},
];

View 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();
});
});