diff --git a/app/controllers/super_admin/app_configs_controller.rb b/app/controllers/super_admin/app_configs_controller.rb index 3972d5a28..5cf158b98 100644 --- a/app/controllers/super_admin/app_configs_controller.rb +++ b/app/controllers/super_admin/app_configs_controller.rb @@ -41,7 +41,8 @@ class SuperAdmin::AppConfigsController < SuperAdmin::ApplicationController 'slack' => %w[SLACK_CLIENT_ID SLACK_CLIENT_SECRET], 'instagram' => %w[INSTAGRAM_APP_ID INSTAGRAM_APP_SECRET INSTAGRAM_VERIFY_TOKEN INSTAGRAM_API_VERSION ENABLE_INSTAGRAM_CHANNEL_HUMAN_AGENT], 'whatsapp_embedded' => %w[WHATSAPP_APP_ID WHATSAPP_APP_SECRET WHATSAPP_CONFIGURATION_ID WHATSAPP_API_VERSION], - 'notion' => %w[NOTION_CLIENT_ID NOTION_CLIENT_SECRET] + 'notion' => %w[NOTION_CLIENT_ID NOTION_CLIENT_SECRET], + 'google' => %w[GOOGLE_OAUTH_CLIENT_ID GOOGLE_OAUTH_CLIENT_SECRET GOOGLE_OAUTH_REDIRECT_URI] } @allowed_configs = mapping.fetch(@config, %w[ENABLE_ACCOUNT_SIGNUP FIREBASE_PROJECT_ID FIREBASE_CREDENTIALS]) diff --git a/app/controllers/super_admin/application_controller.rb b/app/controllers/super_admin/application_controller.rb index 775fb34fc..5b04fbb44 100644 --- a/app/controllers/super_admin/application_controller.rb +++ b/app/controllers/super_admin/application_controller.rb @@ -7,8 +7,9 @@ class SuperAdmin::ApplicationController < Administrate::ApplicationController include ActionView::Helpers::TagHelper include ActionView::Context + include SuperAdmin::NavigationHelper - helper_method :render_vue_component + helper_method :render_vue_component, :settings_open?, :settings_pages # authenticiation done via devise : SuperAdmin Model before_action :authenticate_super_admin! diff --git a/enterprise/app/helpers/super_admin/features.yml b/app/helpers/super_admin/features.yml similarity index 90% rename from enterprise/app/helpers/super_admin/features.yml rename to app/helpers/super_admin/features.yml index f2b2b263c..f49004e79 100644 --- a/enterprise/app/helpers/super_admin/features.yml +++ b/app/helpers/super_admin/features.yml @@ -1,5 +1,7 @@ # TODO: Move this values to features.yml itself # No need to replicate the same values in two places + +# ------- Premium Features ------- # captain: name: 'Captain' description: 'Enable AI-powered conversations with your customers.' @@ -32,6 +34,15 @@ disable_branding: enabled: <%= (ChatwootHub.pricing_plan != 'community') %> icon: 'icon-sailbot-fill' enterprise: true + +# ------- Product Features ------- # +help_center: + name: 'Help Center' + description: 'Allow agents to create help center articles and publish them in a portal.' + enabled: true + icon: 'icon-book-2-line' + +# ------- Communication Channels ------- # live_chat: name: 'Live Chat' description: 'Improve your customer experience using a live chat on your website.' @@ -42,6 +53,12 @@ email: description: 'Manage your email customer interactions from Chatwoot.' enabled: true icon: 'icon-mail-send-fill' + config_key: 'email' +sms: + name: 'SMS' + description: 'Manage your SMS customer interactions from Chatwoot.' + enabled: true + icon: 'icon-message-line' messenger: name: 'Messenger' description: 'Stay connected with your customers on Facebook & Instagram.' @@ -69,22 +86,22 @@ line: description: 'Manage your Line customer interactions from Chatwoot.' enabled: true icon: 'icon-line-line' -sms: - name: 'SMS' - description: 'Manage your SMS customer interactions from Chatwoot.' + +# ------- OAuth & Authentication ------- # +google: + name: 'Google' + description: 'Configuration for setting up Google OAuth Integration' enabled: true - icon: 'icon-message-line' -help_center: - name: 'Help Center' - description: 'Allow agents to create help center articles and publish them in a portal.' - enabled: true - icon: 'icon-book-2-line' + icon: 'icon-google' + config_key: 'google' microsoft: name: 'Microsoft' description: 'Configuration for setting up Microsoft Email' enabled: true icon: 'icon-microsoft' config_key: 'microsoft' + +# ------- Third-party Integrations ------- # linear: name: 'Linear' description: 'Configuration for setting up Linear Integration' diff --git a/enterprise/app/helpers/super_admin/features_helper.rb b/app/helpers/super_admin/features_helper.rb similarity index 78% rename from enterprise/app/helpers/super_admin/features_helper.rb rename to app/helpers/super_admin/features_helper.rb index 2fbcd1715..475ad6d25 100644 --- a/enterprise/app/helpers/super_admin/features_helper.rb +++ b/app/helpers/super_admin/features_helper.rb @@ -1,6 +1,6 @@ module SuperAdmin::FeaturesHelper def self.available_features - YAML.load(ERB.new(Rails.root.join('enterprise/app/helpers/super_admin/features.yml').read).result).with_indifferent_access + YAML.load(ERB.new(Rails.root.join('app/helpers/super_admin/features.yml').read).result).with_indifferent_access end def self.plan_details diff --git a/app/helpers/super_admin/navigation_helper.rb b/app/helpers/super_admin/navigation_helper.rb new file mode 100644 index 000000000..5fca3fa76 --- /dev/null +++ b/app/helpers/super_admin/navigation_helper.rb @@ -0,0 +1,16 @@ +module SuperAdmin::NavigationHelper + def settings_open? + params[:controller].in? %w[super_admin/settings super_admin/app_configs] + end + + def settings_pages + features = SuperAdmin::FeaturesHelper.available_features.select do |_feature, attrs| + attrs['config_key'].present? && attrs['enabled'] + end + + # Add general at the beginning + general_feature = [['general', { 'config_key' => 'general', 'name' => 'General' }]] + + general_feature + features.to_a + end +end diff --git a/app/javascript/dashboard/i18n/locale/en/automation.json b/app/javascript/dashboard/i18n/locale/en/automation.json index cb030332f..cf63de81c 100644 --- a/app/javascript/dashboard/i18n/locale/en/automation.json +++ b/app/javascript/dashboard/i18n/locale/en/automation.json @@ -146,6 +146,7 @@ "SEND_WEBHOOK_EVENT": "Send Webhook Event", "SEND_ATTACHMENT": "Send Attachment", "SEND_MESSAGE": "Send a Message", + "ADD_PRIVATE_NOTE": "Add a Private Note", "CHANGE_PRIORITY": "Change Priority", "ADD_SLA": "Add SLA", "OPEN_CONVERSATION": "Open conversation" diff --git a/app/javascript/dashboard/routes/dashboard/settings/automation/constants.js b/app/javascript/dashboard/routes/dashboard/settings/automation/constants.js index 1b0f0599f..dfa6163d8 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/automation/constants.js +++ b/app/javascript/dashboard/routes/dashboard/settings/automation/constants.js @@ -555,6 +555,11 @@ export const AUTOMATION_ACTION_TYPES = [ label: 'SEND_MESSAGE', inputType: 'textarea', }, + { + key: 'add_private_note', + label: 'ADD_PRIVATE_NOTE', + inputType: 'textarea', + }, { key: 'change_priority', label: 'CHANGE_PRIORITY', diff --git a/app/models/automation_rule.rb b/app/models/automation_rule.rb index c8f5a180d..6f3f47d9c 100644 --- a/app/models/automation_rule.rb +++ b/app/models/automation_rule.rb @@ -41,7 +41,8 @@ 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 open_conversation snooze_conversation change_priority send_email_transcript].freeze + send_attachment change_status resolve_conversation open_conversation snooze_conversation change_priority send_email_transcript + add_private_note].freeze end def file_base_data diff --git a/app/services/automation_rules/action_service.rb b/app/services/automation_rules/action_service.rb index 290e14a9e..e409faba2 100644 --- a/app/services/automation_rules/action_service.rb +++ b/app/services/automation_rules/action_service.rb @@ -47,6 +47,13 @@ class AutomationRules::ActionService < ActionService Messages::MessageBuilder.new(nil, @conversation, params).perform end + def add_private_note(message) + return if conversation_a_tweet? + + params = { content: message[0], private: true, content_attributes: { automation_rule_id: @rule.id } } + Messages::MessageBuilder.new(nil, @conversation.reload, params).perform + end + def send_email_to_team(params) teams = Team.where(id: params[0][:team_ids]) diff --git a/app/views/super_admin/application/_icons.html.erb b/app/views/super_admin/application/_icons.html.erb index 6669fe87d..a45c4c1b3 100644 --- a/app/views/super_admin/application/_icons.html.erb +++ b/app/views/super_admin/application/_icons.html.erb @@ -2,6 +2,12 @@ + + + + + + diff --git a/app/views/super_admin/application/_nav_item.html.erb b/app/views/super_admin/application/_nav_item.html.erb index a6366d8b5..a32fddd11 100644 --- a/app/views/super_admin/application/_nav_item.html.erb +++ b/app/views/super_admin/application/_nav_item.html.erb @@ -1,6 +1,4 @@ -
  • +
  • <% text_class_name = current_page?(url) ? 'text-woot-500 bg-slate-25' : 'text-slate-800' %> <%= link_to(url, class: text_class_name + " -ml-1 focus:outline-none cursor-pointer flex items-center px-2 py-1.5 text-slate-800 cursor-pointer hover:text-woot-500 hover:bg-slate-25 rounded-lg") do %> diff --git a/app/views/super_admin/application/_navigation.html.erb b/app/views/super_admin/application/_navigation.html.erb index f673c6bd1..787576d33 100644 --- a/app/views/super_admin/application/_navigation.html.erb +++ b/app/views/super_admin/application/_navigation.html.erb @@ -39,14 +39,13 @@ as defined by the routes in the `admin/` namespace label: display_resource_name(resource), } %> + <% end %> + <%= render 'settings_menu', open: settings_open? %>
    -
    -
    -
    -

    Current plan

    - - - Refresh - + <% if ChatwootApp.enterprise? %> +
    +
    +
    +

    Current plan

    + + + Refresh + +
    +

    <%= SuperAdmin::FeaturesHelper.plan_details.html_safe %>

    -

    <%= SuperAdmin::FeaturesHelper.plan_details.html_safe %>

    + + +
    - - - -
    + <% end %> <% if ChatwootHub.pricing_plan != 'community' && User.count > ChatwootHub.pricing_plan_quantity %>
    @@ -99,10 +101,11 @@
    <% if !attrs[:enabled] %> <% end %>
    diff --git a/config/installation_config.yml b/config/installation_config.yml index b17d3cec0..2e8d94a96 100644 --- a/config/installation_config.yml +++ b/config/installation_config.yml @@ -87,11 +87,14 @@ # ------- Email Related Config ------- # - name: MAILER_INBOUND_EMAIL_DOMAIN + display_title: 'Inbound Email Domain' value: description: 'The domain name to be used for generating conversation continuity emails (reply+id@domain.com)' locked: false - name: MAILER_SUPPORT_EMAIL + display_title: 'Support Email' value: + description: 'The support email address for your installation' locked: false # ------- End of Email Related Config ------- # @@ -394,3 +397,22 @@ locked: false type: secret # ------- End of OG Image Related Config ------- # + +## ------ Configs added for Google OAuth ------ ## +- name: GOOGLE_OAUTH_CLIENT_ID + display_title: 'Google OAuth Client ID' + value: + locked: false + description: 'Google OAuth Client ID for email authentication' +- name: GOOGLE_OAUTH_CLIENT_SECRET + display_title: 'Google OAuth Client Secret' + value: + locked: false + description: 'Google OAuth Client Secret for email authentication' + type: secret +- name: GOOGLE_OAUTH_REDIRECT_URI + display_title: 'Google OAuth Redirect URI' + value: + locked: false + description: 'The redirect URI configured in your Google OAuth app' +## ------ End of Configs added for Google OAuth ------ ## diff --git a/lib/chatwoot_hub.rb b/lib/chatwoot_hub.rb index 0d99becd3..c18fb299b 100644 --- a/lib/chatwoot_hub.rb +++ b/lib/chatwoot_hub.rb @@ -19,10 +19,14 @@ class ChatwootHub end def self.pricing_plan + return 'community' unless ChatwootApp.enterprise? + InstallationConfig.find_by(name: 'INSTALLATION_PRICING_PLAN')&.value || 'community' end def self.pricing_plan_quantity + return 0 unless ChatwootApp.enterprise? + InstallationConfig.find_by(name: 'INSTALLATION_PRICING_PLAN_QUANTITY')&.value || 0 end diff --git a/spec/services/automation_rules/action_service_spec.rb b/spec/services/automation_rules/action_service_spec.rb index bdfa7af0c..e63fd7545 100644 --- a/spec/services/automation_rules/action_service_spec.rb +++ b/spec/services/automation_rules/action_service_spec.rb @@ -117,5 +117,27 @@ RSpec.describe AutomationRules::ActionService do expect(mailer).to have_received(:conversation_transcript).exactly(1).times end end + + describe '#perform with add_private_note action' do + let(:message_builder) { double } + + before do + allow(Messages::MessageBuilder).to receive(:new).and_return(message_builder) + rule.actions.delete_if { |a| a['action_name'] == 'send_message' } + rule.actions << { action_name: 'add_private_note', action_params: ['Note'] } + end + + it 'will add private note' do + expect(message_builder).to receive(:perform) + described_class.new(rule, account, conversation).perform + end + + it 'will not add note if conversation is a tweet' do + twitter_inbox = create(:inbox, channel: create(:channel_twitter_profile, account: account)) + conversation = create(:conversation, inbox: twitter_inbox, additional_attributes: { type: 'tweet' }) + expect(message_builder).not_to receive(:perform) + described_class.new(rule, account, conversation).perform + end + end end end