mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-10-31 02:57:57 +00:00 
			
		
		
		
	feat(ee): Add support for SLA in automation rules (#8910)
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
This commit is contained in:
		| @@ -129,7 +129,13 @@ export const agentList = agents => [ | |||||||
|   ...(agents || []), |   ...(agents || []), | ||||||
| ]; | ]; | ||||||
|  |  | ||||||
| export const getActionOptions = ({ agents, teams, labels, type }) => { | export const getActionOptions = ({ | ||||||
|  |   agents, | ||||||
|  |   teams, | ||||||
|  |   labels, | ||||||
|  |   slaPolicies, | ||||||
|  |   type, | ||||||
|  | }) => { | ||||||
|   const actionsMap = { |   const actionsMap = { | ||||||
|     assign_agent: agentList(agents), |     assign_agent: agentList(agents), | ||||||
|     assign_team: teams, |     assign_team: teams, | ||||||
| @@ -137,6 +143,7 @@ export const getActionOptions = ({ agents, teams, labels, type }) => { | |||||||
|     add_label: generateConditionOptions(labels, 'title'), |     add_label: generateConditionOptions(labels, 'title'), | ||||||
|     remove_label: generateConditionOptions(labels, 'title'), |     remove_label: generateConditionOptions(labels, 'title'), | ||||||
|     change_priority: PRIORITY_CONDITION_VALUES, |     change_priority: PRIORITY_CONDITION_VALUES, | ||||||
|  |     add_sla: slaPolicies, | ||||||
|   }; |   }; | ||||||
|   return actionsMap[type]; |   return actionsMap[type]; | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -27,6 +27,7 @@ export default { | |||||||
|       inboxes: 'inboxes/getInboxes', |       inboxes: 'inboxes/getInboxes', | ||||||
|       labels: 'labels/getLabels', |       labels: 'labels/getLabels', | ||||||
|       teams: 'teams/getTeams', |       teams: 'teams/getTeams', | ||||||
|  |       slaPolicies: 'sla/getSLA', | ||||||
|     }), |     }), | ||||||
|     booleanFilterOptions() { |     booleanFilterOptions() { | ||||||
|       return [ |       return [ | ||||||
| @@ -257,8 +258,15 @@ export default { | |||||||
|       }; |       }; | ||||||
|     }, |     }, | ||||||
|     getActionDropdownValues(type) { |     getActionDropdownValues(type) { | ||||||
|       const { agents, labels, teams } = this; |       const { agents, labels, teams, slaPolicies } = this; | ||||||
|       return getActionOptions({ agents, labels, teams, languages, type }); |       return getActionOptions({ | ||||||
|  |         agents, | ||||||
|  |         labels, | ||||||
|  |         teams, | ||||||
|  |         slaPolicies, | ||||||
|  |         languages, | ||||||
|  |         type, | ||||||
|  |       }); | ||||||
|     }, |     }, | ||||||
|     manifestCustomAttributes() { |     manifestCustomAttributes() { | ||||||
|       const conversationCustomAttributesRaw = this.$store.getters[ |       const conversationCustomAttributesRaw = this.$store.getters[ | ||||||
|   | |||||||
| @@ -144,6 +144,7 @@ | |||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
|  | import { mapGetters } from 'vuex'; | ||||||
| import alertMixin from 'shared/mixins/alertMixin'; | import alertMixin from 'shared/mixins/alertMixin'; | ||||||
| import automationMethodsMixin from 'dashboard/mixins/automations/methodsMixin'; | import automationMethodsMixin from 'dashboard/mixins/automations/methodsMixin'; | ||||||
| import automationValidationsMixin from 'dashboard/mixins/automations/validationsMixin'; | import automationValidationsMixin from 'dashboard/mixins/automations/validationsMixin'; | ||||||
| @@ -173,7 +174,6 @@ export default { | |||||||
|       automationTypes: JSON.parse(JSON.stringify(AUTOMATIONS)), |       automationTypes: JSON.parse(JSON.stringify(AUTOMATIONS)), | ||||||
|       automationRuleEvent: AUTOMATION_RULE_EVENTS[0].key, |       automationRuleEvent: AUTOMATION_RULE_EVENTS[0].key, | ||||||
|       automationRuleEvents: AUTOMATION_RULE_EVENTS, |       automationRuleEvents: AUTOMATION_RULE_EVENTS, | ||||||
|       automationActionTypes: AUTOMATION_ACTION_TYPES, |  | ||||||
|       automationMutated: false, |       automationMutated: false, | ||||||
|       show: true, |       show: true, | ||||||
|       automation: { |       automation: { | ||||||
| @@ -202,6 +202,10 @@ export default { | |||||||
|     }; |     }; | ||||||
|   }, |   }, | ||||||
|   computed: { |   computed: { | ||||||
|  |     ...mapGetters({ | ||||||
|  |       accountId: 'getCurrentAccountId', | ||||||
|  |       isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount', | ||||||
|  |     }), | ||||||
|     hasAutomationMutated() { |     hasAutomationMutated() { | ||||||
|       if ( |       if ( | ||||||
|         this.automation.conditions[0].values || |         this.automation.conditions[0].values || | ||||||
| @@ -210,6 +214,12 @@ export default { | |||||||
|         return true; |         return true; | ||||||
|       return false; |       return false; | ||||||
|     }, |     }, | ||||||
|  |     automationActionTypes() { | ||||||
|  |       const isSLAEnabled = this.isFeatureEnabled('sla'); | ||||||
|  |       return isSLAEnabled | ||||||
|  |         ? AUTOMATION_ACTION_TYPES | ||||||
|  |         : AUTOMATION_ACTION_TYPES.filter(action => action.key !== 'add_sla'); | ||||||
|  |     }, | ||||||
|   }, |   }, | ||||||
|   mounted() { |   mounted() { | ||||||
|     this.$store.dispatch('inboxes/get'); |     this.$store.dispatch('inboxes/get'); | ||||||
| @@ -221,6 +231,11 @@ export default { | |||||||
|     this.allCustomAttributes = this.$store.getters['attributes/getAttributes']; |     this.allCustomAttributes = this.$store.getters['attributes/getAttributes']; | ||||||
|     this.manifestCustomAttributes(); |     this.manifestCustomAttributes(); | ||||||
|   }, |   }, | ||||||
|  |   methods: { | ||||||
|  |     isFeatureEnabled(flag) { | ||||||
|  |       return this.isFeatureEnabledonAccount(this.accountId, flag); | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
| }; | }; | ||||||
| </script> | </script> | ||||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||||
|   | |||||||
| @@ -142,6 +142,7 @@ | |||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script> | <script> | ||||||
|  | import { mapGetters } from 'vuex'; | ||||||
| import alertMixin from 'shared/mixins/alertMixin'; | import alertMixin from 'shared/mixins/alertMixin'; | ||||||
| import automationMethodsMixin from 'dashboard/mixins/automations/methodsMixin'; | import automationMethodsMixin from 'dashboard/mixins/automations/methodsMixin'; | ||||||
| import automationValidationsMixin from 'dashboard/mixins/automations/validationsMixin'; | import automationValidationsMixin from 'dashboard/mixins/automations/validationsMixin'; | ||||||
| @@ -175,7 +176,6 @@ export default { | |||||||
|       automationTypes: JSON.parse(JSON.stringify(AUTOMATIONS)), |       automationTypes: JSON.parse(JSON.stringify(AUTOMATIONS)), | ||||||
|       automationRuleEvent: AUTOMATION_RULE_EVENTS[0].key, |       automationRuleEvent: AUTOMATION_RULE_EVENTS[0].key, | ||||||
|       automationRuleEvents: AUTOMATION_RULE_EVENTS, |       automationRuleEvents: AUTOMATION_RULE_EVENTS, | ||||||
|       automationActionTypes: AUTOMATION_ACTION_TYPES, |  | ||||||
|       automationMutated: false, |       automationMutated: false, | ||||||
|       show: true, |       show: true, | ||||||
|       automation: null, |       automation: null, | ||||||
| @@ -185,6 +185,10 @@ export default { | |||||||
|     }; |     }; | ||||||
|   }, |   }, | ||||||
|   computed: { |   computed: { | ||||||
|  |     ...mapGetters({ | ||||||
|  |       accountId: 'getCurrentAccountId', | ||||||
|  |       isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount', | ||||||
|  |     }), | ||||||
|     hasAutomationMutated() { |     hasAutomationMutated() { | ||||||
|       if ( |       if ( | ||||||
|         this.automation.conditions[0].values || |         this.automation.conditions[0].values || | ||||||
| @@ -193,12 +197,23 @@ export default { | |||||||
|         return true; |         return true; | ||||||
|       return false; |       return false; | ||||||
|     }, |     }, | ||||||
|  |     automationActionTypes() { | ||||||
|  |       const isSLAEnabled = this.isFeatureEnabled('sla'); | ||||||
|  |       return isSLAEnabled | ||||||
|  |         ? AUTOMATION_ACTION_TYPES | ||||||
|  |         : AUTOMATION_ACTION_TYPES.filter(action => action.key !== 'add_sla'); | ||||||
|  |     }, | ||||||
|   }, |   }, | ||||||
|   mounted() { |   mounted() { | ||||||
|     this.manifestCustomAttributes(); |     this.manifestCustomAttributes(); | ||||||
|     this.allCustomAttributes = this.$store.getters['attributes/getAttributes']; |     this.allCustomAttributes = this.$store.getters['attributes/getAttributes']; | ||||||
|     this.formatAutomation(this.selectedResponse); |     this.formatAutomation(this.selectedResponse); | ||||||
|   }, |   }, | ||||||
|  |   methods: { | ||||||
|  |     isFeatureEnabled(flag) { | ||||||
|  |       return this.isFeatureEnabledonAccount(this.accountId, flag); | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
| }; | }; | ||||||
| </script> | </script> | ||||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||||
|   | |||||||
| @@ -153,6 +153,8 @@ export default { | |||||||
|     ...mapGetters({ |     ...mapGetters({ | ||||||
|       records: ['automations/getAutomations'], |       records: ['automations/getAutomations'], | ||||||
|       uiFlags: 'automations/getUIFlags', |       uiFlags: 'automations/getUIFlags', | ||||||
|  |       accountId: 'getCurrentAccountId', | ||||||
|  |       isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount', | ||||||
|     }), |     }), | ||||||
|     // Delete Modal |     // Delete Modal | ||||||
|     deleteConfirmText() { |     deleteConfirmText() { | ||||||
| @@ -168,6 +170,9 @@ export default { | |||||||
|     deleteMessage() { |     deleteMessage() { | ||||||
|       return ` ${this.selectedResponse.name}?`; |       return ` ${this.selectedResponse.name}?`; | ||||||
|     }, |     }, | ||||||
|  |     isSLAEnabled() { | ||||||
|  |       return this.isFeatureEnabledonAccount(this.accountId, 'sla'); | ||||||
|  |     }, | ||||||
|   }, |   }, | ||||||
|   mounted() { |   mounted() { | ||||||
|     this.$store.dispatch('inboxes/get'); |     this.$store.dispatch('inboxes/get'); | ||||||
| @@ -177,6 +182,7 @@ export default { | |||||||
|     this.$store.dispatch('labels/get'); |     this.$store.dispatch('labels/get'); | ||||||
|     this.$store.dispatch('campaigns/get'); |     this.$store.dispatch('campaigns/get'); | ||||||
|     this.$store.dispatch('automations/get'); |     this.$store.dispatch('automations/get'); | ||||||
|  |     if (this.isSLAEnabled) this.$store.dispatch('sla/get'); | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|     openAddPopup() { |     openAddPopup() { | ||||||
|   | |||||||
| @@ -611,4 +611,9 @@ export const AUTOMATION_ACTION_TYPES = [ | |||||||
|     label: 'Change Priority', |     label: 'Change Priority', | ||||||
|     inputType: 'search_select', |     inputType: 'search_select', | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     key: 'add_sla', | ||||||
|  |     label: 'Add SLA', | ||||||
|  |     inputType: 'search_select', | ||||||
|  |   }, | ||||||
| ]; | ]; | ||||||
|   | |||||||
| @@ -111,12 +111,26 @@ export default { | |||||||
|     ...mapGetters({ |     ...mapGetters({ | ||||||
|       records: 'sla/getSLA', |       records: 'sla/getSLA', | ||||||
|       uiFlags: 'sla/getUIFlags', |       uiFlags: 'sla/getUIFlags', | ||||||
|  |       accountId: 'getCurrentAccountId', | ||||||
|  |       isFeatureEnabledonAccount: 'accounts/isFeatureEnabledonAccount', | ||||||
|     }), |     }), | ||||||
|  |     isSLAEnabled() { | ||||||
|  |       return this.isFeatureEnabledonAccount(this.accountId, 'sla'); | ||||||
|  |     }, | ||||||
|   }, |   }, | ||||||
|   mounted() { |   mounted() { | ||||||
|     this.$store.dispatch('sla/get'); |     this.isSLAfeatureEnabled(); | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|  |     isSLAfeatureEnabled() { | ||||||
|  |       if (!this.isSLAEnabled) { | ||||||
|  |         this.$router.push({ | ||||||
|  |           name: 'general_settings_index', | ||||||
|  |         }); | ||||||
|  |       } else { | ||||||
|  |         this.$store.dispatch('sla/get'); | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|     openAddPopup() { |     openAddPopup() { | ||||||
|       this.showAddPopup = true; |       this.showAddPopup = true; | ||||||
|     }, |     }, | ||||||
|   | |||||||
| @@ -762,3 +762,45 @@ export const expectedOutputForCustomAttributeGenerator = [ | |||||||
|     ], |     ], | ||||||
|   }, |   }, | ||||||
| ]; | ]; | ||||||
|  | export const slaPolicies = [ | ||||||
|  |   { | ||||||
|  |     id: 1, | ||||||
|  |     account_id: 1, | ||||||
|  |     name: 'Low', | ||||||
|  |     first_response_time_threshold: 60, | ||||||
|  |     next_response_time_threshold: 120, | ||||||
|  |     resolution_time_threshold: 240, | ||||||
|  |     created_at: '2022-01-26T08:06:39.470Z', | ||||||
|  |     updated_at: '2022-01-26T08:06:39.470Z', | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     id: 2, | ||||||
|  |     account_id: 1, | ||||||
|  |     name: 'Medium', | ||||||
|  |     first_response_time_threshold: 30, | ||||||
|  |     next_response_time_threshold: 60, | ||||||
|  |     resolution_time_threshold: 120, | ||||||
|  |     created_at: '2022-01-26T08:06:39.470Z', | ||||||
|  |     updated_at: '2022-01-26T08:06:39.470Z', | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     id: 3, | ||||||
|  |     account_id: 1, | ||||||
|  |     name: 'High', | ||||||
|  |     first_response_time_threshold: 15, | ||||||
|  |     next_response_time_threshold: 30, | ||||||
|  |     resolution_time_threshold: 60, | ||||||
|  |     created_at: '2022-01-26T08:06:39.470Z', | ||||||
|  |     updated_at: '2022-01-26T08:06:39.470Z', | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |     id: 4, | ||||||
|  |     account_id: 1, | ||||||
|  |     name: 'Urgent', | ||||||
|  |     first_response_time_threshold: 5, | ||||||
|  |     next_response_time_threshold: 10, | ||||||
|  |     resolution_time_threshold: 20, | ||||||
|  |     created_at: '2022-01-26T08:06:39.470Z', | ||||||
|  |     updated_at: '2022-01-26T08:06:39.470Z', | ||||||
|  |   }, | ||||||
|  | ]; | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ import { | |||||||
|   inboxes, |   inboxes, | ||||||
|   languages, |   languages, | ||||||
|   countries, |   countries, | ||||||
|  |   slaPolicies, | ||||||
|   MESSAGE_CONDITION_VALUES, |   MESSAGE_CONDITION_VALUES, | ||||||
|   automationToSubmit, |   automationToSubmit, | ||||||
|   savedAutomation, |   savedAutomation, | ||||||
| @@ -89,6 +90,9 @@ const generateComputedProperties = () => { | |||||||
|     countries() { |     countries() { | ||||||
|       return countries; |       return countries; | ||||||
|     }, |     }, | ||||||
|  |     slaPolicies() { | ||||||
|  |       return slaPolicies; | ||||||
|  |     }, | ||||||
|     MESSAGE_CONDITION_VALUES() { |     MESSAGE_CONDITION_VALUES() { | ||||||
|       return MESSAGE_CONDITION_VALUES; |       return MESSAGE_CONDITION_VALUES; | ||||||
|     }, |     }, | ||||||
| @@ -433,6 +437,9 @@ describe('automationMethodsMixin', () => { | |||||||
|       teams() { |       teams() { | ||||||
|         return teams; |         return teams; | ||||||
|       }, |       }, | ||||||
|  |       slaPolicies() { | ||||||
|  |         return slaPolicies; | ||||||
|  |       }, | ||||||
|     }; |     }; | ||||||
|     const expectedActionDropdownValues = [ |     const expectedActionDropdownValues = [ | ||||||
|       { id: 'testlabel', name: 'testlabel' }, |       { id: 'testlabel', name: 'testlabel' }, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Vishnu Narayanan
					Vishnu Narayanan