diff --git a/.codeclimate.yml b/.codeclimate.yml index 5e16262da..213f7d172 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -57,3 +57,5 @@ exclude_patterns: - 'app/javascript/shared/constants/locales.js' - 'app/javascript/dashboard/helper/specs/macrosFixtures.js' - 'app/javascript/dashboard/routes/dashboard/settings/macros/constants.js' + - '**/fixtures/**' + - '**/*/fixtures.js' diff --git a/app/javascript/dashboard/components-next/filter/ConditionRow.story.vue b/app/javascript/dashboard/components-next/filter/ConditionRow.story.vue new file mode 100644 index 000000000..4c4c3c80b --- /dev/null +++ b/app/javascript/dashboard/components-next/filter/ConditionRow.story.vue @@ -0,0 +1,58 @@ + + + diff --git a/app/javascript/dashboard/components-next/filter/ConditionRow.vue b/app/javascript/dashboard/components-next/filter/ConditionRow.vue new file mode 100644 index 000000000..079313933 --- /dev/null +++ b/app/javascript/dashboard/components-next/filter/ConditionRow.vue @@ -0,0 +1,197 @@ + + + diff --git a/app/javascript/dashboard/components-next/filter/fixtures/filterTypes.js b/app/javascript/dashboard/components-next/filter/fixtures/filterTypes.js new file mode 100644 index 000000000..fcec5eb08 --- /dev/null +++ b/app/javascript/dashboard/components-next/filter/fixtures/filterTypes.js @@ -0,0 +1,558 @@ +export const filterTypes = [ + { + attributeKey: 'status', + value: 'status', + attributeName: 'Status', + label: 'Status', + inputType: 'multiSelect', + options: [ + { id: 'open', name: 'Open' }, + { id: 'resolved', name: 'Resolved' }, + { id: 'pending', name: 'Pending' }, + { id: 'snoozed', name: 'Snoozed' }, + { id: 'all', name: 'All' }, + ], + dataType: 'text', + filterOperators: [ + { + value: 'equal_to', + label: 'Equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-equals-bold', + }, + { + value: 'not_equal_to', + label: 'Not equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-not-equals-bold', + }, + ], + attributeModel: 'standard', + }, + { + attributeKey: 'assignee_id', + value: 'assignee_id', + attributeName: 'Assignee name', + label: 'Assignee name', + inputType: 'searchSelect', + options: [ + { id: 14, name: 'Ben Nugent' }, + { id: 30, name: 'Bruce' }, + { id: 16, name: 'Cathy Simms' }, + { id: 7, name: 'Charles Miner' }, + { id: 10, name: 'Craig D' }, + { id: 9, name: 'Dan Gore' }, + { id: 13, name: 'Danny Cordray' }, + { id: 3, name: 'David Wallace' }, + { id: 4, name: 'Deangelo Vickers' }, + { id: 33, name: 'Devon White' }, + { id: 8, name: 'Ed Truck' }, + { id: 31, name: 'Frank' }, + { id: 29, name: 'Gideon' }, + { id: 24, name: 'Glenn Max' }, + ], + dataType: 'text', + filterOperators: [ + { + value: 'equal_to', + label: 'Equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-equals-bold', + }, + { + value: 'not_equal_to', + label: 'Not equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-not-equals-bold', + }, + { + value: 'is_present', + label: 'Is present', + hasInput: false, + inputOverride: null, + icon: 'i-ph-member-of-bold', + }, + { + value: 'is_not_present', + label: 'Is not present', + hasInput: false, + inputOverride: null, + icon: 'i-ph-not-member-of', + }, + ], + attributeModel: 'standard', + }, + { + attributeKey: 'team_id', + value: 'team_id', + attributeName: 'Team name', + label: 'Team name', + inputType: 'searchSelect', + options: [ + { id: 223, name: '💰 sales' }, + { id: 224, name: '💼 management' }, + { id: 225, name: '👩‍💼 administration' }, + { id: 226, name: '🚛 warehouse' }, + ], + dataType: 'number', + filterOperators: [ + { + value: 'equal_to', + label: 'Equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-equals-bold', + }, + { + value: 'not_equal_to', + label: 'Not equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-not-equals-bold', + }, + { + value: 'is_present', + label: 'Is present', + hasInput: false, + inputOverride: null, + icon: 'i-ph-member-of-bold', + }, + { + value: 'is_not_present', + label: 'Is not present', + hasInput: false, + inputOverride: null, + icon: 'i-ph-not-member-of', + }, + ], + attributeModel: 'standard', + }, + { + attributeKey: 'display_id', + value: 'display_id', + attributeName: 'Conversation identifier', + label: 'Conversation identifier', + inputType: 'plainText', + datatype: 'number', + filterOperators: [ + { + value: 'equal_to', + label: 'Equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-equals-bold', + }, + { + value: 'not_equal_to', + label: 'Not equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-not-equals-bold', + }, + { + value: 'contains', + label: 'Contains', + hasInput: true, + inputOverride: null, + icon: 'i-ph-superset-of-bold', + }, + { + value: 'does_not_contain', + label: 'Does not contain', + hasInput: true, + inputOverride: null, + icon: 'i-ph-not-superset-of', + }, + ], + attributeModel: 'standard', + }, + { + attributeKey: 'campaign_id', + value: 'campaign_id', + attributeName: 'Campaign name', + label: 'Campaign name', + inputType: 'searchSelect', + options: [], + datatype: 'number', + filterOperators: [ + { + value: 'equal_to', + label: 'Equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-equals-bold', + }, + { + value: 'not_equal_to', + label: 'Not equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-not-equals-bold', + }, + { + value: 'is_present', + label: 'Is present', + hasInput: false, + inputOverride: null, + icon: 'i-ph-member-of-bold', + }, + { + value: 'is_not_present', + label: 'Is not present', + hasInput: false, + inputOverride: null, + icon: 'i-ph-not-member-of', + }, + ], + attributeModel: 'standard', + }, + { + attributeKey: 'labels', + value: 'labels', + attributeName: 'Labels', + label: 'Labels', + inputType: 'multiSelect', + options: [ + { id: 'billing', name: 'billing' }, + { id: 'delivery', name: 'delivery' }, + { id: 'lead', name: 'lead' }, + { id: 'ops-handover', name: 'ops-handover' }, + { id: 'premium-customer', name: 'premium-customer' }, + { id: 'software', name: 'software' }, + ], + dataType: 'text', + filterOperators: [ + { + value: 'equal_to', + label: 'Equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-equals-bold', + }, + { + value: 'not_equal_to', + label: 'Not equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-not-equals-bold', + }, + { + value: 'is_present', + label: 'Is present', + hasInput: false, + inputOverride: null, + icon: 'i-ph-member-of-bold', + }, + { + value: 'is_not_present', + label: 'Is not present', + hasInput: false, + inputOverride: null, + icon: 'i-ph-not-member-of', + }, + ], + attributeModel: 'standard', + }, + { + attributeKey: 'referer', + value: 'referer', + attributeName: 'Referer link', + label: 'Referer link', + inputType: 'plainText', + dataType: 'text', + filterOperators: [ + { + value: 'equal_to', + label: 'Equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-equals-bold', + }, + { + value: 'not_equal_to', + label: 'Not equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-not-equals-bold', + }, + { + value: 'contains', + label: 'Contains', + hasInput: true, + inputOverride: null, + icon: 'i-ph-superset-of-bold', + }, + { + value: 'does_not_contain', + label: 'Does not contain', + hasInput: true, + inputOverride: null, + icon: 'i-ph-not-superset-of', + }, + ], + attributeModel: 'additional', + }, + { + attributeKey: 'created_at', + value: 'created_at', + attributeName: 'Created at', + label: 'Created at', + inputType: 'date', + dataType: 'text', + filterOperators: [ + { + value: 'is_greater_than', + label: 'Is greater than', + hasInput: true, + inputOverride: null, + icon: 'i-ph-greater-than-bold', + }, + { + value: 'is_less_than', + label: 'Is lesser than', + hasInput: true, + inputOverride: null, + icon: 'i-ph-less-than-bold', + }, + { + value: 'days_before', + label: 'Is x days before', + hasInput: true, + inputOverride: 'plainText', + icon: 'i-ph-calendar-minus-bold', + }, + ], + attributeModel: 'standard', + }, + { + attributeKey: 'last_activity_at', + value: 'last_activity_at', + attributeName: 'Last activity', + label: 'Last activity', + inputType: 'date', + dataType: 'text', + filterOperators: [ + { + value: 'is_greater_than', + label: 'Is greater than', + hasInput: true, + inputOverride: null, + icon: 'i-ph-greater-than-bold', + }, + { + value: 'is_less_than', + label: 'Is lesser than', + hasInput: true, + inputOverride: null, + icon: 'i-ph-less-than-bold', + }, + { + value: 'days_before', + label: 'Is x days before', + hasInput: true, + inputOverride: 'plainText', + icon: 'i-ph-calendar-minus-bold', + }, + ], + attributeModel: 'standard', + }, + { + attributeKey: 'are_you_a_paid_customer', + value: 'are_you_a_paid_customer', + attributeName: 'Are you a paid customer?', + label: 'Are you a paid customer?', + inputType: 'booleanSelect', + filterOperators: [ + { + value: 'equal_to', + label: 'Equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-equals-bold', + }, + { + value: 'not_equal_to', + label: 'Not equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-not-equals-bold', + }, + ], + options: [], + attributeModel: 'customAttributes', + }, + { + attributeKey: 'date_of_purchase', + value: 'date_of_purchase', + attributeName: 'Date of Purchase', + label: 'Date of Purchase', + inputType: 'date', + filterOperators: [ + { + value: 'equal_to', + label: 'Equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-equals-bold', + }, + { + value: 'not_equal_to', + label: 'Not equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-not-equals-bold', + }, + { + value: 'is_present', + label: 'Is present', + hasInput: false, + inputOverride: null, + icon: 'i-ph-member-of-bold', + }, + { + value: 'is_not_present', + label: 'Is not present', + hasInput: false, + inputOverride: null, + icon: 'i-ph-not-member-of', + }, + { + value: 'is_greater_than', + label: 'Is greater than', + hasInput: true, + inputOverride: null, + icon: 'i-ph-greater-than-bold', + }, + { + value: 'is_less_than', + label: 'Is lesser than', + hasInput: true, + inputOverride: null, + icon: 'i-ph-less-than-bold', + }, + ], + options: [], + attributeModel: 'customAttributes', + }, + { + attributeKey: 'your_website', + value: 'your_website', + attributeName: 'Your website', + label: 'Your website', + inputType: 'plainText', + filterOperators: [ + { + value: 'equal_to', + label: 'Equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-equals-bold', + }, + { + value: 'not_equal_to', + label: 'Not equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-not-equals-bold', + }, + ], + options: [], + attributeModel: 'customAttributes', + }, + { + attributeKey: 'are_you_residing_in_india', + value: 'are_you_residing_in_india', + attributeName: 'Are you residing in India?', + label: 'Are you residing in India?', + inputType: 'booleanSelect', + filterOperators: [ + { + value: 'equal_to', + label: 'Equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-equals-bold', + }, + { + value: 'not_equal_to', + label: 'Not equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-not-equals-bold', + }, + ], + options: [], + attributeModel: 'customAttributes', + }, + { + attributeKey: 'cloud', + value: 'cloud', + attributeName: 'Cloud', + label: 'Cloud', + inputType: 'booleanSelect', + filterOperators: [ + { + value: 'equal_to', + label: 'Equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-equals-bold', + }, + { + value: 'not_equal_to', + label: 'Not equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-not-equals-bold', + }, + ], + options: [], + attributeModel: 'customAttributes', + }, + { + attributeKey: 'license_type', + value: 'license_type', + attributeName: 'License Type', + label: 'License Type', + inputType: 'searchSelect', + filterOperators: [ + { + value: 'equal_to', + label: 'Equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-equals-bold', + }, + { + value: 'not_equal_to', + label: 'Not equal to', + hasInput: true, + inputOverride: null, + icon: 'i-ph-not-equals-bold', + }, + ], + options: [ + { + id: 'Personal', + name: 'Personal', + }, + { + id: 'Enterprise', + name: 'Enterprise', + }, + { + id: 'Teams', + name: 'Teams', + }, + { + id: 'Professional', + name: 'Professional', + }, + ], + attributeModel: 'customAttributes', + }, +]; diff --git a/app/javascript/dashboard/helper/validations.js b/app/javascript/dashboard/helper/validations.js index 352e5397e..155108c61 100644 --- a/app/javascript/dashboard/helper/validations.js +++ b/app/javascript/dashboard/helper/validations.js @@ -20,7 +20,7 @@ export const ATLEAST_ONE_ACTION_REQUIRED = 'ATLEAST_ONE_ACTION_REQUIRED'; * * @returns {string|null} An error message if validation fails, or null if validation passes. */ -const validateSingleFilter = filter => { +export const validateSingleFilter = filter => { if (!filter.attribute_key) { return ATTRIBUTE_KEY_REQUIRED; } diff --git a/tailwind.config.js b/tailwind.config.js index 69c4c4bf3..9af26b294 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -29,6 +29,7 @@ const tailwindConfig = { './app/javascript/shared/**/*.vue', './app/javascript/survey/**/*.vue', './app/javascript/dashboard/helper/**/*.js', + './app/javascript/dashboard/components-next/**/*.js', './app/views/**/*.html.erb', ], theme: { @@ -112,6 +113,11 @@ const tailwindConfig = { collections: { woot: { icons: { + 'logic-or': { + body: ``, + width: 24, + height: 24, + }, alert: { body: ``, width: 2,