From c674393c0245fa06f0763c176de18f28a6077a82 Mon Sep 17 00:00:00 2001
From: Fayaz Ahmed <15716057+fayazara@users.noreply.github.com>
Date: Tue, 29 Mar 2022 13:27:16 +0530
Subject: [PATCH] feat: New automation actions (#4033)
---
.../accounts/automation_rules_controller.rb | 2 +-
.../widgets/AutomationActionInput.vue | 58 ++++++---
.../settings/automation/AddAutomationRule.vue | 13 +-
.../automation/EditAutomationRule.vue | 1 -
.../settings/automation/constants.js | 122 ++++++++++++++++--
.../concerns/activity_message_handler.rb | 7 +
.../automation_rules/action_service.rb | 14 +-
app/services/filter_service.rb | 8 +-
.../automation_rule_listener_spec.rb | 2 +-
9 files changed, 192 insertions(+), 35 deletions(-)
diff --git a/app/controllers/api/v1/accounts/automation_rules_controller.rb b/app/controllers/api/v1/accounts/automation_rules_controller.rb
index 3971dbcaf..2dc71bcec 100644
--- a/app/controllers/api/v1/accounts/automation_rules_controller.rb
+++ b/app/controllers/api/v1/accounts/automation_rules_controller.rb
@@ -34,7 +34,7 @@ class Api::V1::Accounts::AutomationRulesController < Api::V1::Accounts::BaseCont
params.permit(
:name, :description, :event_name, :account_id, :active,
conditions: [:attribute_key, :filter_operator, :query_operator, { values: [] }],
- actions: [:action_name, { action_params: [{}] }]
+ actions: [:action_name, { action_params: [] }]
)
end
diff --git a/app/javascript/dashboard/components/widgets/AutomationActionInput.vue b/app/javascript/dashboard/components/widgets/AutomationActionInput.vue
index 22521af91..0c8178a9b 100644
--- a/app/javascript/dashboard/components/widgets/AutomationActionInput.vue
+++ b/app/javascript/dashboard/components/widgets/AutomationActionInput.vue
@@ -7,7 +7,8 @@
@@ -91,13 +111,17 @@ export default {
this.$emit('input', { ...payload, action_params: value });
},
},
+ inputType() {
+ return this.actionTypes.find(action => action.key === this.action_name)
+ .inputType;
+ },
},
methods: {
removeAction() {
this.$emit('removeAction');
},
- resetFilter() {
- this.$emit('resetFilter');
+ resetAction() {
+ this.$emit('resetAction');
},
},
};
@@ -136,6 +160,10 @@ export default {
max-width: 50%;
}
+.action__question.full-width {
+ max-width: 100%;
+}
+
.filter__answer--wrap {
margin-right: var(--space-smaller);
flex-grow: 1;
diff --git a/app/javascript/dashboard/routes/dashboard/settings/automation/AddAutomationRule.vue b/app/javascript/dashboard/routes/dashboard/settings/automation/AddAutomationRule.vue
index 814e90c25..2e10280e5 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/automation/AddAutomationRule.vue
+++ b/app/javascript/dashboard/routes/dashboard/settings/automation/AddAutomationRule.vue
@@ -101,6 +101,7 @@
getActionDropdownValues(automation.actions[i].action_name)
"
:v="$v.automation.actions.$each[i]"
+ @resetAction="resetAction(i)"
@removeAction="removeAction(i)"
/>
@@ -187,7 +188,13 @@ export default {
required,
$each: {
action_params: {
- required,
+ required: requiredIf(prop => {
+ return !(
+ prop.action_name === 'mute_conversation' ||
+ prop.action_name === 'snooze_convresation' ||
+ prop.action_name === 'resolve_convresation'
+ );
+ }),
},
},
},
@@ -351,7 +358,6 @@ export default {
getActionDropdownValues(type) {
switch (type) {
case 'assign_team':
- case 'send_email_to_team':
return this.$store.getters['teams/getTeams'];
case 'add_label':
return this.$store.getters['labels/getLabels'].map(i => {
@@ -424,6 +430,9 @@ export default {
).filterOperators[0].value;
this.automation.conditions[index].values = '';
},
+ resetAction(index) {
+ this.automation.actions[index].action_params = [];
+ },
showUserInput(operatorType) {
if (operatorType === 'is_present' || operatorType === 'is_not_present')
return false;
diff --git a/app/javascript/dashboard/routes/dashboard/settings/automation/EditAutomationRule.vue b/app/javascript/dashboard/routes/dashboard/settings/automation/EditAutomationRule.vue
index d55ce419b..6add27ba5 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/automation/EditAutomationRule.vue
+++ b/app/javascript/dashboard/routes/dashboard/settings/automation/EditAutomationRule.vue
@@ -351,7 +351,6 @@ export default {
getActionDropdownValues(type) {
switch (type) {
case 'assign_team':
- case 'send_email_to_team':
return this.$store.getters['teams/getTeams'];
case 'add_label':
return this.$store.getters['labels/getLabels'].map(i => {
diff --git a/app/javascript/dashboard/routes/dashboard/settings/automation/constants.js b/app/javascript/dashboard/routes/dashboard/settings/automation/constants.js
index 90e3a7395..dd11700bd 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/automation/constants.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/automation/constants.js
@@ -79,8 +79,33 @@ export const AUTOMATIONS = {
// {
// key: 'send_email_to_team',
// name: 'Send an email to team',
- // attributeI18nKey: 'SEND_EMAIL_TO_TEAM',
+ // attributeI18nKey: 'SEND_MESSAGE',
// },
+ {
+ key: 'send_email_transcript',
+ name: 'Send an email transcript',
+ attributeI18nKey: 'SEND_EMAIL_TRANSCRIPT',
+ },
+ {
+ key: 'mute_conversation',
+ name: 'Mute conversation',
+ attributeI18nKey: 'MUTE_CONVERSATION',
+ },
+ {
+ key: 'snooze_convresation',
+ name: 'Snooze conversation',
+ attributeI18nKey: 'MUTE_CONVERSATION',
+ },
+ {
+ key: 'resolve_convresation',
+ name: 'Resolve conversation',
+ attributeI18nKey: 'RESOLVE_CONVERSATION',
+ },
+ {
+ key: 'send_webhook_event',
+ name: 'Send Webhook Event',
+ attributeI18nKey: 'SEND_WEBHOOK_EVENT',
+ },
],
},
conversation_created: {
@@ -120,15 +145,40 @@ export const AUTOMATIONS = {
name: 'Assign a team',
attributeI18nKey: 'ASSIGN_TEAM',
},
+ {
+ key: 'assign_agent',
+ name: 'Assign an agent',
+ attributeI18nKey: 'ASSIGN_AGENT',
+ },
// {
// key: 'send_email_to_team',
// name: 'Send an email to team',
// attributeI18nKey: 'SEND_MESSAGE',
// },
{
- key: 'assign_agent',
- name: 'Assign an agent',
- attributeI18nKey: 'ASSIGN_AGENT',
+ key: 'send_email_transcript',
+ name: 'Send an email transcript',
+ attributeI18nKey: 'SEND_EMAIL_TRANSCRIPT',
+ },
+ {
+ key: 'mute_conversation',
+ name: 'Mute conversation',
+ attributeI18nKey: 'MUTE_CONVERSATION',
+ },
+ {
+ key: 'snooze_convresation',
+ name: 'Snooze conversation',
+ attributeI18nKey: 'MUTE_CONVERSATION',
+ },
+ {
+ key: 'resolve_convresation',
+ name: 'Resolve conversation',
+ attributeI18nKey: 'RESOLVE_CONVERSATION',
+ },
+ {
+ key: 'send_webhook_event',
+ name: 'Send Webhook Event',
+ attributeI18nKey: 'SEND_WEBHOOK_EVENT',
},
],
},
@@ -183,16 +233,40 @@ export const AUTOMATIONS = {
name: 'Assign a team',
attributeI18nKey: 'ASSIGN_TEAM',
},
- // {
- // key: 'send_email_to_team',
- // name: 'Send an email to team',
- // attributeI18nKey: 'SEND_EMAIL_TO_TEAM',
- // },
{
key: 'assign_agent',
name: 'Assign an agent',
attributeI18nKey: 'ASSIGN_AGENT',
- attributeKey: 'assignee_id',
+ },
+ // {
+ // key: 'send_email_to_team',
+ // name: 'Send an email to team',
+ // attributeI18nKey: 'SEND_MESSAGE',
+ // },
+ {
+ key: 'send_email_transcript',
+ name: 'Send an email transcript',
+ attributeI18nKey: 'SEND_EMAIL_TRANSCRIPT',
+ },
+ {
+ key: 'mute_conversation',
+ name: 'Mute conversation',
+ attributeI18nKey: 'MUTE_CONVERSATION',
+ },
+ {
+ key: 'snooze_convresation',
+ name: 'Snooze conversation',
+ attributeI18nKey: 'MUTE_CONVERSATION',
+ },
+ {
+ key: 'resolve_convresation',
+ name: 'Resolve conversation',
+ attributeI18nKey: 'RESOLVE_CONVERSATION',
+ },
+ {
+ key: 'send_webhook_event',
+ name: 'Send Webhook Event',
+ attributeI18nKey: 'SEND_WEBHOOK_EVENT',
},
],
},
@@ -217,13 +291,41 @@ export const AUTOMATION_ACTION_TYPES = [
{
key: 'assign_team',
label: 'Assign a team',
+ inputType: 'multi_select',
},
{
key: 'add_label',
label: 'Add a label',
+ inputType: 'multi_select',
},
// {
// key: 'send_email_to_team',
// label: 'Send an email to team',
+ // inputType: 'multi_select',
// },
+ {
+ key: 'send_email_transcript',
+ label: 'Send an email transcript',
+ inputType: 'email',
+ },
+ {
+ key: 'mute_conversation',
+ label: 'Mute conversation',
+ inputType: null,
+ },
+ {
+ key: 'snooze_convresation',
+ label: 'Snooze conversation',
+ inputType: null,
+ },
+ {
+ key: 'resolve_convresation',
+ label: 'Resolve conversation',
+ inputType: null,
+ },
+ {
+ key: 'send_webhook_event',
+ label: 'Send Webhook Event',
+ inputType: 'url',
+ },
];
diff --git a/app/models/concerns/activity_message_handler.rb b/app/models/concerns/activity_message_handler.rb
index 6ccdfa7a9..4a2b4f22e 100644
--- a/app/models/concerns/activity_message_handler.rb
+++ b/app/models/concerns/activity_message_handler.rb
@@ -10,6 +10,8 @@ module ActivityMessageHandler
end
def status_change_activity(user_name)
+ return send_automation_activity if Current.executed_by.present?
+
create_status_change_message(user_name)
end
@@ -29,6 +31,11 @@ module ActivityMessageHandler
::Conversations::ActivityMessageJob.perform_later(self, activity_message_params(content)) if content
end
+ def send_automation_activity
+ content = I18n.t("conversations.activity.status.#{status}", user_name: 'Automation System')
+ ::Conversations::ActivityMessageJob.perform_later(self, activity_message_params(content)) if content
+ end
+
def create_label_added(user_name, labels = [])
return unless labels.size.positive?
diff --git a/app/services/automation_rules/action_service.rb b/app/services/automation_rules/action_service.rb
index 158ac59c5..3848e30f5 100644
--- a/app/services/automation_rules/action_service.rb
+++ b/app/services/automation_rules/action_service.rb
@@ -21,21 +21,27 @@ class AutomationRules::ActionService
private
- def send_email_transcript(email)
- ConversationReplyMailer.with(account: conversation.account).conversation_transcript(@conversation, email)&.deliver_later
+ def send_email_transcript(emails)
+ emails.each do |email|
+ ConversationReplyMailer.with(account: @conversation.account).conversation_transcript(@conversation, email)&.deliver_later
+ end
end
def mute_conversation(_params)
@conversation.mute!
end
+ def snooze_conversation(_params)
+ @conversation.ensure_snooze_until_reset
+ end
+
def change_status(status)
@conversation.update!(status: status[0])
end
- def send_webhook_events(webhook_url)
+ def send_webhook_event(webhook_url)
payload = @conversation.webhook_data.merge(event: "automation_event: #{@rule.event_name}")
- WebhookJob.perform_later(webhook_url, payload)
+ WebhookJob.perform_later(webhook_url[0], payload)
end
def send_message(message)
diff --git a/app/services/filter_service.rb b/app/services/filter_service.rb
index bf2d7d6a0..e0167b5af 100644
--- a/app/services/filter_service.rb
+++ b/app/services/filter_service.rb
@@ -28,7 +28,7 @@ class FilterService
@filter_values["value_#{current_index}"] = filter_values(query_hash)
equals_to_filter_string(query_hash[:filter_operator], current_index)
when 'contains', 'does_not_contain'
- @filter_values["value_#{current_index}"] = "%#{filter_values(query_hash)}%"
+ @filter_values["value_#{current_index}"] = "%#{string_filter_values(query_hash)}%"
like_filter_string(query_hash[:filter_operator], current_index)
when 'is_present'
@filter_values["value_#{current_index}"] = 'IS NOT NULL'
@@ -57,6 +57,12 @@ class FilterService
end
end
+ def string_filter_values(query_hash)
+ return query_hash['values'][0] if query_hash['values'].is_a?(Array)
+
+ query_hash['values']
+ end
+
def lt_gt_filter_values(query_hash)
attribute_key = query_hash[:attribute_key]
attribute_type = custom_attribute(attribute_key).try(:attribute_display_type)
diff --git a/spec/listeners/automation_rule_listener_spec.rb b/spec/listeners/automation_rule_listener_spec.rb
index ff289a6dd..66a9a68ac 100644
--- a/spec/listeners/automation_rule_listener_spec.rb
+++ b/spec/listeners/automation_rule_listener_spec.rb
@@ -31,7 +31,7 @@ describe AutomationRuleListener do
},
{ 'action_name' => 'assign_team', 'action_params' => [team.id] },
{ 'action_name' => 'add_label', 'action_params' => %w[support priority_customer] },
- { 'action_name' => 'send_webhook_events', 'action_params' => 'https://www.example.com' },
+ { 'action_name' => 'send_webhook_event', 'action_params' => ['https://www.example.com'] },
{ 'action_name' => 'assign_best_agent', 'action_params' => [user_1.id] },
{ 'action_name' => 'send_email_transcript', 'action_params' => 'new_agent@example.com' },
{ 'action_name' => 'mute_conversation', 'action_params' => nil },