diff --git a/Gemfile b/Gemfile index 680a0738b..7533cf3cf 100644 --- a/Gemfile +++ b/Gemfile @@ -76,7 +76,7 @@ gem 'faraday_middleware-aws-sigv4' ##--- gems for server & infra configuration ---## gem 'dotenv-rails', '>= 3.0.0' gem 'foreman' -gem 'puma' +gem 'puma', '~> 7.2', '>= 7.2.1' gem 'vite_rails' # metrics on heroku gem 'barnes' diff --git a/Gemfile.lock b/Gemfile.lock index 7151d0ff1..ad2a96921 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -593,7 +593,7 @@ GEM sidekiq newrelic_rpm (9.6.0) base64 - nio4r (2.7.3) + nio4r (2.7.5) nokogiri (1.19.3) mini_portile2 (~> 2.8.2) racc (~> 1.4) @@ -682,7 +682,7 @@ GEM pry-rails (0.3.9) pry (>= 0.10.4) public_suffix (7.0.5) - puma (6.4.3) + puma (7.2.1) nio4r (~> 2.0) pundit (2.3.0) activesupport (>= 3.0.0) @@ -1132,7 +1132,7 @@ DEPENDENCIES pgvector procore-sift pry-rails - puma + puma (~> 7.2, >= 7.2.1) pundit rack-attack (>= 6.7.0) rack-cors (= 2.0.0) diff --git a/app/controllers/api/v1/accounts/portals_controller.rb b/app/controllers/api/v1/accounts/portals_controller.rb index 770018e3c..c74c0ecfc 100644 --- a/app/controllers/api/v1/accounts/portals_controller.rb +++ b/app/controllers/api/v1/accounts/portals_controller.rb @@ -80,10 +80,15 @@ class Api::V1::Accounts::PortalsController < Api::V1::Accounts::BaseController :id, :color, :custom_domain, :header_text, :homepage_link, :name, :page_title, :slug, :archived, { config: [:default_locale, :layout, { allowed_locales: [] }, { draft_locales: [] }, - { social_profiles: %i[facebook x instagram linkedin youtube tiktok github whatsapp] }] } + { social_profiles: %i[facebook x instagram linkedin youtube tiktok github whatsapp] }, + { locale_translations: locale_translation_keys.index_with { %i[name page_title header_text] } }] } ) end + def locale_translation_keys + params.dig(:portal, :config, :locale_translations)&.keys || [] + end + def live_chat_widget_params permitted_params = params.permit(:inbox_id) return {} unless permitted_params.key?(:inbox_id) diff --git a/app/controllers/concerns/access_token_auth_helper.rb b/app/controllers/concerns/access_token_auth_helper.rb index 7fb27799f..10d0bc7e7 100644 --- a/app/controllers/concerns/access_token_auth_helper.rb +++ b/app/controllers/concerns/access_token_auth_helper.rb @@ -1,8 +1,9 @@ module AccessTokenAuthHelper BOT_ACCESSIBLE_ENDPOINTS = { - 'api/v1/accounts/conversations' => %w[toggle_status toggle_typing_status toggle_priority create update custom_attributes], + 'api/v1/accounts/conversations' => %w[show toggle_status toggle_typing_status toggle_priority create update custom_attributes], 'api/v1/accounts/conversations/messages' => ['create'], - 'api/v1/accounts/conversations/assignments' => ['create'] + 'api/v1/accounts/conversations/assignments' => ['create'], + 'api/v1/accounts/conversations/labels' => %w[index create] }.freeze def ensure_access_token diff --git a/app/controllers/public/api/v1/portals_controller.rb b/app/controllers/public/api/v1/portals_controller.rb index 63f44b052..57db11aec 100644 --- a/app/controllers/public/api/v1/portals_controller.rb +++ b/app/controllers/public/api/v1/portals_controller.rb @@ -9,7 +9,7 @@ class Public::Api::V1::PortalsController < Public::Api::V1::Portals::BaseControl layout 'portal' def show - @og_image_url = helpers.set_og_image_url('', @portal.header_text) + @og_image_url = helpers.set_og_image_url('', @portal.localized_value('header_text', @locale)) end def sitemap diff --git a/app/drops/contact_drop.rb b/app/drops/contact_drop.rb index 1d450adb7..16240ec06 100644 --- a/app/drops/contact_drop.rb +++ b/app/drops/contact_drop.rb @@ -12,7 +12,7 @@ class ContactDrop < BaseDrop end def first_name - @obj.try(:name).try(:split).try(:first).try(:capitalize) if @obj.try(:name).try(:split).try(:size) > 1 + @obj.try(:name).try(:split).try(:first).try(:capitalize) end def last_name diff --git a/app/drops/user_drop.rb b/app/drops/user_drop.rb index cf6f1b6a1..83d5e2347 100644 --- a/app/drops/user_drop.rb +++ b/app/drops/user_drop.rb @@ -12,7 +12,7 @@ class UserDrop < BaseDrop end def first_name - @obj.try(:name).try(:split).try(:first).try(:capitalize) if @obj.try(:name).try(:split).try(:size).to_i > 1 + @obj.try(:name).try(:split).try(:first).try(:capitalize) end def last_name diff --git a/app/helpers/super_admin/features.yml b/app/helpers/super_admin/features.yml index f21a97f78..6489d0194 100644 --- a/app/helpers/super_admin/features.yml +++ b/app/helpers/super_admin/features.yml @@ -34,6 +34,12 @@ disable_branding: enabled: <%= (ChatwootHub.pricing_plan != 'community') %> icon: 'icon-sailbot-fill' enterprise: true +voice_calls: + name: 'Voice Calls' + description: 'Enable voice calling capabilities for your agents and customers.' + enabled: <%= (ChatwootHub.pricing_plan != 'community') %> + icon: 'icon-voice-line' + enterprise: true # ------- Product Features ------- # help_center: diff --git a/app/javascript/dashboard/api/channel/voice/twilioVoiceClient.js b/app/javascript/dashboard/api/channel/voice/twilioVoiceClient.js index 13f61a16c..14dd56ec9 100644 --- a/app/javascript/dashboard/api/channel/voice/twilioVoiceClient.js +++ b/app/javascript/dashboard/api/channel/voice/twilioVoiceClient.js @@ -48,6 +48,12 @@ class TwilioVoiceClient extends EventTarget { return !!this.activeConnection; } + setMuted(shouldMute) { + if (!this.activeConnection) return false; + this.activeConnection.mute(shouldMute); + return shouldMute; + } + endClientCall() { if (this.activeConnection) { this.activeConnection.disconnect(); diff --git a/app/javascript/dashboard/components-next/Companies/CompaniesCard/CompaniesCard.vue b/app/javascript/dashboard/components-next/Companies/CompaniesCard/CompaniesCard.vue index fe4385bbb..d81b997c5 100644 --- a/app/javascript/dashboard/components-next/Companies/CompaniesCard/CompaniesCard.vue +++ b/app/javascript/dashboard/components-next/Companies/CompaniesCard/CompaniesCard.vue @@ -46,9 +46,8 @@ const formattedLastActivityAt = computed(() => { :src="avatarSource" class="shrink-0" :name="name" - :size="48" + :size="42" hide-offline-status - rounded-full />
diff --git a/app/javascript/dashboard/components-next/Companies/CompanyDetail/CompanyProfileCard.vue b/app/javascript/dashboard/components-next/Companies/CompanyDetail/CompanyProfileCard.vue index 1ffbf0c18..7615328ca 100644 --- a/app/javascript/dashboard/components-next/Companies/CompanyDetail/CompanyProfileCard.vue +++ b/app/javascript/dashboard/components-next/Companies/CompanyDetail/CompanyProfileCard.vue @@ -141,7 +141,6 @@ const handleUpdateCompany = async () => { :src="avatarSource" :size="72" :allow-upload="!isAvatarBusy" - rounded-full hide-offline-status @upload="handleAvatarUpload" @delete="handleAvatarDelete" diff --git a/app/javascript/dashboard/components-next/Contacts/ContactsCard/ContactsCard.vue b/app/javascript/dashboard/components-next/Contacts/ContactsCard/ContactsCard.vue index ba887b46f..50af6f0c0 100644 --- a/app/javascript/dashboard/components-next/Contacts/ContactsCard/ContactsCard.vue +++ b/app/javascript/dashboard/components-next/Contacts/ContactsCard/ContactsCard.vue @@ -124,10 +124,9 @@ const handleAvatarHover = isHovered => {