+
+
+ {{ t('GENERAL_SETTINGS.FORM.AUTO_RESOLVE.TITLE') }}
+
+
+
-
-
-
-
-
-
+
+ {{ t('GENERAL_SETTINGS.FORM.AUTO_RESOLVE.NOTE') }}
+
+
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/attributes/CustomAttribute.vue b/app/javascript/dashboard/routes/dashboard/settings/attributes/CustomAttribute.vue
deleted file mode 100644
index db9c2dacf..000000000
--- a/app/javascript/dashboard/routes/dashboard/settings/attributes/CustomAttribute.vue
+++ /dev/null
@@ -1,176 +0,0 @@
-
-
-
-
-
-
- |
- {{ tableHeader }}
- |
-
-
-
- |
- {{ attribute.attribute_display_name }}
- |
-
- {{ attribute.attribute_description }}
- |
-
- {{
- $t(
- `ATTRIBUTES_MGMT.ATTRIBUTE_TYPES.${attribute.attribute_display_type?.toUpperCase()}`
- )
- }}
- |
-
- {{ attribute.attribute_key }}
- |
-
-
-
-
-
- |
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/javascript/dashboard/routes/dashboard/settings/conversationWorkflow/conversationWorkflow.routes.js b/app/javascript/dashboard/routes/dashboard/settings/conversationWorkflow/conversationWorkflow.routes.js
new file mode 100644
index 000000000..494e6a7f1
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/conversationWorkflow/conversationWorkflow.routes.js
@@ -0,0 +1,22 @@
+import { frontendURL } from '../../../../helper/URLHelper';
+import SettingsWrapper from '../SettingsWrapper.vue';
+import ConversationWorkflowIndex from './index.vue';
+
+export default {
+ routes: [
+ {
+ path: frontendURL('accounts/:accountId/settings/conversation-workflow'),
+ component: SettingsWrapper,
+ children: [
+ {
+ path: '',
+ name: 'conversation_workflow_index',
+ component: ConversationWorkflowIndex,
+ meta: {
+ permissions: ['administrator'],
+ },
+ },
+ ],
+ },
+ ],
+};
diff --git a/app/javascript/dashboard/routes/dashboard/settings/conversationWorkflow/index.vue b/app/javascript/dashboard/routes/dashboard/settings/conversationWorkflow/index.vue
new file mode 100644
index 000000000..30df5bbd6
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/conversationWorkflow/index.vue
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/settings.routes.js b/app/javascript/dashboard/routes/dashboard/settings/settings.routes.js
index 41c3498e1..e277a0ef4 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/settings.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/settings/settings.routes.js
@@ -24,6 +24,7 @@ import teams from './teams/teams.routes';
import customRoles from './customRoles/customRole.routes';
import profile from './profile/profile.routes';
import security from './security/security.routes';
+import conversationWorkflow from './conversationWorkflow/conversationWorkflow.routes';
import captain from './captain/captain.routes';
export default {
@@ -64,6 +65,7 @@ export default {
...customRoles.routes,
...profile.routes,
...security.routes,
+ ...conversationWorkflow.routes,
...captain.routes,
],
};
diff --git a/app/javascript/dashboard/store/modules/conversations/actions.js b/app/javascript/dashboard/store/modules/conversations/actions.js
index dcaf5f9c9..559eaaad9 100644
--- a/app/javascript/dashboard/store/modules/conversations/actions.js
+++ b/app/javascript/dashboard/store/modules/conversations/actions.js
@@ -240,9 +240,21 @@ const actions = {
toggleStatus: async (
{ commit },
- { conversationId, status, snoozedUntil = null }
+ { conversationId, status, snoozedUntil = null, customAttributes = null }
) => {
try {
+ // Update custom attributes first if provided
+ if (customAttributes) {
+ await ConversationApi.updateCustomAttributes({
+ conversationId,
+ customAttributes,
+ });
+ commit(types.UPDATE_CONVERSATION_CUSTOM_ATTRIBUTES, {
+ conversationId,
+ customAttributes,
+ });
+ }
+
const {
data: {
payload: {
@@ -459,7 +471,10 @@ const actions = {
customAttributes,
});
const { custom_attributes } = response.data;
- commit(types.UPDATE_CONVERSATION_CUSTOM_ATTRIBUTES, custom_attributes);
+ commit(types.UPDATE_CONVERSATION_CUSTOM_ATTRIBUTES, {
+ conversationId,
+ customAttributes: custom_attributes,
+ });
} catch (error) {
// Handle error
}
diff --git a/app/javascript/dashboard/store/modules/conversations/index.js b/app/javascript/dashboard/store/modules/conversations/index.js
index 72b7bc566..8d3ef9a9a 100644
--- a/app/javascript/dashboard/store/modules/conversations/index.js
+++ b/app/javascript/dashboard/store/modules/conversations/index.js
@@ -121,9 +121,19 @@ export const mutations = {
chat.priority = priority;
},
- [types.UPDATE_CONVERSATION_CUSTOM_ATTRIBUTES](_state, custom_attributes) {
- const [chat] = getSelectedChatConversation(_state);
- chat.custom_attributes = custom_attributes;
+ [types.UPDATE_CONVERSATION_CUSTOM_ATTRIBUTES](
+ _state,
+ { conversationId, customAttributes }
+ ) {
+ const conversation = _state.allConversations.find(
+ c => c.id === conversationId
+ );
+ if (conversation) {
+ conversation.custom_attributes = {
+ ...conversation.custom_attributes,
+ ...customAttributes,
+ };
+ }
},
[types.CHANGE_CONVERSATION_STATUS](
diff --git a/app/javascript/dashboard/store/modules/specs/conversations/actions.spec.js b/app/javascript/dashboard/store/modules/specs/conversations/actions.spec.js
index 161ae914b..502c072f6 100644
--- a/app/javascript/dashboard/store/modules/specs/conversations/actions.spec.js
+++ b/app/javascript/dashboard/store/modules/specs/conversations/actions.spec.js
@@ -548,7 +548,13 @@ describe('#deleteMessage', () => {
}
);
expect(commit.mock.calls).toEqual([
- [types.UPDATE_CONVERSATION_CUSTOM_ATTRIBUTES, { order_d: '1001' }],
+ [
+ types.UPDATE_CONVERSATION_CUSTOM_ATTRIBUTES,
+ {
+ conversationId: 1,
+ customAttributes: { order_d: '1001' },
+ },
+ ],
]);
});
});
diff --git a/app/javascript/dashboard/store/modules/specs/conversations/mutations.spec.js b/app/javascript/dashboard/store/modules/specs/conversations/mutations.spec.js
index 48e676215..e9e78a25c 100644
--- a/app/javascript/dashboard/store/modules/specs/conversations/mutations.spec.js
+++ b/app/javascript/dashboard/store/modules/specs/conversations/mutations.spec.js
@@ -239,14 +239,14 @@ describe('#mutations', () => {
describe('#UPDATE_CONVERSATION_CUSTOM_ATTRIBUTES', () => {
it('update conversation custom attributes', () => {
const custom_attributes = { order_id: 1001 };
- const state = { allConversations: [{ id: 1 }], selectedChatId: 1 };
+ const state = { allConversations: [{ id: 1, custom_attributes: {} }] };
mutations[types.UPDATE_CONVERSATION_CUSTOM_ATTRIBUTES](state, {
conversationId: 1,
- custom_attributes,
+ customAttributes: custom_attributes,
});
- expect(
- state.allConversations[0].custom_attributes.custom_attributes
- ).toEqual(custom_attributes);
+ expect(state.allConversations[0].custom_attributes).toEqual(
+ custom_attributes
+ );
});
});
});
diff --git a/app/models/account.rb b/app/models/account.rb
index dad5bc18d..df79ee6c1 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -85,7 +85,7 @@ class Account < ApplicationRecord
store_accessor :settings, :auto_resolve_after, :auto_resolve_message, :auto_resolve_ignore_waiting
- store_accessor :settings, :audio_transcriptions, :auto_resolve_label, :conversation_required_attributes
+ store_accessor :settings, :audio_transcriptions, :auto_resolve_label
store_accessor :settings, :captain_models, :captain_features
has_many :account_users, dependent: :destroy_async
diff --git a/app/models/custom_attribute_definition.rb b/app/models/custom_attribute_definition.rb
index 4154da3b8..70956c108 100644
--- a/app/models/custom_attribute_definition.rb
+++ b/app/models/custom_attribute_definition.rb
@@ -45,7 +45,6 @@ class CustomAttributeDefinition < ApplicationRecord
belongs_to :account
after_update :update_widget_pre_chat_custom_fields
after_destroy :sync_widget_pre_chat_custom_fields
- after_destroy :cleanup_conversation_required_attributes
private
@@ -57,13 +56,6 @@ class CustomAttributeDefinition < ApplicationRecord
::Inboxes::UpdateWidgetPreChatCustomFieldsJob.perform_later(account, self)
end
- def cleanup_conversation_required_attributes
- return unless conversation_attribute? && account.conversation_required_attributes&.include?(attribute_key)
-
- account.conversation_required_attributes = account.conversation_required_attributes - [attribute_key]
- account.save!
- end
-
def attribute_must_not_conflict
model_keys = attribute_model.to_sym == :conversation_attribute ? :conversation : :contact
return unless attribute_key.in?(STANDARD_ATTRIBUTES[model_keys])
@@ -71,3 +63,5 @@ class CustomAttributeDefinition < ApplicationRecord
errors.add(:attribute_key, I18n.t('errors.custom_attribute_definition.key_conflict'))
end
end
+
+CustomAttributeDefinition.include_mod_with('Concerns::CustomAttributeDefinition')
diff --git a/config/features.yml b/config/features.yml
index 703d3cb8c..e03690d74 100644
--- a/config/features.yml
+++ b/config/features.yml
@@ -237,3 +237,7 @@
- name: captain_tasks
display_name: Captain Tasks
enabled: true
+- name: conversation_required_attributes
+ display_name: Required Conversation Attributes
+ enabled: false
+ premium: true
diff --git a/enterprise/app/controllers/enterprise/api/v1/accounts_settings.rb b/enterprise/app/controllers/enterprise/api/v1/accounts_settings.rb
new file mode 100644
index 000000000..bdcbfc1d3
--- /dev/null
+++ b/enterprise/app/controllers/enterprise/api/v1/accounts_settings.rb
@@ -0,0 +1,7 @@
+module Enterprise::Api::V1::AccountsSettings
+ private
+
+ def permitted_settings_attributes
+ super + [{ conversation_required_attributes: [] }]
+ end
+end
diff --git a/enterprise/app/models/enterprise/concerns/account.rb b/enterprise/app/models/enterprise/concerns/account.rb
index cae32e86c..01693ac79 100644
--- a/enterprise/app/models/enterprise/concerns/account.rb
+++ b/enterprise/app/models/enterprise/concerns/account.rb
@@ -2,6 +2,8 @@ module Enterprise::Concerns::Account
extend ActiveSupport::Concern
included do
+ store_accessor :settings, :conversation_required_attributes
+
has_many :sla_policies, dependent: :destroy_async
has_many :applied_slas, dependent: :destroy_async
has_many :custom_roles, dependent: :destroy_async
diff --git a/enterprise/app/models/enterprise/concerns/custom_attribute_definition.rb b/enterprise/app/models/enterprise/concerns/custom_attribute_definition.rb
new file mode 100644
index 000000000..ad359f8a0
--- /dev/null
+++ b/enterprise/app/models/enterprise/concerns/custom_attribute_definition.rb
@@ -0,0 +1,16 @@
+module Enterprise::Concerns::CustomAttributeDefinition
+ extend ActiveSupport::Concern
+
+ included do
+ after_destroy :cleanup_conversation_required_attributes
+ end
+
+ private
+
+ def cleanup_conversation_required_attributes
+ return unless conversation_attribute? && account.conversation_required_attributes&.include?(attribute_key)
+
+ account.conversation_required_attributes = account.conversation_required_attributes - [attribute_key]
+ account.save!
+ end
+end
diff --git a/enterprise/app/services/enterprise/billing/handle_stripe_event_service.rb b/enterprise/app/services/enterprise/billing/handle_stripe_event_service.rb
index 10887a1d7..a5f03cddf 100644
--- a/enterprise/app/services/enterprise/billing/handle_stripe_event_service.rb
+++ b/enterprise/app/services/enterprise/billing/handle_stripe_event_service.rb
@@ -22,7 +22,7 @@ class Enterprise::Billing::HandleStripeEventService
].freeze
# Additional features available starting with the Business plan
- BUSINESS_PLAN_FEATURES = %w[sla custom_roles csat_review_notes].freeze
+ BUSINESS_PLAN_FEATURES = %w[sla custom_roles csat_review_notes conversation_required_attributes].freeze
# Additional features available only in the Enterprise plan
ENTERPRISE_PLAN_FEATURES = %w[audit_logs disable_branding saml].freeze
diff --git a/enterprise/config/premium_features.yml b/enterprise/config/premium_features.yml
index 9465a6e11..64275503d 100644
--- a/enterprise/config/premium_features.yml
+++ b/enterprise/config/premium_features.yml
@@ -6,3 +6,4 @@
- custom_roles
- captain_integration
- csat_review_notes
+- conversation_required_attributes
diff --git a/spec/models/custom_attribute_definition_spec.rb b/spec/enterprise/models/custom_attribute_definition_spec.rb
similarity index 100%
rename from spec/models/custom_attribute_definition_spec.rb
rename to spec/enterprise/models/custom_attribute_definition_spec.rb