diff --git a/app/javascript/dashboard/helper/validations.js b/app/javascript/dashboard/helper/validations.js index 58f3faa1a..edebc4656 100644 --- a/app/javascript/dashboard/helper/validations.js +++ b/app/javascript/dashboard/helper/validations.js @@ -126,6 +126,7 @@ const validateSingleAction = action => { 'snooze_conversation', 'resolve_conversation', 'remove_assigned_team', + 'open_conversation', ]; if ( diff --git a/app/javascript/dashboard/i18n/locale/en/automation.json b/app/javascript/dashboard/i18n/locale/en/automation.json index 86ec0b58b..c5dd4a514 100644 --- a/app/javascript/dashboard/i18n/locale/en/automation.json +++ b/app/javascript/dashboard/i18n/locale/en/automation.json @@ -147,7 +147,8 @@ "SEND_ATTACHMENT": "Send Attachment", "SEND_MESSAGE": "Send a Message", "CHANGE_PRIORITY": "Change Priority", - "ADD_SLA": "Add SLA" + "ADD_SLA": "Add SLA", + "OPEN_CONVERSATION": "Open conversation" }, "ATTRIBUTES": { "MESSAGE_TYPE": "Message Type", diff --git a/app/javascript/dashboard/routes/dashboard/settings/automation/constants.js b/app/javascript/dashboard/routes/dashboard/settings/automation/constants.js index 18468e3ad..1b0f0599f 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/automation/constants.js +++ b/app/javascript/dashboard/routes/dashboard/settings/automation/constants.js @@ -32,6 +32,30 @@ export const AUTOMATIONS = { inputType: 'multi_select', filterOperators: OPERATOR_TYPES_1, }, + { + key: 'status', + name: 'STATUS', + inputType: 'multi_select', + filterOperators: OPERATOR_TYPES_1, + }, + { + key: 'assignee_id', + name: 'ASSIGNEE_NAME', + inputType: 'search_select', + filterOperators: OPERATOR_TYPES_3, + }, + { + key: 'team_id', + name: 'TEAM_NAME', + inputType: 'search_select', + filterOperators: OPERATOR_TYPES_3, + }, + { + key: 'priority', + name: 'PRIORITY', + inputType: 'multi_select', + filterOperators: OPERATOR_TYPES_1, + }, { key: 'conversation_language', name: 'CONVERSATION_LANGUAGE', @@ -82,7 +106,10 @@ export const AUTOMATIONS = { key: 'snooze_conversation', name: 'SNOOZE_CONVERSATION', }, - + { + key: 'open_conversation', + name: 'OPEN_CONVERSATION', + }, { key: 'resolve_conversation', name: 'RESOLVE_CONVERSATION', @@ -508,6 +535,11 @@ export const AUTOMATION_ACTION_TYPES = [ label: 'RESOLVE_CONVERSATION', inputType: null, }, + { + key: 'open_conversation', + label: 'OPEN_CONVERSATION', + inputType: null, + }, { key: 'send_webhook_event', label: 'SEND_WEBHOOK_EVENT', diff --git a/app/models/automation_rule.rb b/app/models/automation_rule.rb index 258c5c0a3..c8f5a180d 100644 --- a/app/models/automation_rule.rb +++ b/app/models/automation_rule.rb @@ -41,7 +41,7 @@ class AutomationRule < ApplicationRecord def actions_attributes %w[send_message add_label remove_label send_email_to_team assign_team assign_agent send_webhook_event mute_conversation - send_attachment change_status resolve_conversation snooze_conversation change_priority send_email_transcript].freeze + send_attachment change_status resolve_conversation open_conversation snooze_conversation change_priority send_email_transcript].freeze end def file_base_data diff --git a/app/services/action_service.rb b/app/services/action_service.rb index 4f33a302b..a50b11193 100644 --- a/app/services/action_service.rb +++ b/app/services/action_service.rb @@ -18,6 +18,10 @@ class ActionService @conversation.resolved! end + def open_conversation(_params) + @conversation.open! + end + def change_status(status) @conversation.update!(status: status[0]) end diff --git a/spec/listeners/automation_rule_listener_spec.rb b/spec/listeners/automation_rule_listener_spec.rb index e0103b19a..c08b6e402 100644 --- a/spec/listeners/automation_rule_listener_spec.rb +++ b/spec/listeners/automation_rule_listener_spec.rb @@ -171,6 +171,16 @@ describe AutomationRuleListener do listener.message_created(event) expect(AutomationRules::ActionService).not_to have_received(:new).with(automation_rule, account, conversation) end + + it 'passes conversation attributes to conditions filter service' do + conversation.update!(status: :open, priority: :high) + listener.message_created(event) + expect(AutomationRules::ConditionsFilterService).to have_received(:new).with( + automation_rule, + conversation, + { message: message, changed_attributes: { content: %w[nil Hi] } } + ) + end end end end diff --git a/spec/services/action_service_spec.rb b/spec/services/action_service_spec.rb index c28761844..95b1e6ecf 100644 --- a/spec/services/action_service_spec.rb +++ b/spec/services/action_service_spec.rb @@ -14,6 +14,17 @@ describe ActionService do end end + describe '#open_conversation' do + let(:conversation) { create(:conversation, status: :resolved) } + let(:action_service) { described_class.new(conversation) } + + it 'opens the conversation' do + expect(conversation.status).to eq('resolved') + action_service.open_conversation(nil) + expect(conversation.reload.status).to eq('open') + end + end + describe '#change_priority' do let(:conversation) { create(:conversation) } let(:action_service) { described_class.new(conversation) } diff --git a/spec/services/automation_rules/conditions_filter_service_spec.rb b/spec/services/automation_rules/conditions_filter_service_spec.rb index ec9f52062..7082d31b1 100644 --- a/spec/services/automation_rules/conditions_filter_service_spec.rb +++ b/spec/services/automation_rules/conditions_filter_service_spec.rb @@ -110,6 +110,29 @@ RSpec.describe AutomationRules::ConditionsFilterService do expect(described_class.new(rule, conversation, { message: message, changed_attributes: {} }).perform).to be(false) end end + + context 'when filtering messages based on conversation attributes' do + let(:conversation) { create(:conversation, account: account, status: :open, priority: :high) } + let(:message) do + create(:message, account: account, conversation: conversation, content: 'Test message', + inbox: conversation.inbox, message_type: :incoming) + end + + it 'will return true when conversation status matches' do + rule.update(conditions: [{ 'values': ['open'], 'attribute_key': 'status', 'query_operator': nil, 'filter_operator': 'equal_to' }]) + expect(described_class.new(rule, conversation, { message: message, changed_attributes: {} }).perform).to be(true) + end + + it 'will return false when conversation status does not match' do + rule.update(conditions: [{ 'values': ['resolved'], 'attribute_key': 'status', 'query_operator': nil, 'filter_operator': 'equal_to' }]) + expect(described_class.new(rule, conversation, { message: message, changed_attributes: {} }).perform).to be(false) + end + + it 'will return true when conversation priority matches' do + rule.update(conditions: [{ 'values': ['high'], 'attribute_key': 'priority', 'query_operator': nil, 'filter_operator': 'equal_to' }]) + expect(described_class.new(rule, conversation, { message: message, changed_attributes: {} }).perform).to be(true) + end + end end end end