diff --git a/app/assets/stylesheets/administrate/components/_search.scss b/app/assets/stylesheets/administrate/components/_search.scss index 9b61a696a..f3a259618 100644 --- a/app/assets/stylesheets/administrate/components/_search.scss +++ b/app/assets/stylesheets/administrate/components/_search.scss @@ -1,7 +1,7 @@ .search { margin-left: auto; margin-right: 2rem; - max-width: 24rem; + max-width: 44rem; position: relative; width: 100%; } diff --git a/app/controllers/api/v1/accounts/conversations_controller.rb b/app/controllers/api/v1/accounts/conversations_controller.rb index 849c36942..fcda432a5 100644 --- a/app/controllers/api/v1/accounts/conversations_controller.rb +++ b/app/controllers/api/v1/accounts/conversations_controller.rb @@ -27,7 +27,12 @@ class Api::V1::Accounts::ConversationsController < Api::BaseController end def toggle_status - @status = @conversation.toggle_status + if params[:status] + @conversation.status = params[:status] + @status = @conversation.save + else + @status = @conversation.toggle_status + end end def toggle_typing_status diff --git a/app/controllers/super_admin/account_users_controller.rb b/app/controllers/super_admin/account_users_controller.rb index bf86a5af6..b210dea19 100644 --- a/app/controllers/super_admin/account_users_controller.rb +++ b/app/controllers/super_admin/account_users_controller.rb @@ -6,18 +6,8 @@ class SuperAdmin::AccountUsersController < SuperAdmin::ApplicationController resource = resource_class.new(resource_params) authorize_resource(resource) - redirect_resource = params[:redirect_to] == 'user' ? resource.user : resource.account - if resource.save - redirect_to( - [namespace, redirect_resource], - notice: translate_with_resource('create.success') - ) - else - redirect_to( - [namespace, redirect_resource], - notice: resource.errors.full_messages.first - ) - end + notice = resource.save ? translate_with_resource('create.success') : resource.errors.full_messages.first + redirect_back(fallback_location: [namespace, resource.account], notice: notice) end def destroy @@ -26,7 +16,7 @@ class SuperAdmin::AccountUsersController < SuperAdmin::ApplicationController else flash[:error] = requested_resource.errors.full_messages.join('
') end - redirect_to([namespace, requested_resource.account]) + redirect_back(fallback_location: [namespace, requested_resource.account]) end # Override this method to specify custom lookup behavior. diff --git a/app/controllers/super_admin/agent_bots_controller.rb b/app/controllers/super_admin/agent_bots_controller.rb new file mode 100644 index 000000000..8e094e752 --- /dev/null +++ b/app/controllers/super_admin/agent_bots_controller.rb @@ -0,0 +1,44 @@ +class SuperAdmin::AgentBotsController < SuperAdmin::ApplicationController + # Overwrite any of the RESTful controller actions to implement custom behavior + # For example, you may want to send an email after a foo is updated. + # + # def update + # super + # send_foo_updated_email(requested_resource) + # end + + # Override this method to specify custom lookup behavior. + # This will be used to set the resource for the `show`, `edit`, and `update` + # actions. + # + # def find_resource(param) + # Foo.find_by!(slug: param) + # end + + # The result of this lookup will be available as `requested_resource` + + # Override this if you have certain roles that require a subset + # this will be used to set the records shown on the `index` action. + # + # def scoped_resource + # if current_user.super_admin? + # resource_class + # else + # resource_class.with_less_stuff + # end + # end + + # Override `resource_params` if you want to transform the submitted + # data before it's persisted. For example, the following would turn all + # empty values into nil values. It uses other APIs such as `resource_class` + # and `dashboard`: + # + # def resource_params + # params.require(resource_class.model_name.param_key). + # permit(dashboard.permitted_attributes). + # transform_values { |value| value == "" ? nil : value } + # end + + # See https://administrate-prototype.herokuapp.com/customizing_controller_actions + # for more information +end diff --git a/app/dashboards/access_token_dashboard.rb b/app/dashboards/access_token_dashboard.rb index bdc50a7db..6864b99d4 100644 --- a/app/dashboards/access_token_dashboard.rb +++ b/app/dashboards/access_token_dashboard.rb @@ -55,7 +55,11 @@ class AccessTokenDashboard < Administrate::BaseDashboard # COLLECTION_FILTERS = { # open: ->(resources) { resources.where(open: true) } # }.freeze - COLLECTION_FILTERS = {}.freeze + COLLECTION_FILTERS = { + user: ->(resources) { resources.where(owner_type: 'User') }, + super_admin: ->(resources) { resources.where(owner_type: 'SuperAdmin') }, + agent_bot: ->(resources) { resources.where(owner_type: 'AgentBot') } + }.freeze # Overwrite this method to customize how access tokens are displayed # across all pages of the admin dashboard. diff --git a/app/dashboards/agent_bot_dashboard.rb b/app/dashboards/agent_bot_dashboard.rb new file mode 100644 index 000000000..ca6ca7ad1 --- /dev/null +++ b/app/dashboards/agent_bot_dashboard.rb @@ -0,0 +1,73 @@ +require 'administrate/base_dashboard' + +class AgentBotDashboard < Administrate::BaseDashboard + # ATTRIBUTE_TYPES + # a hash that describes the type of each of the model's fields. + # + # Each different type represents an Administrate::Field object, + # which determines how the attribute is displayed + # on pages throughout the dashboard. + ATTRIBUTE_TYPES = { + access_token: Field::HasOne, + avatar_url: AvatarField, + id: Field::Number, + name: Field::String, + description: Field::String, + outgoing_url: Field::String, + created_at: Field::DateTime, + updated_at: Field::DateTime, + hide_input_for_bot_conversations: Field::Boolean + }.freeze + + # COLLECTION_ATTRIBUTES + # an array of attributes that will be displayed on the model's index page. + # + # By default, it's limited to four items to reduce clutter on index pages. + # Feel free to add, remove, or rearrange items. + COLLECTION_ATTRIBUTES = %i[ + id + avatar_url + name + outgoing_url + ].freeze + + # SHOW_PAGE_ATTRIBUTES + # an array of attributes that will be displayed on the model's show page. + SHOW_PAGE_ATTRIBUTES = %i[ + id + avatar_url + name + description + outgoing_url + hide_input_for_bot_conversations + ].freeze + + # FORM_ATTRIBUTES + # an array of attributes that will be displayed + # on the model's form (`new` and `edit`) pages. + FORM_ATTRIBUTES = %i[ + name + description + outgoing_url + hide_input_for_bot_conversations + ].freeze + + # COLLECTION_FILTERS + # a hash that defines filters that can be used while searching via the search + # field of the dashboard. + # + # For example to add an option to search for open resources by typing "open:" + # in the search field: + # + # COLLECTION_FILTERS = { + # open: ->(resources) { resources.where(open: true) } + # }.freeze + COLLECTION_FILTERS = {}.freeze + + # Overwrite this method to customize how agent bots are displayed + # across all pages of the admin dashboard. + # + # def display_resource(agent_bot) + # "AgentBot ##{agent_bot.id}" + # end +end diff --git a/app/models/conversation.rb b/app/models/conversation.rb index 07a9e9fc2..db25c27da 100644 --- a/app/models/conversation.rb +++ b/app/models/conversation.rb @@ -50,13 +50,11 @@ class Conversation < ApplicationRecord has_many :messages, dependent: :destroy, autosave: true before_create :set_display_id, unless: :display_id? - before_create :set_bot_conversation - + after_create :notify_conversation_creation + after_save :run_round_robin after_update :notify_status_change, :create_activity - after_create :notify_conversation_creation, :run_round_robin - acts_as_taggable_on :labels def update_assignee(agent = nil) @@ -173,10 +171,24 @@ class Conversation < ApplicationRecord Rails.configuration.dispatcher.dispatch(event_name, Time.zone.now, conversation: self) end + def should_round_robin? + return false unless inbox.enable_auto_assignment? + + # run only if assignee is blank or doesn't have access to inbox + assignee.blank? || inbox.members.exclude?(assignee) + end + + def conversation_status_changed_to_open? + return false unless open? + # saved_change_to_status? method only works in case of update + return true if previous_changes.key?(:id) || saved_change_to_status? + end + def run_round_robin - return unless inbox.enable_auto_assignment - return if assignee - return if bot? + # Round robin kicks in on conversation create & update + # run it only when conversation status changes to open + return unless conversation_status_changed_to_open? + return unless should_round_robin? inbox.next_available_agent.then { |new_assignee| update_assignee(new_assignee) } end diff --git a/app/services/message_templates/template/email_collect.rb b/app/services/message_templates/template/email_collect.rb index 07004081e..e9e830d3b 100644 --- a/app/services/message_templates/template/email_collect.rb +++ b/app/services/message_templates/template/email_collect.rb @@ -18,8 +18,11 @@ class MessageTemplates::Template::EmailCollect delegate :inbox, to: :message def typical_reply_message_params - content = I18n.t('conversations.templates.typical_reply_message_body', - account_name: account.name) + content = @conversation.inbox&.channel&.agent_away_message + if content.blank? + content = I18n.t('conversations.templates.typical_reply_message_body', + account_name: account.name) + end { account_id: @conversation.account_id, diff --git a/app/views/api/v1/models/_user.json.jbuilder b/app/views/api/v1/models/_user.json.jbuilder index 4fdacf14a..5638fc233 100644 --- a/app/views/api/v1/models/_user.json.jbuilder +++ b/app/views/api/v1/models/_user.json.jbuilder @@ -4,10 +4,10 @@ json.uid resource.uid json.name resource.name json.nickname resource.nickname json.email resource.email -json.account_id resource.active_account_user.account_id +json.account_id resource.active_account_user&.account_id json.pubsub_token resource.pubsub_token -json.role resource.active_account_user.role -json.inviter_id resource.active_account_user.inviter_id +json.role resource.active_account_user&.role +json.inviter_id resource.active_account_user&.inviter_id json.confirmed resource.confirmed? json.avatar_url resource.avatar_url json.access_token resource.access_token.token diff --git a/app/views/super_admin/accounts/show.html.erb b/app/views/super_admin/accounts/show.html.erb index ca08929a6..93cd37945 100644 --- a/app/views/super_admin/accounts/show.html.erb +++ b/app/views/super_admin/accounts/show.html.erb @@ -72,7 +72,6 @@ as well as a link to its edit page. <% account_user_page.attributes.each do |attribute| -%> <% if attribute.name == "account" %> <%= f.hidden_field('account_id', value: page.resource.id) %> - <%= f.hidden_field('redirect_to', value: 'user') %> <% else %>
<%= render_field attribute, f: f %> diff --git a/app/views/super_admin/application/_navigation.html.erb b/app/views/super_admin/application/_navigation.html.erb index 005bd8cb8..6ecc5bd90 100644 --- a/app/views/super_admin/application/_navigation.html.erb +++ b/app/views/super_admin/application/_navigation.html.erb @@ -30,7 +30,7 @@ as defined by the routes in the `admin/` namespace <%= link_to "Dashboard", super_admin_root_url %> <% Administrate::Namespace.new(namespace).resources.each do |resource| %> - <% next if ["account_users", "dashboard", "devise/sessions"].include? resource.resource %> + <% next if ["account_users", "agent_bots","dashboard", "devise/sessions"].include? resource.resource %>