diff --git a/app/jobs/internal/process_stale_contacts_job.rb b/app/jobs/internal/process_stale_contacts_job.rb
new file mode 100644
index 000000000..eaf53be75
--- /dev/null
+++ b/app/jobs/internal/process_stale_contacts_job.rb
@@ -0,0 +1,18 @@
+# housekeeping
+# remove stale contacts for all accounts
+# - have no identification (email, phone_number, and identifier are NULL)
+# - have no conversations
+# - are older than 30 days
+
+class Internal::ProcessStaleContactsJob < ApplicationJob
+ queue_as :scheduled_jobs
+
+ def perform
+ Account.find_in_batches(batch_size: 100) do |accounts|
+ accounts.each do |account|
+ Rails.logger.info "Enqueuing RemoveStaleContactsJob for account #{account.id}"
+ Internal::RemoveStaleContactsJob.perform_later(account)
+ end
+ end
+ end
+end
diff --git a/app/jobs/internal/remove_stale_contacts_job.rb b/app/jobs/internal/remove_stale_contacts_job.rb
new file mode 100644
index 000000000..3c33fd245
--- /dev/null
+++ b/app/jobs/internal/remove_stale_contacts_job.rb
@@ -0,0 +1,13 @@
+# housekeeping
+# remove contacts that:
+# - have no identification (email, phone_number, and identifier are NULL)
+# - have no conversations
+# - are older than 30 days
+
+class Internal::RemoveStaleContactsJob < ApplicationJob
+ queue_as :low
+
+ def perform(account, batch_size = 1000)
+ Internal::RemoveStaleContactsService.new(account: account).perform(batch_size)
+ end
+end
diff --git a/app/models/account.rb b/app/models/account.rb
index e6216873c..eb95194c5 100644
--- a/app/models/account.rb
+++ b/app/models/account.rb
@@ -56,6 +56,7 @@ class Account < ApplicationRecord
has_many :data_imports, dependent: :destroy_async
has_many :email_channels, dependent: :destroy_async, class_name: '::Channel::Email'
has_many :facebook_pages, dependent: :destroy_async, class_name: '::Channel::FacebookPage'
+ has_many :instagram_channels, dependent: :destroy_async, class_name: '::Channel::Instagram'
has_many :hooks, dependent: :destroy_async, class_name: 'Integrations::Hook'
has_many :inboxes, dependent: :destroy_async
has_many :labels, dependent: :destroy_async
diff --git a/app/models/channel/facebook_page.rb b/app/models/channel/facebook_page.rb
index ce5f5d221..1755889f8 100644
--- a/app/models/channel/facebook_page.rb
+++ b/app/models/channel/facebook_page.rb
@@ -63,22 +63,4 @@ class Channel::FacebookPage < ApplicationRecord
Rails.logger.debug { "Rescued: #{e.inspect}" }
true
end
-
- # TODO: We will be removing this code after instagram_manage_insights is implemented
- def fetch_instagram_story_link(message)
- k = Koala::Facebook::API.new(page_access_token)
- result = k.get_object(message.source_id, fields: %w[story]) || {}
- story_link = result['story']['mention']['link']
- # If the story is expired then it raises the ClientError and if the story is deleted with valid story-id it responses with nil
- delete_instagram_story(message) if story_link.blank?
- story_link
- rescue Koala::Facebook::ClientError => e
- Rails.logger.debug { "Instagram Story Expired: #{e.inspect}" }
- delete_instagram_story(message)
- end
-
- def delete_instagram_story(message)
- message.attachments.destroy_all
- message.update(content: I18n.t('conversations.messages.instagram_deleted_story_content'), content_attributes: {})
- end
end
diff --git a/app/models/channel/instagram.rb b/app/models/channel/instagram.rb
new file mode 100644
index 000000000..fcfcb852e
--- /dev/null
+++ b/app/models/channel/instagram.rb
@@ -0,0 +1,28 @@
+# == Schema Information
+#
+# Table name: channel_instagram
+#
+# id :bigint not null, primary key
+# access_token :string not null
+# expires_at :datetime not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# account_id :integer not null
+# instagram_id :string not null
+#
+# Indexes
+#
+# index_channel_instagram_on_instagram_id (instagram_id) UNIQUE
+#
+class Channel::Instagram < ApplicationRecord
+ include Channelable
+
+ self.table_name = 'channel_instagram'
+
+ validates :access_token, presence: true
+ validates :instagram_id, uniqueness: true, presence: true
+
+ def name
+ 'Instagram'
+ end
+end
diff --git a/app/models/contact.rb b/app/models/contact.rb
index d9555f5fa..83920d9fc 100644
--- a/app/models/contact.rb
+++ b/app/models/contact.rb
@@ -128,6 +128,18 @@ class Contact < ApplicationRecord
)
}
+ # Find contacts that:
+ # 1. Have no identification (email, phone_number, and identifier are NULL or empty string)
+ # 2. Have no conversations
+ # 3. Are older than the specified time period
+ scope :stale_without_conversations, lambda { |time_period|
+ where('contacts.email IS NULL OR contacts.email = ?', '')
+ .where('contacts.phone_number IS NULL OR contacts.phone_number = ?', '')
+ .where('contacts.identifier IS NULL OR contacts.identifier = ?', '')
+ .where('contacts.created_at < ?', time_period)
+ .where.missing(:conversations)
+ }
+
def get_source_id(inbox_id)
contact_inboxes.find_by!(inbox_id: inbox_id).source_id
end
diff --git a/app/models/inbox.rb b/app/models/inbox.rb
index 2c08172ff..508675858 100644
--- a/app/models/inbox.rb
+++ b/app/models/inbox.rb
@@ -98,6 +98,10 @@ class Inbox < ApplicationRecord
update_account_cache
end
+ def sms?
+ channel_type == 'Channel::Sms'
+ end
+
def facebook?
channel_type == 'Channel::FacebookPage'
end
diff --git a/app/models/message.rb b/app/models/message.rb
index 6244d050c..20dad7403 100644
--- a/app/models/message.rb
+++ b/app/models/message.rb
@@ -155,15 +155,6 @@ class Message < ApplicationRecord
}
end
- # TODO: We will be removing this code after instagram_manage_insights is implemented
- # Better logic is to listen to webhook and remove stories proactively rather than trying
- # a fetch every time a message is returned
- def validate_instagram_story
- inbox.channel.fetch_instagram_story_link(self)
- # we want to reload the message in case the story has expired and data got removed
- reload
- end
-
def merge_sender_attributes(data)
data[:sender] = sender.push_event_data if sender && !sender.is_a?(AgentBot)
data[:sender] = sender.push_event_data(inbox) if sender.is_a?(AgentBot)
diff --git a/app/policies/account_policy.rb b/app/policies/account_policy.rb
index a74a13a66..5eb80c1ab 100644
--- a/app/policies/account_policy.rb
+++ b/app/policies/account_policy.rb
@@ -8,7 +8,7 @@ class AccountPolicy < ApplicationPolicy
end
def limits?
- @account_user.administrator?
+ @account_user.administrator? || @account_user.agent?
end
def update?
diff --git a/app/services/contacts/contactable_inboxes_service.rb b/app/services/contacts/contactable_inboxes_service.rb
index c5cde516f..92d4160fe 100644
--- a/app/services/contacts/contactable_inboxes_service.rb
+++ b/app/services/contacts/contactable_inboxes_service.rb
@@ -42,20 +42,20 @@ class Contacts::ContactableInboxesService
end
def email_contactable_inbox(inbox)
- return unless @contact.email
+ return if @contact.email.blank?
{ source_id: @contact.email, inbox: inbox }
end
def whatsapp_contactable_inbox(inbox)
- return unless @contact.phone_number
+ return if @contact.phone_number.blank?
# Remove the plus since thats the format 360 dialog uses
{ source_id: @contact.phone_number.delete('+'), inbox: inbox }
end
def sms_contactable_inbox(inbox)
- return unless @contact.phone_number
+ return if @contact.phone_number.blank?
{ source_id: @contact.phone_number, inbox: inbox }
end
diff --git a/app/services/internal/remove_stale_contacts_service.rb b/app/services/internal/remove_stale_contacts_service.rb
new file mode 100644
index 000000000..74e189068
--- /dev/null
+++ b/app/services/internal/remove_stale_contacts_service.rb
@@ -0,0 +1,19 @@
+class Internal::RemoveStaleContactsService
+ pattr_initialize [:account!]
+
+ def perform(batch_size = 1000)
+ contacts_to_remove = @account.contacts.stale_without_conversations(30.days.ago)
+ total_deleted = 0
+
+ Rails.logger.info "[Internal::RemoveStaleContactsService] Starting removal of stale contacts for account #{@account.id}"
+
+ contacts_to_remove.find_in_batches(batch_size: batch_size) do |batch|
+ contact_ids = batch.map(&:id)
+
+ ContactInbox.where(contact_id: contact_ids).delete_all
+ Contact.where(id: contact_ids).delete_all
+ total_deleted += batch.size
+ Rails.logger.info "[Internal::RemoveStaleContactsService] Deleted #{batch.size} contacts (#{total_deleted} total) for account #{@account.id}"
+ end
+ end
+end
diff --git a/app/services/whatsapp/send_on_whatsapp_service.rb b/app/services/whatsapp/send_on_whatsapp_service.rb
index 3d843e64b..186c8b2ae 100644
--- a/app/services/whatsapp/send_on_whatsapp_service.rb
+++ b/app/services/whatsapp/send_on_whatsapp_service.rb
@@ -28,14 +28,13 @@ class Whatsapp::SendOnWhatsappService < Base::SendOnChannelService
message.update!(source_id: message_id) if message_id.present?
end
- # rubocop:disable Metrics/CyclomaticComplexity
def processable_channel_message_template
if template_params.present?
return [
template_params['name'],
template_params['namespace'],
template_params['language'],
- template_params['processed_params']&.map { |_, value| { type: 'text', text: value } }
+ processed_templates_params(template_params)
]
end
@@ -56,7 +55,6 @@ class Whatsapp::SendOnWhatsappService < Base::SendOnChannelService
end
[nil, nil, nil, nil]
end
- # rubocop:enable Metrics/CyclomaticComplexity
def template_match_object(template)
body_object = validated_body_object(template)
@@ -82,6 +80,25 @@ class Whatsapp::SendOnWhatsappService < Base::SendOnChannelService
Regexp.new template_match_string
end
+ def template(template_params)
+ channel.message_templates.find do |t|
+ t['name'] == template_params['name'] && t['language'] == template_params['language']
+ end
+ end
+
+ def processed_templates_params(template_params)
+ template = template(template_params)
+ return if template.blank?
+
+ parameter_format = template['parameter_format']
+
+ if parameter_format == 'NAMED'
+ template_params['processed_params']&.map { |key, value| { type: 'text', parameter_name: key, text: value } }
+ else
+ template_params['processed_params']&.map { |_, value| { type: 'text', text: value } }
+ end
+ end
+
def validated_body_object(template)
# we don't care if its not approved template
return if template['status'] != 'approved'
diff --git a/app/views/widget_tests/index.html.erb b/app/views/widget_tests/index.html.erb
index 9471c44c2..45769bb45 100644
--- a/app/views/widget_tests/index.html.erb
+++ b/app/views/widget_tests/index.html.erb
@@ -62,6 +62,10 @@ window.addEventListener('chatwoot:on-message', function(e) {
console.log('chatwoot:on-message', e.detail)
})
+window.addEventListener('chatwoot:postback', function(e) {
+ console.log('chatwoot:postback', e.detail)
+})
+
window.addEventListener('chatwoot:on-start-conversation', function(e) {
console.log('chatwoot:on-start-conversation', e.detail)
diff --git a/config/app.yml b/config/app.yml
index f655afca7..df6fc62c0 100644
--- a/config/app.yml
+++ b/config/app.yml
@@ -1,5 +1,5 @@
shared: &shared
- version: '4.0.3'
+ version: '4.0.4'
development:
<<: *shared
diff --git a/config/locales/am.yml b/config/locales/am.yml
index 3e2297c78..905e236d7 100644
--- a/config/locales/am.yml
+++ b/config/locales/am.yml
@@ -53,6 +53,8 @@ am:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ am:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/ar.yml b/config/locales/ar.yml
index f01e74dd6..f86f6a30d 100644
--- a/config/locales/ar.yml
+++ b/config/locales/ar.yml
@@ -53,6 +53,8 @@ ar:
invalid_message_type: 'نوع الرسالة غير صالح. الإجراء غير مسموح به'
slack:
invalid_channel_id: 'قناة Slack غير صحيحة. الرجاء المحاولة مرة أخرى'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: الرجاء التحقق من اتصال الشبكة وعنوان IMAP ثم حاول مرة أخرى.
@@ -217,6 +219,9 @@ ar:
linear:
name: 'Linear'
description: 'إنشاء مشكلات في Linear مباشرة من نافذة المحادثة الخاصة بك. بدلاً من ذلك، قم بربط مشكلات Linear القائمة من أجل عملية تتبع أكثر تبسيطاً وكفاءة.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/az.yml b/config/locales/az.yml
index ffd7e9051..0a178161c 100644
--- a/config/locales/az.yml
+++ b/config/locales/az.yml
@@ -53,6 +53,8 @@ az:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ az:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/bg.yml b/config/locales/bg.yml
index 05f930db4..98ae8f3a9 100644
--- a/config/locales/bg.yml
+++ b/config/locales/bg.yml
@@ -53,6 +53,8 @@ bg:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ bg:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/ca.yml b/config/locales/ca.yml
index c07a98f2f..f1a1bcfe1 100644
--- a/config/locales/ca.yml
+++ b/config/locales/ca.yml
@@ -53,6 +53,8 @@ ca:
invalid_message_type: 'Tipus de missatge no vàlid. Acció no permesa'
slack:
invalid_channel_id: 'Canal slack no vàlid. Torna-ho a provar'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Comprova la connexió de xarxa, l'adreça IMAP i torna-ho a provar.
@@ -217,6 +219,9 @@ ca:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/cs.yml b/config/locales/cs.yml
index 5e5c74c9e..fd687b472 100644
--- a/config/locales/cs.yml
+++ b/config/locales/cs.yml
@@ -53,6 +53,8 @@ cs:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ cs:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/da.yml b/config/locales/da.yml
index c7e268c88..f7186445a 100644
--- a/config/locales/da.yml
+++ b/config/locales/da.yml
@@ -53,6 +53,8 @@ da:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Tjek venligst netværksforbindelsen, IMAP-adressen og prøv igen.
@@ -217,6 +219,9 @@ da:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 89bd65f0b..465519e5e 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -53,6 +53,8 @@ de:
invalid_message_type: 'Ungültiger Nachrichtentyp. Aktion nicht erlaubt'
slack:
invalid_channel_id: 'Ungültiger Slack Channel. Bitte erneut versuchen'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Bitte überprüfen Sie die Netzwerkverbindung, die IMAP-Adresse und versuchen Sie es erneut.
@@ -217,6 +219,9 @@ de:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/el.yml b/config/locales/el.yml
index 8b7330a3c..f41b53c30 100644
--- a/config/locales/el.yml
+++ b/config/locales/el.yml
@@ -53,6 +53,8 @@ el:
invalid_message_type: 'Μη έγκυρος τύπος μηνύματος. Δεν επιτρέπεται η ενέργεια'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Παρακαλώ ελέγξτε τη σύνδεση δικτύου, τη διεύθυνση IMAP και προσπαθήστε ξανά.
@@ -217,6 +219,9 @@ el:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 63e176c5c..711fc238c 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -53,6 +53,8 @@ es:
invalid_message_type: 'Tipo de mensaje inválido. Acción no permitida'
slack:
invalid_channel_id: 'Canal de slack inválido. Por favor, inténtalo de nuevo'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Verifique la conexión de red, la dirección IMAP y vuelva a intentarlo.
@@ -217,6 +219,9 @@ es:
linear:
name: 'Lineal'
description: 'Crea problemas en Linear directamente desde tu ventana de conversación. Alternativamente, enlaza problemas existentes en Linear para un proceso de seguimiento de problemas más eficiente y ágil.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Conecte un asistente a esta bandeja de entrada para utilizar Copilot'
copilot_limit: 'Te quedaste sin créditos de Copilot. Puedes comprar más créditos desde la sección de facturación.'
diff --git a/config/locales/fa.yml b/config/locales/fa.yml
index 3818d1d2e..1e2b1ba44 100644
--- a/config/locales/fa.yml
+++ b/config/locales/fa.yml
@@ -53,6 +53,8 @@ fa:
invalid_message_type: 'نوع پیام نامعتبر است. اقدام مجاز نیست'
slack:
invalid_channel_id: 'کانال اسلک نامعتبر است. لطفا دوباره تلاش کنید'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: لطفا اتصال شبکه، آدرس IMAP را بررسی کنید و دوباره امتحان کنید.
@@ -217,6 +219,9 @@ fa:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/fi.yml b/config/locales/fi.yml
index 992be9fd1..25e6193bb 100644
--- a/config/locales/fi.yml
+++ b/config/locales/fi.yml
@@ -53,6 +53,8 @@ fi:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ fi:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index c47b19809..1b7846cf5 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -53,6 +53,8 @@ fr:
invalid_message_type: 'Type de message invalide. Action non autorisée'
slack:
invalid_channel_id: 'Canal Slack invalide. Veuillez réessayer'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Veuillez vérifier la connexion, l'adresse IMAP et réessayez.
@@ -217,6 +219,9 @@ fr:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/he.yml b/config/locales/he.yml
index 7162882a6..dee5aa5e1 100644
--- a/config/locales/he.yml
+++ b/config/locales/he.yml
@@ -53,6 +53,8 @@ he:
invalid_message_type: 'סוג הודעה לא חוקי. פעולה אסורה'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ he:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/hi.yml b/config/locales/hi.yml
index a31c616dc..3fb3e1708 100644
--- a/config/locales/hi.yml
+++ b/config/locales/hi.yml
@@ -53,6 +53,8 @@ hi:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ hi:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/hr.yml b/config/locales/hr.yml
index 735bf0067..b285cda29 100644
--- a/config/locales/hr.yml
+++ b/config/locales/hr.yml
@@ -53,6 +53,8 @@ hr:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ hr:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/hu.yml b/config/locales/hu.yml
index 73ece653d..9d6569f25 100644
--- a/config/locales/hu.yml
+++ b/config/locales/hu.yml
@@ -53,6 +53,8 @@ hu:
invalid_message_type: 'Hibás üzenet típus. Kérés elutasítva'
slack:
invalid_channel_id: 'Érvénytelen Slack csatorna. Kérjük, próbálja újra'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Kérlek ellenőrizd a hálózati kapcsolatot, az IMAP címet, majd próbáld újra.
@@ -217,6 +219,9 @@ hu:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/hy.yml b/config/locales/hy.yml
index 0750ac8c1..15dbf2328 100644
--- a/config/locales/hy.yml
+++ b/config/locales/hy.yml
@@ -53,6 +53,8 @@ hy:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ hy:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/id.yml b/config/locales/id.yml
index a154d065c..12bb26056 100644
--- a/config/locales/id.yml
+++ b/config/locales/id.yml
@@ -53,6 +53,8 @@ id:
invalid_message_type: 'Jenis pesan tidak valid. Tindakan tidak diizinkan'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Periksa sambungan jaringan, alamat IMAP, dan coba lagi.
@@ -217,6 +219,9 @@ id:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/is.yml b/config/locales/is.yml
index 5847ea6d7..1f7a4abfb 100644
--- a/config/locales/is.yml
+++ b/config/locales/is.yml
@@ -53,6 +53,8 @@ is:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Athugaðu nettenginguna, IMAP vistfangið og reyndu aftur.
@@ -217,6 +219,9 @@ is:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/it.yml b/config/locales/it.yml
index 39b14762d..94f7e09aa 100644
--- a/config/locales/it.yml
+++ b/config/locales/it.yml
@@ -53,6 +53,8 @@ it:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Controlla la connessione di rete, l'indirizzo IMAP e riprova.
@@ -217,6 +219,9 @@ it:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index 0fb403728..80c424c6d 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -53,6 +53,8 @@ ja:
invalid_message_type: '無効なメッセージタイプです。アクションは許可されていません'
slack:
invalid_channel_id: '無効なSlackチャンネルです。もう一度お試しください。'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: ネットワーク接続、IMAPアドレスを確認の上、再度お試しください。
@@ -217,6 +219,9 @@ ja:
linear:
name: 'Linear'
description: '会話ウィンドウから直接Linearに問題を作成します。あるいは、既存のLinearの問題をリンクして、より効率的な問題追跡プロセスを実現します。'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'この受信トレイにアシスタントを接続してCopilotを使用してください'
copilot_limit: 'Copilot残高がありません。課金セクションからクレジットを追加購入することができます。'
diff --git a/config/locales/ka.yml b/config/locales/ka.yml
index 51083a438..4ed4e4369 100644
--- a/config/locales/ka.yml
+++ b/config/locales/ka.yml
@@ -53,6 +53,8 @@ ka:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ ka:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/ko.yml b/config/locales/ko.yml
index 6008c841a..c0a4fe11c 100644
--- a/config/locales/ko.yml
+++ b/config/locales/ko.yml
@@ -53,6 +53,8 @@ ko:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ ko:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/lt.yml b/config/locales/lt.yml
index 50475f598..1bf7bb2cd 100644
--- a/config/locales/lt.yml
+++ b/config/locales/lt.yml
@@ -53,6 +53,8 @@ lt:
invalid_message_type: 'Neteisingas pranešimo tipas. Veiksmas neleidžiamas'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Patikrinkite tinklo sujungimus, IMAP adresą ir bandykite dar kartą.
@@ -217,6 +219,9 @@ lt:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/lv.yml b/config/locales/lv.yml
index 98754b4eb..b817997d1 100644
--- a/config/locales/lv.yml
+++ b/config/locales/lv.yml
@@ -53,6 +53,8 @@ lv:
invalid_message_type: 'Nederīgs ziņojuma veids. Darbība nav atļauta'
slack:
invalid_channel_id: 'Nepareizs Slack kanāls. Lūdzu, mēģiniet vēlreiz'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Lūdzu, pārbaudiet tīkla savienojumu, IMAP adresi un mēģiniet vēlreiz.
@@ -217,6 +219,9 @@ lv:
linear:
name: 'Lineārs'
description: 'Izveidojiet problēmu pieteikumus programmā Linear, tieši no sarunas loga. Varat arī sasaistīt esošos Linear problēmu pieteikumus, lai nodrošinātu racionālāku un efektīvāku problēmu izsekošanas procesu.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Lai izmantotu Copilot, lūdzu, pievienojiet šai iesūtnei palīgu'
copilot_limit: 'Jums ir beigušies Copilot kredīti. Vairāk kredītu varat iegādāties norēķinu sadaļā.'
diff --git a/config/locales/ml.yml b/config/locales/ml.yml
index 268c76329..d97c9c258 100644
--- a/config/locales/ml.yml
+++ b/config/locales/ml.yml
@@ -53,6 +53,8 @@ ml:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ ml:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/ms.yml b/config/locales/ms.yml
index d8cb502e9..5bf8726d3 100644
--- a/config/locales/ms.yml
+++ b/config/locales/ms.yml
@@ -53,6 +53,8 @@ ms:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ ms:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/ne.yml b/config/locales/ne.yml
index 5c72426a4..9abde5cfc 100644
--- a/config/locales/ne.yml
+++ b/config/locales/ne.yml
@@ -53,6 +53,8 @@ ne:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ ne:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/nl.yml b/config/locales/nl.yml
index 7ff10aa66..80aea0ece 100644
--- a/config/locales/nl.yml
+++ b/config/locales/nl.yml
@@ -53,6 +53,8 @@ nl:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Controleer de netwerkverbinding, IMAP-adres en probeer het opnieuw.
@@ -217,6 +219,9 @@ nl:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/no.yml b/config/locales/no.yml
index 771c924a0..44792478f 100644
--- a/config/locales/no.yml
+++ b/config/locales/no.yml
@@ -53,6 +53,8 @@
invalid_message_type: 'Ugyldig meldingstype. Handlingen er ikke tillatt'
slack:
invalid_channel_id: 'Ugyldig slack kanal. Vennligst prøv på nytt'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Kontroller nettverkstilkoblingen, IMAP-adressen og prøv på nytt.
@@ -217,6 +219,9 @@
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index f95e8a1c8..564917bcb 100644
--- a/config/locales/pl.yml
+++ b/config/locales/pl.yml
@@ -53,6 +53,8 @@ pl:
invalid_message_type: 'Nieprawidłowy typ wiadomości. Niedozwolone działanie.'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Sprawdź połączenie sieciowe, adres IMAP i spróbuj ponownie.
@@ -217,6 +219,9 @@ pl:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/pt.yml b/config/locales/pt.yml
index 844485ca6..001709b4b 100644
--- a/config/locales/pt.yml
+++ b/config/locales/pt.yml
@@ -53,6 +53,8 @@ pt:
invalid_message_type: 'Tipo de mensagem inválido. Ação não permitida'
slack:
invalid_channel_id: 'Canal de slack inválido. Por favor, tente novamente'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Por favor, verifique a ligação à rede, endereço IMAP e tente novamente.
@@ -217,6 +219,9 @@ pt:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/pt_BR.yml b/config/locales/pt_BR.yml
index 36ec2df73..dab14bb08 100644
--- a/config/locales/pt_BR.yml
+++ b/config/locales/pt_BR.yml
@@ -53,6 +53,8 @@ pt_BR:
invalid_message_type: 'Tipo de mensagem inválido. Ação não permitida'
slack:
invalid_channel_id: 'Canal de slack inválido. Por favor, tente novamente'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Por favor, verifique a conexão de rede, endereço IMAP e tente novamente.
@@ -217,6 +219,9 @@ pt_BR:
linear:
name: 'Linear'
description: 'Crie issues em Linear diretamente da sua janela de conversa. Alternativamente, vincule as issues lineares existentes para um processo de rastreamento de problemas mais simples e eficiente.'
+ shopify:
+ name: 'Shopify'
+ description: 'Conecte sua loja Shopify para acessar detalhes de pedidos, informações de clientes e dados de produtos diretamente em suas conversas e ajudar sua equipe de suporte a fornecer um atendimento mais rápido e contextual aos seus clientes.'
captain:
copilot_error: 'Conecte com um assistente a esta caixa de entrada para usar Copilot'
copilot_limit: 'Você está sem créditos de Copilot. Pode comprar mais créditos na seção de faturamento.'
diff --git a/config/locales/ro.yml b/config/locales/ro.yml
index f832b940a..8dd0ff599 100644
--- a/config/locales/ro.yml
+++ b/config/locales/ro.yml
@@ -53,6 +53,8 @@ ro:
invalid_message_type: 'Tip de mesaj nevalid. Acțiune nepermisă'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Verificați conexiunea la rețea, adresa IMAP și încercați din nou.
@@ -217,6 +219,9 @@ ro:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index c0a6618ba..40993bbf1 100644
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -53,6 +53,8 @@ ru:
invalid_message_type: 'Недопустимый тип сообщения. Действие запрещено'
slack:
invalid_channel_id: 'Неправильный канал slack - попробуйте еще раз'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Пожалуйста, проверьте сетевое подключение, адрес IMAP и повторите попытку.
@@ -217,6 +219,9 @@ ru:
linear:
name: 'Linear'
description: 'Создавайте или прикрепляйте уже существующие задачи в Linear непосредственно из окна диалога для более упорядоченного и эффективного процесса отслеживания проблем.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Пожалуйста, подключите ассистента к этому источнику входящих для использования Copilot'
copilot_limit: 'У вас закончились кредиты для Copilot. Вы можете купить дополнительные кредиты в разделе биллинга.'
diff --git a/config/locales/sh.yml b/config/locales/sh.yml
index 0714ad604..5330e99a9 100644
--- a/config/locales/sh.yml
+++ b/config/locales/sh.yml
@@ -53,6 +53,8 @@ sh:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ sh:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/sk.yml b/config/locales/sk.yml
index 1de4582a0..21fc7d850 100644
--- a/config/locales/sk.yml
+++ b/config/locales/sk.yml
@@ -53,6 +53,8 @@ sk:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ sk:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/sl.yml b/config/locales/sl.yml
index 7af2f0215..3090c7424 100644
--- a/config/locales/sl.yml
+++ b/config/locales/sl.yml
@@ -53,6 +53,8 @@ sl:
invalid_message_type: 'Neveljavna vrsta sporočila. Dejanje ni dovoljeno'
slack:
invalid_channel_id: 'Neveljaven slack kanal. Prosimo poskusite ponovno'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Preverite omrežno povezavo, naslov IMAP in poskusite znova.
@@ -217,6 +219,9 @@ sl:
linear:
name: 'Linear'
description: 'Ustvarite issue v Linearju neposredno iz pogovornega okna. Druga možnost je, da povežete obstoječe Linear issue za bolj poenostavljen in učinkovit postopek sledenja težavam.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/sq.yml b/config/locales/sq.yml
index e5b7dab72..048acbe86 100644
--- a/config/locales/sq.yml
+++ b/config/locales/sq.yml
@@ -53,6 +53,8 @@ sq:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ sq:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/sr.yml b/config/locales/sr.yml
index 356ad5346..fdd689e6e 100644
--- a/config/locales/sr.yml
+++ b/config/locales/sr.yml
@@ -53,6 +53,8 @@ sr-Latn:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Molim vas proverite vezu sa mrežom, IMAP adresu i pokušajte ponovo.
@@ -217,6 +219,9 @@ sr-Latn:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/sv.yml b/config/locales/sv.yml
index a12e6c4b5..3c9d4dcaa 100644
--- a/config/locales/sv.yml
+++ b/config/locales/sv.yml
@@ -53,6 +53,8 @@ sv:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ sv:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/ta.yml b/config/locales/ta.yml
index edfda5b74..521321236 100644
--- a/config/locales/ta.yml
+++ b/config/locales/ta.yml
@@ -53,6 +53,8 @@ ta:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ ta:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/th.yml b/config/locales/th.yml
index f0d49ef53..28524b441 100644
--- a/config/locales/th.yml
+++ b/config/locales/th.yml
@@ -53,6 +53,8 @@ th:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ th:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/tl.yml b/config/locales/tl.yml
index d6995fabf..692baecac 100644
--- a/config/locales/tl.yml
+++ b/config/locales/tl.yml
@@ -53,6 +53,8 @@ tl:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ tl:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/tr.yml b/config/locales/tr.yml
index e3e6c0dec..b154a6f21 100644
--- a/config/locales/tr.yml
+++ b/config/locales/tr.yml
@@ -53,6 +53,8 @@ tr:
invalid_message_type: 'Geçersiz mesaj türü. İşlem izin verilmiyor'
slack:
invalid_channel_id: 'Geçersiz Slack kanalı. Lütfen tekrar deneyin'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Lütfen ağ bağlantınızı, IMAP adresini kontrol edin ve tekrar deneyin.
@@ -217,6 +219,9 @@ tr:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/uk.yml b/config/locales/uk.yml
index c7860385f..2bf4968a8 100644
--- a/config/locales/uk.yml
+++ b/config/locales/uk.yml
@@ -53,6 +53,8 @@ uk:
invalid_message_type: 'Невірний тип повідомлення. Дію не дозволено'
slack:
invalid_channel_id: 'Недійсний канал slack. Будь ласка, спробуйте ще раз'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Перевірте підключення до мережі, адреса IMAP і повторіть спробу.
@@ -217,6 +219,9 @@ uk:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/ur.yml b/config/locales/ur.yml
index defae7b0d..ffbd664ee 100644
--- a/config/locales/ur.yml
+++ b/config/locales/ur.yml
@@ -53,6 +53,8 @@ ur:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ ur:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/ur_IN.yml b/config/locales/ur_IN.yml
index 76fdf9707..542424bb7 100644
--- a/config/locales/ur_IN.yml
+++ b/config/locales/ur_IN.yml
@@ -53,6 +53,8 @@ ur:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ ur:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/vi.yml b/config/locales/vi.yml
index 378faded9..aa8344f97 100644
--- a/config/locales/vi.yml
+++ b/config/locales/vi.yml
@@ -53,6 +53,8 @@ vi:
invalid_message_type: 'Loại tin nhắn không hợp lệ. Hành động không được phép'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Vui lòng kiểm tra kết nối mạng, địa chỉ IMAP và thử lại.
@@ -217,6 +219,9 @@ vi:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/locales/zh_CN.yml b/config/locales/zh_CN.yml
index 3f271ecf7..87aca8ede 100644
--- a/config/locales/zh_CN.yml
+++ b/config/locales/zh_CN.yml
@@ -53,6 +53,8 @@ zh_CN:
invalid_message_type: '无效的消息类型。不允许操作'
slack:
invalid_channel_id: '无效的Slack频道。请重试'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: 请检查网络连接,IMAP地址,然后再试一次。
@@ -217,6 +219,9 @@ zh_CN:
linear:
name: 'Linear'
description: '直接从对话窗口在 Linear 中创建问题。或者,链接现有的 Linear 问题以简化问题跟踪过程。'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: '请为该收件箱连接一个助手以使用 Copilot'
copilot_limit: '您的 Copilot 积分已用完。您可以从计费部分购买更多积分。'
diff --git a/config/locales/zh_TW.yml b/config/locales/zh_TW.yml
index d8ddc1bf0..7a038bf5b 100644
--- a/config/locales/zh_TW.yml
+++ b/config/locales/zh_TW.yml
@@ -53,6 +53,8 @@ zh_TW:
invalid_message_type: 'Invalid message type. Action not permitted'
slack:
invalid_channel_id: 'Invalid slack channel. Please try again'
+ channel_service:
+ invalid_source_id: "This conversation may have originally belonged to a different contact but is now showing here due to a merge or update. You won't be able to continue this conversation. Please create a new conversation to proceed."
inboxes:
imap:
socket_error: Please check the network connection, IMAP address and try again.
@@ -217,6 +219,9 @@ zh_TW:
linear:
name: 'Linear'
description: 'Create issues in Linear directly from your conversation window. Alternatively, link existing Linear issues for a more streamlined and efficient issue tracking process.'
+ shopify:
+ name: 'Shopify'
+ description: 'Connect your Shopify store to access order details, customer information, and product data directly within your conversations and helps your support team provide faster, more contextual assistance to your customers.'
captain:
copilot_error: 'Please connect an assistant to this inbox to use Copilot'
copilot_limit: 'You are out of Copilot credits. You can buy more credits from the billing section.'
diff --git a/config/schedule.yml b/config/schedule.yml
index d8d23172b..f86015de6 100644
--- a/config/schedule.yml
+++ b/config/schedule.yml
@@ -32,3 +32,10 @@ remove_stale_redis_keys_job.rb:
cron: '30 22 * * *'
class: 'Internal::RemoveStaleRedisKeysJob'
queue: scheduled_jobs
+
+# executed daily at 2230 UTC
+# which is our lowest traffic time
+# process_stale_contacts_job:
+# cron: '30 22 * * *'
+# class: 'Internal::ProcessStaleContactsJob'
+# queue: scheduled_jobs
diff --git a/db/migrate/20250326034635_add_instagram_channel.rb b/db/migrate/20250326034635_add_instagram_channel.rb
new file mode 100644
index 000000000..6882caf6a
--- /dev/null
+++ b/db/migrate/20250326034635_add_instagram_channel.rb
@@ -0,0 +1,13 @@
+class AddInstagramChannel < ActiveRecord::Migration[7.0]
+ def change
+ create_table :channel_instagram do |t|
+ t.string :access_token, null: false
+ t.datetime :expires_at, null: false
+ t.integer :account_id, null: false
+ t.string :instagram_id, null: false
+ t.timestamps
+ end
+
+ add_index :channel_instagram, :instagram_id, unique: true
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 0818d1117..1f7217cd8 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[7.0].define(version: 2025_03_15_202035) do
+ActiveRecord::Schema[7.0].define(version: 2025_03_26_034635) do
# These extensions should be enabled to support this database
enable_extension "pg_stat_statements"
enable_extension "pg_trgm"
@@ -377,6 +377,16 @@ ActiveRecord::Schema[7.0].define(version: 2025_03_15_202035) do
t.index ["page_id"], name: "index_channel_facebook_pages_on_page_id"
end
+ create_table "channel_instagram", force: :cascade do |t|
+ t.string "access_token", null: false
+ t.datetime "expires_at", null: false
+ t.integer "account_id", null: false
+ t.string "instagram_id", null: false
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["instagram_id"], name: "index_channel_instagram_on_instagram_id", unique: true
+ end
+
create_table "channel_line", force: :cascade do |t|
t.integer "account_id", null: false
t.string "line_channel_id", null: false
diff --git a/enterprise/app/controllers/enterprise/api/v1/accounts_controller.rb b/enterprise/app/controllers/enterprise/api/v1/accounts_controller.rb
index f449529b8..86ec2fb55 100644
--- a/enterprise/app/controllers/enterprise/api/v1/accounts_controller.rb
+++ b/enterprise/app/controllers/enterprise/api/v1/accounts_controller.rb
@@ -13,24 +13,24 @@ class Enterprise::Api::V1::AccountsController < Api::BaseController
end
def limits
- limits = {
- 'conversation' => {},
- 'non_web_inboxes' => {},
- 'captain' => @account.usage_limits[:captain]
- }
-
- if default_plan?(@account)
- limits = {
- 'conversation' => {
- 'allowed' => 500,
- 'consumed' => conversations_this_month(@account)
- },
- 'non_web_inboxes' => {
- 'allowed' => 0,
- 'consumed' => non_web_inboxes(@account)
- }
- }
- end
+ limits = if default_plan?(@account)
+ {
+ 'conversation' => {
+ 'allowed' => 500,
+ 'consumed' => conversations_this_month(@account)
+ },
+ 'non_web_inboxes' => {
+ 'allowed' => 0,
+ 'consumed' => non_web_inboxes(@account)
+ },
+ 'agents' => {
+ 'allowed' => 2,
+ 'consumed' => agents(@account)
+ }
+ }
+ else
+ default_limits
+ end
# include id in response to ensure that the store can be updated on the frontend
render json: { id: @account.id, limits: limits }, status: :ok
@@ -49,6 +49,15 @@ class Enterprise::Api::V1::AccountsController < Api::BaseController
private
+ def default_limits
+ {
+ 'conversation' => {},
+ 'non_web_inboxes' => {},
+ 'agents' => {},
+ 'captain' => @account.usage_limits[:captain]
+ }
+ end
+
def fetch_account
@account = current_user.accounts.find(params[:id])
@current_account_user = @account.account_users.find_by(user_id: current_user.id)
diff --git a/package.json b/package.json
index 8264fb5e7..4c30829f7 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@chatwoot/chatwoot",
- "version": "4.0.3",
+ "version": "4.0.4",
"license": "MIT",
"scripts": {
"eslint": "eslint app/**/*.{js,vue}",
@@ -34,7 +34,7 @@
"@breezystack/lamejs": "^1.2.7",
"@chatwoot/ninja-keys": "1.2.3",
"@chatwoot/prosemirror-schema": "1.1.1-next",
- "@chatwoot/utils": "^0.0.41",
+ "@chatwoot/utils": "^0.0.42",
"@formkit/core": "^1.6.7",
"@formkit/vue": "^1.6.7",
"@hcaptcha/vue3-hcaptcha": "^1.3.0",
@@ -72,6 +72,7 @@
"highlight.js": "^11.10.0",
"idb": "^8.0.0",
"js-cookie": "^3.0.5",
+ "json-logic-js": "^2.0.5",
"lettersanitizer": "^1.0.6",
"libphonenumber-js": "^1.11.9",
"markdown-it": "^13.0.2",
@@ -137,7 +138,7 @@
"prosemirror-model": "^1.22.3",
"size-limit": "^8.2.4",
"tailwindcss": "^3.4.13",
- "vite": "^5.4.12",
+ "vite": "^5.4.15",
"vite-plugin-ruby": "^5.0.0",
"vitest": "3.0.5"
},
@@ -153,7 +154,7 @@
"pnpm": {
"overrides": {
"vite-node": "2.0.1",
- "vite": "5.4.12",
+ "vite": "5.4.15",
"vitest": "3.0.5"
}
},
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index fdeeac9fb..41ef0526a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -6,7 +6,7 @@ settings:
overrides:
vite-node: 2.0.1
- vite: 5.4.12
+ vite: 5.4.15
vitest: 3.0.5
importers:
@@ -23,8 +23,8 @@ importers:
specifier: 1.1.1-next
version: 1.1.1-next
'@chatwoot/utils':
- specifier: ^0.0.41
- version: 0.0.41
+ specifier: ^0.0.42
+ version: 0.0.42
'@formkit/core':
specifier: ^1.6.7
version: 1.6.7
@@ -72,7 +72,7 @@ importers:
version: 8.20.5(vue@3.5.12(typescript@5.6.2))
'@vitejs/plugin-vue':
specifier: ^5.1.4
- version: 5.1.4(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))
+ version: 5.1.4(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))
'@vue/compiler-sfc':
specifier: ^3.5.8
version: 3.5.8
@@ -136,6 +136,9 @@ importers:
js-cookie:
specifier: ^3.0.5
version: 3.0.5
+ json-logic-js:
+ specifier: ^2.0.5
+ version: 2.0.5
lettersanitizer:
specifier: ^1.0.6
version: 1.0.6
@@ -235,7 +238,7 @@ importers:
version: 1.8.1(tailwindcss@3.4.13)
'@histoire/plugin-vue':
specifier: 0.17.15
- version: 0.17.15(histoire@0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)))(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))
+ version: 0.17.15(histoire@0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)))(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))
'@iconify-json/logos':
specifier: ^1.2.3
version: 1.2.3
@@ -298,7 +301,7 @@ importers:
version: 6.0.0
histoire:
specifier: 0.17.15
- version: 0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
+ version: 0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
husky:
specifier: ^7.0.0
version: 7.0.4
@@ -327,11 +330,11 @@ importers:
specifier: ^3.4.13
version: 3.4.13
vite:
- specifier: 5.4.12
- version: 5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
+ specifier: 5.4.15
+ version: 5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
vite-plugin-ruby:
specifier: ^5.0.0
- version: 5.0.0(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
+ version: 5.0.0(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
vitest:
specifier: 3.0.5
version: 3.0.5(@types/node@22.7.0)(jsdom@24.1.3)(sass@1.79.3)(terser@5.33.0)
@@ -403,8 +406,8 @@ packages:
'@chatwoot/prosemirror-schema@1.1.1-next':
resolution: {integrity: sha512-/M2qZ+ZF7GlQNt1riwVP499fvp3hxSqd5iy8hxyF9pkj9qQ+OKYn5JK+v3qwwqQY3IxhmNOn1Lp6tm7vstrd9Q==}
- '@chatwoot/utils@0.0.41':
- resolution: {integrity: sha512-f0D+XArVYbc9m9M7KZpCaVJ+EUVzobX+D9P5Vt/h2jUipg706GoBhGwsP8kjfWhUdNdcS+H+OB4ZCKGF1NIkTQ==}
+ '@chatwoot/utils@0.0.42':
+ resolution: {integrity: sha512-TrEywcG1zjgBScVrQla7GMJwXsbLyc5u/verm/LbLrGxizU2NcNoJecRvJOUgL65kYVEtcO9//+gIDswwqnt6g==}
engines: {node: '>=10'}
'@codemirror/commands@6.7.0':
@@ -857,7 +860,7 @@ packages:
'@histoire/shared@0.17.17':
resolution: {integrity: sha512-ueGtURysonT0MujCObPCR57+mgZluMEXCrbc2FBgKAD/DoAt38tNwSGsmLldk2O6nTr7lr6ClbVSgWrLwgY6Xw==}
peerDependencies:
- vite: 5.4.12
+ vite: 5.4.15
'@histoire/vendors@0.17.17':
resolution: {integrity: sha512-QZvmffdoJlLuYftPIkOU5Q2FPAdG2JjMuQ5jF7NmEl0n1XnmbMqtRkdYTZ4eF6CO1KLZ0Zyf6gBQvoT1uWNcjA==}
@@ -1036,98 +1039,103 @@ packages:
'@rails/ujs@7.1.400':
resolution: {integrity: sha512-YwvXm3BR5tn+VCAKYGycLejMRVZE3Ionj5gFjEeGXCZnI0Rpi+7dKpmyu90kdUY7dRUFpHTdu9zZceEzFLl38w==}
- '@rollup/rollup-android-arm-eabi@4.31.0':
- resolution: {integrity: sha512-9NrR4033uCbUBRgvLcBrJofa2KY9DzxL2UKZ1/4xA/mnTNyhZCWBuD8X3tPm1n4KxcgaraOYgrFKSgwjASfmlA==}
+ '@rollup/rollup-android-arm-eabi@4.37.0':
+ resolution: {integrity: sha512-l7StVw6WAa8l3vA1ov80jyetOAEo1FtHvZDbzXDO/02Sq/QVvqlHkYoFwDJPIMj0GKiistsBudfx5tGFnwYWDQ==}
cpu: [arm]
os: [android]
- '@rollup/rollup-android-arm64@4.31.0':
- resolution: {integrity: sha512-iBbODqT86YBFHajxxF8ebj2hwKm1k8PTBQSojSt3d1FFt1gN+xf4CowE47iN0vOSdnd+5ierMHBbu/rHc7nq5g==}
+ '@rollup/rollup-android-arm64@4.37.0':
+ resolution: {integrity: sha512-6U3SlVyMxezt8Y+/iEBcbp945uZjJwjZimu76xoG7tO1av9VO691z8PkhzQ85ith2I8R2RddEPeSfcbyPfD4hA==}
cpu: [arm64]
os: [android]
- '@rollup/rollup-darwin-arm64@4.31.0':
- resolution: {integrity: sha512-WHIZfXgVBX30SWuTMhlHPXTyN20AXrLH4TEeH/D0Bolvx9PjgZnn4H677PlSGvU6MKNsjCQJYczkpvBbrBnG6g==}
+ '@rollup/rollup-darwin-arm64@4.37.0':
+ resolution: {integrity: sha512-+iTQ5YHuGmPt10NTzEyMPbayiNTcOZDWsbxZYR1ZnmLnZxG17ivrPSWFO9j6GalY0+gV3Jtwrrs12DBscxnlYA==}
cpu: [arm64]
os: [darwin]
- '@rollup/rollup-darwin-x64@4.31.0':
- resolution: {integrity: sha512-hrWL7uQacTEF8gdrQAqcDy9xllQ0w0zuL1wk1HV8wKGSGbKPVjVUv/DEwT2+Asabf8Dh/As+IvfdU+H8hhzrQQ==}
+ '@rollup/rollup-darwin-x64@4.37.0':
+ resolution: {integrity: sha512-m8W2UbxLDcmRKVjgl5J/k4B8d7qX2EcJve3Sut7YGrQoPtCIQGPH5AMzuFvYRWZi0FVS0zEY4c8uttPfX6bwYQ==}
cpu: [x64]
os: [darwin]
- '@rollup/rollup-freebsd-arm64@4.31.0':
- resolution: {integrity: sha512-S2oCsZ4hJviG1QjPY1h6sVJLBI6ekBeAEssYKad1soRFv3SocsQCzX6cwnk6fID6UQQACTjeIMB+hyYrFacRew==}
+ '@rollup/rollup-freebsd-arm64@4.37.0':
+ resolution: {integrity: sha512-FOMXGmH15OmtQWEt174v9P1JqqhlgYge/bUjIbiVD1nI1NeJ30HYT9SJlZMqdo1uQFyt9cz748F1BHghWaDnVA==}
cpu: [arm64]
os: [freebsd]
- '@rollup/rollup-freebsd-x64@4.31.0':
- resolution: {integrity: sha512-pCANqpynRS4Jirn4IKZH4tnm2+2CqCNLKD7gAdEjzdLGbH1iO0zouHz4mxqg0uEMpO030ejJ0aA6e1PJo2xrPA==}
+ '@rollup/rollup-freebsd-x64@4.37.0':
+ resolution: {integrity: sha512-SZMxNttjPKvV14Hjck5t70xS3l63sbVwl98g3FlVVx2YIDmfUIy29jQrsw06ewEYQ8lQSuY9mpAPlmgRD2iSsA==}
cpu: [x64]
os: [freebsd]
- '@rollup/rollup-linux-arm-gnueabihf@4.31.0':
- resolution: {integrity: sha512-0O8ViX+QcBd3ZmGlcFTnYXZKGbFu09EhgD27tgTdGnkcYXLat4KIsBBQeKLR2xZDCXdIBAlWLkiXE1+rJpCxFw==}
+ '@rollup/rollup-linux-arm-gnueabihf@4.37.0':
+ resolution: {integrity: sha512-hhAALKJPidCwZcj+g+iN+38SIOkhK2a9bqtJR+EtyxrKKSt1ynCBeqrQy31z0oWU6thRZzdx53hVgEbRkuI19w==}
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm-musleabihf@4.31.0':
- resolution: {integrity: sha512-w5IzG0wTVv7B0/SwDnMYmbr2uERQp999q8FMkKG1I+j8hpPX2BYFjWe69xbhbP6J9h2gId/7ogesl9hwblFwwg==}
+ '@rollup/rollup-linux-arm-musleabihf@4.37.0':
+ resolution: {integrity: sha512-jUb/kmn/Gd8epbHKEqkRAxq5c2EwRt0DqhSGWjPFxLeFvldFdHQs/n8lQ9x85oAeVb6bHcS8irhTJX2FCOd8Ag==}
cpu: [arm]
os: [linux]
- '@rollup/rollup-linux-arm64-gnu@4.31.0':
- resolution: {integrity: sha512-JyFFshbN5xwy6fulZ8B/8qOqENRmDdEkcIMF0Zz+RsfamEW+Zabl5jAb0IozP/8UKnJ7g2FtZZPEUIAlUSX8cA==}
+ '@rollup/rollup-linux-arm64-gnu@4.37.0':
+ resolution: {integrity: sha512-oNrJxcQT9IcbcmKlkF+Yz2tmOxZgG9D9GRq+1OE6XCQwCVwxixYAa38Z8qqPzQvzt1FCfmrHX03E0pWoXm1DqA==}
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-arm64-musl@4.31.0':
- resolution: {integrity: sha512-kpQXQ0UPFeMPmPYksiBL9WS/BDiQEjRGMfklVIsA0Sng347H8W2iexch+IEwaR7OVSKtr2ZFxggt11zVIlZ25g==}
+ '@rollup/rollup-linux-arm64-musl@4.37.0':
+ resolution: {integrity: sha512-pfxLBMls+28Ey2enpX3JvjEjaJMBX5XlPCZNGxj4kdJyHduPBXtxYeb8alo0a7bqOoWZW2uKynhHxF/MWoHaGQ==}
cpu: [arm64]
os: [linux]
- '@rollup/rollup-linux-loongarch64-gnu@4.31.0':
- resolution: {integrity: sha512-pMlxLjt60iQTzt9iBb3jZphFIl55a70wexvo8p+vVFK+7ifTRookdoXX3bOsRdmfD+OKnMozKO6XM4zR0sHRrQ==}
+ '@rollup/rollup-linux-loongarch64-gnu@4.37.0':
+ resolution: {integrity: sha512-yCE0NnutTC/7IGUq/PUHmoeZbIwq3KRh02e9SfFh7Vmc1Z7atuJRYWhRME5fKgT8aS20mwi1RyChA23qSyRGpA==}
cpu: [loong64]
os: [linux]
- '@rollup/rollup-linux-powerpc64le-gnu@4.31.0':
- resolution: {integrity: sha512-D7TXT7I/uKEuWiRkEFbed1UUYZwcJDU4vZQdPTcepK7ecPhzKOYk4Er2YR4uHKme4qDeIh6N3XrLfpuM7vzRWQ==}
+ '@rollup/rollup-linux-powerpc64le-gnu@4.37.0':
+ resolution: {integrity: sha512-NxcICptHk06E2Lh3a4Pu+2PEdZ6ahNHuK7o6Np9zcWkrBMuv21j10SQDJW3C9Yf/A/P7cutWoC/DptNLVsZ0VQ==}
cpu: [ppc64]
os: [linux]
- '@rollup/rollup-linux-riscv64-gnu@4.31.0':
- resolution: {integrity: sha512-wal2Tc8O5lMBtoePLBYRKj2CImUCJ4UNGJlLwspx7QApYny7K1cUYlzQ/4IGQBLmm+y0RS7dwc3TDO/pmcneTw==}
+ '@rollup/rollup-linux-riscv64-gnu@4.37.0':
+ resolution: {integrity: sha512-PpWwHMPCVpFZLTfLq7EWJWvrmEuLdGn1GMYcm5MV7PaRgwCEYJAwiN94uBuZev0/J/hFIIJCsYw4nLmXA9J7Pw==}
cpu: [riscv64]
os: [linux]
- '@rollup/rollup-linux-s390x-gnu@4.31.0':
- resolution: {integrity: sha512-O1o5EUI0+RRMkK9wiTVpk2tyzXdXefHtRTIjBbmFREmNMy7pFeYXCFGbhKFwISA3UOExlo5GGUuuj3oMKdK6JQ==}
+ '@rollup/rollup-linux-riscv64-musl@4.37.0':
+ resolution: {integrity: sha512-DTNwl6a3CfhGTAOYZ4KtYbdS8b+275LSLqJVJIrPa5/JuIufWWZ/QFvkxp52gpmguN95eujrM68ZG+zVxa8zHA==}
+ cpu: [riscv64]
+ os: [linux]
+
+ '@rollup/rollup-linux-s390x-gnu@4.37.0':
+ resolution: {integrity: sha512-hZDDU5fgWvDdHFuExN1gBOhCuzo/8TMpidfOR+1cPZJflcEzXdCy1LjnklQdW8/Et9sryOPJAKAQRw8Jq7Tg+A==}
cpu: [s390x]
os: [linux]
- '@rollup/rollup-linux-x64-gnu@4.31.0':
- resolution: {integrity: sha512-zSoHl356vKnNxwOWnLd60ixHNPRBglxpv2g7q0Cd3Pmr561gf0HiAcUBRL3S1vPqRC17Zo2CX/9cPkqTIiai1g==}
+ '@rollup/rollup-linux-x64-gnu@4.37.0':
+ resolution: {integrity: sha512-pKivGpgJM5g8dwj0ywBwe/HeVAUSuVVJhUTa/URXjxvoyTT/AxsLTAbkHkDHG7qQxLoW2s3apEIl26uUe08LVQ==}
cpu: [x64]
os: [linux]
- '@rollup/rollup-linux-x64-musl@4.31.0':
- resolution: {integrity: sha512-ypB/HMtcSGhKUQNiFwqgdclWNRrAYDH8iMYH4etw/ZlGwiTVxBz2tDrGRrPlfZu6QjXwtd+C3Zib5pFqID97ZA==}
+ '@rollup/rollup-linux-x64-musl@4.37.0':
+ resolution: {integrity: sha512-E2lPrLKE8sQbY/2bEkVTGDEk4/49UYRVWgj90MY8yPjpnGBQ+Xi1Qnr7b7UIWw1NOggdFQFOLZ8+5CzCiz143w==}
cpu: [x64]
os: [linux]
- '@rollup/rollup-win32-arm64-msvc@4.31.0':
- resolution: {integrity: sha512-JuhN2xdI/m8Hr+aVO3vspO7OQfUFO6bKLIRTAy0U15vmWjnZDLrEgCZ2s6+scAYaQVpYSh9tZtRijApw9IXyMw==}
+ '@rollup/rollup-win32-arm64-msvc@4.37.0':
+ resolution: {integrity: sha512-Jm7biMazjNzTU4PrQtr7VS8ibeys9Pn29/1bm4ph7CP2kf21950LgN+BaE2mJ1QujnvOc6p54eWWiVvn05SOBg==}
cpu: [arm64]
os: [win32]
- '@rollup/rollup-win32-ia32-msvc@4.31.0':
- resolution: {integrity: sha512-U1xZZXYkvdf5MIWmftU8wrM5PPXzyaY1nGCI4KI4BFfoZxHamsIe+BtnPLIvvPykvQWlVbqUXdLa4aJUuilwLQ==}
+ '@rollup/rollup-win32-ia32-msvc@4.37.0':
+ resolution: {integrity: sha512-e3/1SFm1OjefWICB2Ucstg2dxYDkDTZGDYgwufcbsxTHyqQps1UQf33dFEChBNmeSsTOyrjw2JJq0zbG5GF6RA==}
cpu: [ia32]
os: [win32]
- '@rollup/rollup-win32-x64-msvc@4.31.0':
- resolution: {integrity: sha512-ul8rnCsUumNln5YWwz0ted2ZHFhzhRRnkpBZ+YRuHoRAlUji9KChpOUOndY7uykrPEPXVbHLlsdo6v5yXo/TXw==}
+ '@rollup/rollup-win32-x64-msvc@4.37.0':
+ resolution: {integrity: sha512-LWbXUBwn/bcLx2sSsqy7pK5o+Nr+VCoRoAohfJ5C/aBio9nfJmGQqHAhU6pwxV/RmyTk5AqdySma7uwWGlmeuA==}
cpu: [x64]
os: [win32]
@@ -1741,6 +1749,9 @@ packages:
'@types/estree@1.0.6':
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
+ '@types/estree@1.0.7':
+ resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
+
'@types/flexsearch@0.7.6':
resolution: {integrity: sha512-H5IXcRn96/gaDmo+rDl2aJuIJsob8dgOXDqf8K0t8rWZd1AFNaaspmRsElESiU+EWE33qfbFPgI0OC/B1g9FCA==}
@@ -1792,7 +1803,7 @@ packages:
resolution: {integrity: sha512-N2XSI2n3sQqp5w7Y/AN/L2XDjBIRGqXko+eDp42sydYSBeJuSm5a1sLf8zakmo8u7tA8NmBgoDLA1HeOESjp9A==}
engines: {node: ^18.0.0 || >=20.0.0}
peerDependencies:
- vite: 5.4.12
+ vite: 5.4.15
vue: ^3.2.25
'@vitest/coverage-v8@3.0.5':
@@ -1811,7 +1822,7 @@ packages:
resolution: {integrity: sha512-CLPNBFBIE7x6aEGbIjaQAX03ZZlBMaWwAjBdMkIf/cAn6xzLTiM3zYqO/WAbieEjsAZir6tO71mzeHZoodThvw==}
peerDependencies:
msw: ^2.4.9
- vite: 5.4.12
+ vite: 5.4.15
peerDependenciesMeta:
msw:
optional: true
@@ -3092,7 +3103,7 @@ packages:
resolution: {integrity: sha512-DiRMSIgj340z+zikqf0f3Pj0CTv2/xtdBMBIAO1EARat+QXxMwumbfK41Gi7f9IIBr+UVmomNcwFxVY2EM/vrw==}
hasBin: true
peerDependencies:
- vite: 5.4.12
+ vite: 5.4.15
hotkeys-js@3.8.7:
resolution: {integrity: sha512-ckAx3EkUr5XjDwjEHDorHxRO2Kb7z6Z2Sxul4MbBkN8Nho7XDslQsgMJT+CiJ5Z4TgRxxvKHEpuLE3imzqy4Lg==}
@@ -3398,6 +3409,9 @@ packages:
json-buffer@3.0.1:
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
+ json-logic-js@2.0.5:
+ resolution: {integrity: sha512-rTT2+lqcuUmj4DgWfmzupZqQDA64AdmYqizzMPWj3DxGdfFNsxPpcNVSaTj4l8W2tG/+hg7/mQhxjU3aPacO6g==}
+
json-schema-traverse@0.4.1:
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
@@ -4173,8 +4187,8 @@ packages:
resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==}
engines: {node: ^10 || ^12 || >=14}
- postcss@8.5.1:
- resolution: {integrity: sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==}
+ postcss@8.5.3:
+ resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==}
engines: {node: ^10 || ^12 || >=14}
prelude-ls@1.2.1:
@@ -4333,8 +4347,8 @@ packages:
deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
- rollup@4.31.0:
- resolution: {integrity: sha512-9cCE8P4rZLx9+PjoyqHLs31V9a9Vpvfo4qNcs6JCiGWYhw2gijSetFbH6SSy1whnkgcefnUwr8sad7tgqsGvnw==}
+ rollup@4.37.0:
+ resolution: {integrity: sha512-iAtQy/L4QFU+rTJ1YUjXqJOJzuwEghqWzCEYD2FEghT7Gsy1VdABntrO4CLopA5IkflTyqNiLNwPcOJ3S7UKLg==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
@@ -4852,10 +4866,10 @@ packages:
vite-plugin-ruby@5.0.0:
resolution: {integrity: sha512-c8PjTp21Ah/ttgnNUyu0qvCXZI08Jr9I24oUKg3TRIRhF5GcOZ++6wtlTCrNFd9COEQbpXHxlRIXd/MEg0iZJw==}
peerDependencies:
- vite: 5.4.12
+ vite: 5.4.15
- vite@5.4.12:
- resolution: {integrity: sha512-KwUaKB27TvWwDJr1GjjWthLMATbGEbeWYZIbGZ5qFIsgPP3vWzLu4cVooqhm5/Z2SPDUMjyPVjTztm5tYKwQxA==}
+ vite@5.4.15:
+ resolution: {integrity: sha512-6ANcZRivqL/4WtwPGTKNaosuNJr5tWiftOC7liM7G9+rMb8+oeJeyzymDu4rTN93seySBmbjSfsS3Vzr19KNtA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
@@ -5244,7 +5258,7 @@ snapshots:
prosemirror-utils: 1.2.2(prosemirror-model@1.22.3)(prosemirror-state@1.4.3)
prosemirror-view: 1.34.1
- '@chatwoot/utils@0.0.41':
+ '@chatwoot/utils@0.0.42':
dependencies:
date-fns: 2.30.0
@@ -5661,10 +5675,10 @@ snapshots:
highlight.js: 11.10.0
vue: 3.5.12(typescript@5.6.2)
- '@histoire/app@0.17.17(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))':
+ '@histoire/app@0.17.17(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))':
dependencies:
- '@histoire/controls': 0.17.17(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
- '@histoire/shared': 0.17.17(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
+ '@histoire/controls': 0.17.17(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
+ '@histoire/shared': 0.17.17(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
'@histoire/vendors': 0.17.17
'@types/flexsearch': 0.7.6
flexsearch: 0.7.21
@@ -5672,7 +5686,7 @@ snapshots:
transitivePeerDependencies:
- vite
- '@histoire/controls@0.17.17(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))':
+ '@histoire/controls@0.17.17(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))':
dependencies:
'@codemirror/commands': 6.7.0
'@codemirror/lang-json': 6.0.1
@@ -5681,26 +5695,26 @@ snapshots:
'@codemirror/state': 6.4.1
'@codemirror/theme-one-dark': 6.1.2
'@codemirror/view': 6.34.1
- '@histoire/shared': 0.17.17(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
+ '@histoire/shared': 0.17.17(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
'@histoire/vendors': 0.17.17
transitivePeerDependencies:
- vite
- '@histoire/plugin-vue@0.17.15(histoire@0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)))(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))':
+ '@histoire/plugin-vue@0.17.15(histoire@0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)))(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))':
dependencies:
- '@histoire/controls': 0.17.17(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
- '@histoire/shared': 0.17.17(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
+ '@histoire/controls': 0.17.17(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
+ '@histoire/shared': 0.17.17(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
'@histoire/vendors': 0.17.17
change-case: 4.1.2
globby: 13.2.2
- histoire: 0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
+ histoire: 0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
launch-editor: 2.9.1
pathe: 1.1.2
vue: 3.5.12(typescript@5.6.2)
transitivePeerDependencies:
- vite
- '@histoire/shared@0.17.17(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))':
+ '@histoire/shared@0.17.17(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))':
dependencies:
'@histoire/vendors': 0.17.17
'@types/fs-extra': 9.0.13
@@ -5708,7 +5722,7 @@ snapshots:
chokidar: 3.6.0
pathe: 1.1.2
picocolors: 1.1.0
- vite: 5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
+ vite: 5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
'@histoire/vendors@0.17.17': {}
@@ -5933,61 +5947,64 @@ snapshots:
'@rails/ujs@7.1.400': {}
- '@rollup/rollup-android-arm-eabi@4.31.0':
+ '@rollup/rollup-android-arm-eabi@4.37.0':
optional: true
- '@rollup/rollup-android-arm64@4.31.0':
+ '@rollup/rollup-android-arm64@4.37.0':
optional: true
- '@rollup/rollup-darwin-arm64@4.31.0':
+ '@rollup/rollup-darwin-arm64@4.37.0':
optional: true
- '@rollup/rollup-darwin-x64@4.31.0':
+ '@rollup/rollup-darwin-x64@4.37.0':
optional: true
- '@rollup/rollup-freebsd-arm64@4.31.0':
+ '@rollup/rollup-freebsd-arm64@4.37.0':
optional: true
- '@rollup/rollup-freebsd-x64@4.31.0':
+ '@rollup/rollup-freebsd-x64@4.37.0':
optional: true
- '@rollup/rollup-linux-arm-gnueabihf@4.31.0':
+ '@rollup/rollup-linux-arm-gnueabihf@4.37.0':
optional: true
- '@rollup/rollup-linux-arm-musleabihf@4.31.0':
+ '@rollup/rollup-linux-arm-musleabihf@4.37.0':
optional: true
- '@rollup/rollup-linux-arm64-gnu@4.31.0':
+ '@rollup/rollup-linux-arm64-gnu@4.37.0':
optional: true
- '@rollup/rollup-linux-arm64-musl@4.31.0':
+ '@rollup/rollup-linux-arm64-musl@4.37.0':
optional: true
- '@rollup/rollup-linux-loongarch64-gnu@4.31.0':
+ '@rollup/rollup-linux-loongarch64-gnu@4.37.0':
optional: true
- '@rollup/rollup-linux-powerpc64le-gnu@4.31.0':
+ '@rollup/rollup-linux-powerpc64le-gnu@4.37.0':
optional: true
- '@rollup/rollup-linux-riscv64-gnu@4.31.0':
+ '@rollup/rollup-linux-riscv64-gnu@4.37.0':
optional: true
- '@rollup/rollup-linux-s390x-gnu@4.31.0':
+ '@rollup/rollup-linux-riscv64-musl@4.37.0':
optional: true
- '@rollup/rollup-linux-x64-gnu@4.31.0':
+ '@rollup/rollup-linux-s390x-gnu@4.37.0':
optional: true
- '@rollup/rollup-linux-x64-musl@4.31.0':
+ '@rollup/rollup-linux-x64-gnu@4.37.0':
optional: true
- '@rollup/rollup-win32-arm64-msvc@4.31.0':
+ '@rollup/rollup-linux-x64-musl@4.37.0':
optional: true
- '@rollup/rollup-win32-ia32-msvc@4.31.0':
+ '@rollup/rollup-win32-arm64-msvc@4.37.0':
optional: true
- '@rollup/rollup-win32-x64-msvc@4.31.0':
+ '@rollup/rollup-win32-ia32-msvc@4.37.0':
+ optional: true
+
+ '@rollup/rollup-win32-x64-msvc@4.37.0':
optional: true
'@rtsao/scc@1.1.0': {}
@@ -6732,6 +6749,8 @@ snapshots:
'@types/estree@1.0.6': {}
+ '@types/estree@1.0.7': {}
+
'@types/flexsearch@0.7.6': {}
'@types/fs-extra@9.0.13':
@@ -6788,9 +6807,9 @@ snapshots:
global: 4.4.0
is-function: 1.0.2
- '@vitejs/plugin-vue@5.1.4(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))':
+ '@vitejs/plugin-vue@5.1.4(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))':
dependencies:
- vite: 5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
+ vite: 5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
vue: 3.5.12(typescript@5.6.2)
'@vitest/coverage-v8@3.0.5(vitest@3.0.5(@types/node@22.7.0)(jsdom@24.1.3)(sass@1.79.3)(terser@5.33.0))':
@@ -6818,13 +6837,13 @@ snapshots:
chai: 5.1.2
tinyrainbow: 2.0.0
- '@vitest/mocker@3.0.5(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))':
+ '@vitest/mocker@3.0.5(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))':
dependencies:
'@vitest/spy': 3.0.5
estree-walker: 3.0.3
magic-string: 0.30.17
optionalDependencies:
- vite: 5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
+ vite: 5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
'@vitest/pretty-format@3.0.5':
dependencies:
@@ -6899,7 +6918,7 @@ snapshots:
'@vue/shared': 3.5.12
estree-walker: 2.0.2
magic-string: 0.30.17
- postcss: 8.5.1
+ postcss: 8.5.3
source-map-js: 1.2.1
'@vue/compiler-sfc@3.5.13':
@@ -6911,7 +6930,7 @@ snapshots:
'@vue/shared': 3.5.13
estree-walker: 2.0.2
magic-string: 0.30.17
- postcss: 8.5.1
+ postcss: 8.5.3
source-map-js: 1.2.1
'@vue/compiler-sfc@3.5.8':
@@ -8062,7 +8081,7 @@ snapshots:
estree-walker@3.0.3:
dependencies:
- '@types/estree': 1.0.6
+ '@types/estree': 1.0.7
esutils@2.0.3: {}
@@ -8379,12 +8398,12 @@ snapshots:
highlight.js@11.10.0: {}
- histoire@0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)):
+ histoire@0.17.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)):
dependencies:
'@akryum/tinypool': 0.3.1
- '@histoire/app': 0.17.17(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
- '@histoire/controls': 0.17.17(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
- '@histoire/shared': 0.17.17(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
+ '@histoire/app': 0.17.17(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
+ '@histoire/controls': 0.17.17(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
+ '@histoire/shared': 0.17.17(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
'@histoire/vendors': 0.17.17
'@types/flexsearch': 0.7.6
'@types/markdown-it': 12.2.3
@@ -8411,7 +8430,7 @@ snapshots:
sade: 1.8.1
shiki-es: 0.2.0
sirv: 2.0.4
- vite: 5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
+ vite: 5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
vite-node: 2.0.1(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
transitivePeerDependencies:
- '@types/node'
@@ -8761,6 +8780,8 @@ snapshots:
json-buffer@3.0.1: {}
+ json-logic-js@2.0.5: {}
+
json-schema-traverse@0.4.1: {}
json-schema-traverse@1.0.0: {}
@@ -9571,7 +9592,7 @@ snapshots:
picocolors: 1.1.0
source-map-js: 1.2.1
- postcss@8.5.1:
+ postcss@8.5.3:
dependencies:
nanoid: 3.3.8
picocolors: 1.1.1
@@ -9750,29 +9771,30 @@ snapshots:
dependencies:
glob: 7.2.3
- rollup@4.31.0:
+ rollup@4.37.0:
dependencies:
'@types/estree': 1.0.6
optionalDependencies:
- '@rollup/rollup-android-arm-eabi': 4.31.0
- '@rollup/rollup-android-arm64': 4.31.0
- '@rollup/rollup-darwin-arm64': 4.31.0
- '@rollup/rollup-darwin-x64': 4.31.0
- '@rollup/rollup-freebsd-arm64': 4.31.0
- '@rollup/rollup-freebsd-x64': 4.31.0
- '@rollup/rollup-linux-arm-gnueabihf': 4.31.0
- '@rollup/rollup-linux-arm-musleabihf': 4.31.0
- '@rollup/rollup-linux-arm64-gnu': 4.31.0
- '@rollup/rollup-linux-arm64-musl': 4.31.0
- '@rollup/rollup-linux-loongarch64-gnu': 4.31.0
- '@rollup/rollup-linux-powerpc64le-gnu': 4.31.0
- '@rollup/rollup-linux-riscv64-gnu': 4.31.0
- '@rollup/rollup-linux-s390x-gnu': 4.31.0
- '@rollup/rollup-linux-x64-gnu': 4.31.0
- '@rollup/rollup-linux-x64-musl': 4.31.0
- '@rollup/rollup-win32-arm64-msvc': 4.31.0
- '@rollup/rollup-win32-ia32-msvc': 4.31.0
- '@rollup/rollup-win32-x64-msvc': 4.31.0
+ '@rollup/rollup-android-arm-eabi': 4.37.0
+ '@rollup/rollup-android-arm64': 4.37.0
+ '@rollup/rollup-darwin-arm64': 4.37.0
+ '@rollup/rollup-darwin-x64': 4.37.0
+ '@rollup/rollup-freebsd-arm64': 4.37.0
+ '@rollup/rollup-freebsd-x64': 4.37.0
+ '@rollup/rollup-linux-arm-gnueabihf': 4.37.0
+ '@rollup/rollup-linux-arm-musleabihf': 4.37.0
+ '@rollup/rollup-linux-arm64-gnu': 4.37.0
+ '@rollup/rollup-linux-arm64-musl': 4.37.0
+ '@rollup/rollup-linux-loongarch64-gnu': 4.37.0
+ '@rollup/rollup-linux-powerpc64le-gnu': 4.37.0
+ '@rollup/rollup-linux-riscv64-gnu': 4.37.0
+ '@rollup/rollup-linux-riscv64-musl': 4.37.0
+ '@rollup/rollup-linux-s390x-gnu': 4.37.0
+ '@rollup/rollup-linux-x64-gnu': 4.37.0
+ '@rollup/rollup-linux-x64-musl': 4.37.0
+ '@rollup/rollup-win32-arm64-msvc': 4.37.0
+ '@rollup/rollup-win32-ia32-msvc': 4.37.0
+ '@rollup/rollup-win32-x64-msvc': 4.37.0
fsevents: 2.3.3
rope-sequence@1.3.2: {}
@@ -10361,7 +10383,7 @@ snapshots:
debug: 4.4.0
pathe: 1.1.2
picocolors: 1.1.1
- vite: 5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
+ vite: 5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
transitivePeerDependencies:
- '@types/node'
- less
@@ -10373,19 +10395,19 @@ snapshots:
- supports-color
- terser
- vite-plugin-ruby@5.0.0(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)):
+ vite-plugin-ruby@5.0.0(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)):
dependencies:
debug: 4.3.5
fast-glob: 3.3.2
- vite: 5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
+ vite: 5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
transitivePeerDependencies:
- supports-color
- vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0):
+ vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0):
dependencies:
esbuild: 0.21.5
- postcss: 8.5.1
- rollup: 4.31.0
+ postcss: 8.5.3
+ rollup: 4.37.0
optionalDependencies:
'@types/node': 22.7.0
fsevents: 2.3.3
@@ -10395,7 +10417,7 @@ snapshots:
vitest@3.0.5(@types/node@22.7.0)(jsdom@24.1.3)(sass@1.79.3)(terser@5.33.0):
dependencies:
'@vitest/expect': 3.0.5
- '@vitest/mocker': 3.0.5(vite@5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
+ '@vitest/mocker': 3.0.5(vite@5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
'@vitest/pretty-format': 3.0.5
'@vitest/runner': 3.0.5
'@vitest/snapshot': 3.0.5
@@ -10411,7 +10433,7 @@ snapshots:
tinyexec: 0.3.2
tinypool: 1.0.2
tinyrainbow: 2.0.0
- vite: 5.4.12(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
+ vite: 5.4.15(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
vite-node: 2.0.1(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
why-is-node-running: 2.3.0
optionalDependencies:
diff --git a/spec/builders/contact_inbox_builder_spec.rb b/spec/builders/contact_inbox_builder_spec.rb
index 1dda58063..f0e3deb31 100644
--- a/spec/builders/contact_inbox_builder_spec.rb
+++ b/spec/builders/contact_inbox_builder_spec.rb
@@ -330,5 +330,42 @@ describe ContactInboxBuilder do
expect(contact_inbox.source_id).not_to be_nil
end
end
+
+ context 'when there is a race condition' do
+ let(:account) { create(:account) }
+ let(:contact) { create(:contact, account: account) }
+ let(:contact2) { create(:contact, account: account) }
+ let(:channel) { create(:channel_email, account: account) }
+ let(:channel_api) { create(:channel_api, account: account) }
+ let(:source_id) { 'source_123' }
+
+ it 'handles RecordNotUnique error by updating source_id and retrying' do
+ existing_contact_inbox = create(:contact_inbox, contact: contact2, inbox: channel.inbox, source_id: source_id)
+
+ described_class.new(
+ contact: contact,
+ inbox: channel.inbox,
+ source_id: source_id
+ ).perform
+
+ expect(ContactInbox.last.source_id).to eq(source_id)
+ expect(ContactInbox.last.contact_id).to eq(contact.id)
+ expect(ContactInbox.last.inbox_id).to eq(channel.inbox.id)
+ expect(existing_contact_inbox.reload.source_id).to include(source_id)
+ expect(existing_contact_inbox.reload.source_id).not_to eq(source_id)
+ end
+
+ it 'does not update source_id for channels other than email or phone number' do
+ create(:contact_inbox, contact: contact2, inbox: channel_api.inbox, source_id: source_id)
+
+ expect do
+ described_class.new(
+ contact: contact,
+ inbox: channel_api.inbox,
+ source_id: source_id
+ ).perform
+ end.to raise_error(ActiveRecord::RecordNotUnique)
+ end
+ end
end
end
diff --git a/spec/enterprise/controllers/enterprise/api/v1/accounts_controller_spec.rb b/spec/enterprise/controllers/enterprise/api/v1/accounts_controller_spec.rb
index 6373bc842..ac26dc525 100644
--- a/spec/enterprise/controllers/enterprise/api/v1/accounts_controller_spec.rb
+++ b/spec/enterprise/controllers/enterprise/api/v1/accounts_controller_spec.rb
@@ -2,8 +2,8 @@ require 'rails_helper'
RSpec.describe 'Enterprise Billing APIs', type: :request do
let(:account) { create(:account) }
- let(:admin) { create(:user, account: account, role: :administrator) }
- let(:agent) { create(:user, account: account, role: :agent) }
+ let!(:admin) { create(:user, account: account, role: :administrator) }
+ let!(:agent) { create(:user, account: account, role: :agent) }
describe 'POST /enterprise/api/v1/accounts/{account.id}/subscription' do
context 'when it is an unauthenticated user' do
@@ -121,13 +121,36 @@ RSpec.describe 'Enterprise Billing APIs', type: :request do
end
context 'when it is an authenticated user' do
+ before do
+ InstallationConfig.where(name: 'DEPLOYMENT_ENV').first_or_create(value: 'cloud')
+ InstallationConfig.where(name: 'CHATWOOT_CLOUD_PLANS').first_or_create(value: [{ 'name': 'Hacker' }])
+ end
+
context 'when it is an agent' do
it 'returns unauthorized' do
get "/enterprise/api/v1/accounts/#{account.id}/limits",
headers: agent.create_new_auth_token,
as: :json
- expect(response).to have_http_status(:unauthorized)
+ expect(response).to have_http_status(:success)
+ json_response = JSON.parse(response.body)
+ expect(json_response['id']).to eq(account.id)
+ expect(json_response['limits']).to eq(
+ {
+ 'conversation' => {
+ 'allowed' => 500,
+ 'consumed' => 0
+ },
+ 'non_web_inboxes' => {
+ 'allowed' => 0,
+ 'consumed' => 0
+ },
+ 'agents' => {
+ 'allowed' => 2,
+ 'consumed' => 2
+ }
+ }
+ )
end
end
@@ -155,6 +178,10 @@ RSpec.describe 'Enterprise Billing APIs', type: :request do
'non_web_inboxes' => {
'allowed' => 0,
'consumed' => 1
+ },
+ 'agents' => {
+ 'allowed' => 2,
+ 'consumed' => 2
}
}
}
@@ -172,18 +199,11 @@ RSpec.describe 'Enterprise Billing APIs', type: :request do
expected_response = {
'id' => account.id,
'limits' => {
+ 'agents' => {},
'conversation' => {},
'captain' => {
- 'documents' => {
- 'consumed' => 0,
- 'current_available' => ChatwootApp.max_limit,
- 'total_count' => ChatwootApp.max_limit
- },
- 'responses' => {
- 'consumed' => 0,
- 'current_available' => ChatwootApp.max_limit,
- 'total_count' => ChatwootApp.max_limit
- }
+ 'documents' => { 'consumed' => 0, 'current_available' => ChatwootApp.max_limit, 'total_count' => ChatwootApp.max_limit },
+ 'responses' => { 'consumed' => 0, 'current_available' => ChatwootApp.max_limit, 'total_count' => ChatwootApp.max_limit }
},
'non_web_inboxes' => {}
}
@@ -208,6 +228,10 @@ RSpec.describe 'Enterprise Billing APIs', type: :request do
'non_web_inboxes' => {
'allowed' => 0,
'consumed' => 1
+ },
+ 'agents' => {
+ 'allowed' => 2,
+ 'consumed' => 2
}
}
}
diff --git a/spec/factories/channel/channel_instagram.rb b/spec/factories/channel/channel_instagram.rb
new file mode 100644
index 000000000..9a0d33bb5
--- /dev/null
+++ b/spec/factories/channel/channel_instagram.rb
@@ -0,0 +1,13 @@
+FactoryBot.define do
+ factory :channel_instagram, class: 'Channel::Instagram' do
+ account
+ access_token { SecureRandom.hex(32) }
+ instagram_id { SecureRandom.hex(16) }
+ expires_at { 60.days.from_now }
+ updated_at { 25.hours.ago }
+
+ after(:create) do |channel|
+ create(:inbox, channel: channel, account: channel.account)
+ end
+ end
+end
diff --git a/spec/factories/channel/channel_whatsapp.rb b/spec/factories/channel/channel_whatsapp.rb
index ccbbf7172..d437ed346 100644
--- a/spec/factories/channel/channel_whatsapp.rb
+++ b/spec/factories/channel/channel_whatsapp.rb
@@ -30,7 +30,39 @@ FactoryBot.define do
'components' =>
[{ 'text' => 'Your package has been shipped. It will be delivered in {{1}} business days.', 'type' => 'BODY' },
{ 'text' => 'This message is from an unverified business.', 'type' => 'FOOTER' }],
- 'rejected_reason' => 'NONE' }]
+ 'rejected_reason' => 'NONE' },
+ {
+ 'name' => 'ticket_status_updated',
+ 'status' => 'APPROVED',
+ 'category' => 'UTILITY',
+ 'language' => 'en',
+ 'components' => [
+ { 'text' => "Hello {{name}}, Your support ticket with ID: \#{{ticket_id}} has been updated by the support agent.",
+ 'type' => 'BODY',
+ 'example' => { 'body_text_named_params' => [
+ { 'example' => 'John', 'param_name' => 'name' },
+ { 'example' => '2332', 'param_name' => 'ticket_id' }
+ ] } }
+ ],
+ 'sub_category' => 'CUSTOM',
+ 'parameter_format' => 'NAMED'
+ },
+ {
+ 'name' => 'ticket_status_updated',
+ 'status' => 'APPROVED',
+ 'category' => 'UTILITY',
+ 'language' => 'en_US',
+ 'components' => [
+ { 'text' => "Hello {{last_name}}, Your support ticket with ID: \#{{ticket_id}} has been updated by the support agent.",
+ 'type' => 'BODY',
+ 'example' => { 'body_text_named_params' => [
+ { 'example' => 'Dale', 'param_name' => 'last_name' },
+ { 'example' => '2332', 'param_name' => 'ticket_id' }
+ ] } }
+ ],
+ 'sub_category' => 'CUSTOM',
+ 'parameter_format' => 'NAMED'
+ }]
end
message_templates_last_updated { Time.now.utc }
diff --git a/spec/finders/conversation_finder_spec.rb b/spec/finders/conversation_finder_spec.rb
index 4d6e9ed40..0174ccfb0 100644
--- a/spec/finders/conversation_finder_spec.rb
+++ b/spec/finders/conversation_finder_spec.rb
@@ -57,6 +57,16 @@ describe ConversationFinder do
expect(result[:conversations].map(&:id)).not_to include(restricted_conversation.id)
end
+
+ it 'returns only the conversations from the inbox if inbox_id filter is passed' do
+ conversation = create(:conversation, account: account, inbox_id: inbox.id)
+ params = { inbox_id: restricted_inbox.id }
+ result = described_class.new(admin, params).perform
+
+ conversation_ids = result[:conversations].map(&:id)
+ expect(conversation_ids).not_to include(conversation.id)
+ expect(conversation_ids).to include(restricted_conversation.id)
+ end
end
context 'with assignee_type all' do
diff --git a/spec/jobs/internal/process_stale_contacts_job_spec.rb b/spec/jobs/internal/process_stale_contacts_job_spec.rb
new file mode 100644
index 000000000..30648ce9a
--- /dev/null
+++ b/spec/jobs/internal/process_stale_contacts_job_spec.rb
@@ -0,0 +1,34 @@
+require 'rails_helper'
+
+RSpec.describe Internal::ProcessStaleContactsJob do
+ subject(:job) { described_class.perform_later }
+
+ it 'enqueues the job' do
+ expect { job }.to have_enqueued_job(described_class)
+ .on_queue('scheduled_jobs')
+ end
+
+ it 'enqueues RemoveStaleContactsJob for each account' do
+ account1 = create(:account)
+ account2 = create(:account)
+ account3 = create(:account)
+
+ expect { described_class.perform_now }.to have_enqueued_job(Internal::RemoveStaleContactsJob)
+ .with(account1)
+ .on_queue('low')
+ expect { described_class.perform_now }.to have_enqueued_job(Internal::RemoveStaleContactsJob)
+ .with(account2)
+ .on_queue('low')
+ expect { described_class.perform_now }.to have_enqueued_job(Internal::RemoveStaleContactsJob)
+ .with(account3)
+ .on_queue('low')
+ end
+
+ it 'processes accounts in batches' do
+ account = create(:account)
+ allow(Account).to receive(:find_in_batches).with(batch_size: 100).and_yield([account])
+
+ expect(Internal::RemoveStaleContactsJob).to receive(:perform_later).with(account)
+ described_class.perform_now
+ end
+end
diff --git a/spec/jobs/internal/remove_stale_contacts_job_spec.rb b/spec/jobs/internal/remove_stale_contacts_job_spec.rb
new file mode 100644
index 000000000..ea2636114
--- /dev/null
+++ b/spec/jobs/internal/remove_stale_contacts_job_spec.rb
@@ -0,0 +1,20 @@
+require 'rails_helper'
+
+RSpec.describe Internal::RemoveStaleContactsJob do
+ subject(:job) { described_class.perform_later(account) }
+
+ let(:account) { create(:account) }
+
+ it 'enqueues the job' do
+ expect { job }.to have_enqueued_job(described_class)
+ .with(account)
+ .on_queue('low')
+ end
+
+ it 'calls the RemoveStaleContactsService' do
+ service = instance_double(Internal::RemoveStaleContactsService)
+ expect(Internal::RemoveStaleContactsService).to receive(:new).with(account: account).and_return(service)
+ expect(service).to receive(:perform)
+ described_class.perform_now(account)
+ end
+end
diff --git a/spec/models/channel/facebook_page_spec.rb b/spec/models/channel/facebook_page_spec.rb
index 5f1374afe..f0f0e036e 100644
--- a/spec/models/channel/facebook_page_spec.rb
+++ b/spec/models/channel/facebook_page_spec.rb
@@ -30,42 +30,6 @@ RSpec.describe Channel::FacebookPage do
channel.prompt_reauthorization!
end
end
-
- context 'when fetch instagram story' do
- let!(:account) { create(:account) }
- let!(:instagram_channel) { create(:channel_instagram_fb_page, account: account, instagram_id: 'chatwoot-app-user-id-1') }
- let!(:instagram_inbox) { create(:inbox, channel: instagram_channel, account: account, greeting_enabled: false) }
- let(:fb_object) { double }
- let(:message) { create(:message, inbox_id: instagram_inbox.id) }
- let(:instagram_message) { create(:message, :instagram_story_mention, inbox_id: instagram_inbox.id) }
-
- it '#fetch_instagram_story_link' do
- allow(Koala::Facebook::API).to receive(:new).and_return(fb_object)
- allow(fb_object).to receive(:get_object).and_return(
- { story:
- {
- mention: {
- link: 'https://www.example.com/test.jpeg',
- id: '17920786367196703'
- }
- },
- from: {
- username: 'Sender-id-1', id: 'Sender-id-1'
- },
- id: 'instagram-message-id-1234' }.with_indifferent_access
- )
- story_link = instagram_channel.fetch_instagram_story_link(message)
- expect(story_link).to eq('https://www.example.com/test.jpeg')
- end
-
- it '#delete_instagram_story' do
- expect(instagram_message.attachments.count).to eq(1)
-
- instagram_channel.delete_instagram_story(instagram_message)
-
- expect(instagram_message.attachments.count).to eq(0)
- end
- end
end
it 'has a valid name' do
diff --git a/spec/models/channel/instagram_spec.rb b/spec/models/channel/instagram_spec.rb
new file mode 100644
index 000000000..901fe392e
--- /dev/null
+++ b/spec/models/channel/instagram_spec.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe Channel::Instagram do
+ let(:channel) { create(:channel_instagram) }
+
+ it { is_expected.to validate_presence_of(:account_id) }
+ it { is_expected.to validate_presence_of(:access_token) }
+ it { is_expected.to validate_presence_of(:instagram_id) }
+ it { is_expected.to belong_to(:account) }
+ it { is_expected.to have_one(:inbox).dependent(:destroy_async) }
+
+ it 'has a valid name' do
+ expect(channel.name).to eq('Instagram')
+ end
+end
diff --git a/spec/services/conversations/filter_service_spec.rb b/spec/services/conversations/filter_service_spec.rb
index 53878c780..5afa92e77 100644
--- a/spec/services/conversations/filter_service_spec.rb
+++ b/spec/services/conversations/filter_service_spec.rb
@@ -521,4 +521,241 @@ describe Conversations::FilterService do
end
end
end
+
+ describe 'Frontend alignment tests' do
+ let!(:account) { create(:account) }
+ let!(:user_1) { create(:user, account: account) }
+ let!(:inbox) { create(:inbox, account: account) }
+ let!(:params) { { payload: [], page: 1 } }
+
+ before do
+ account.conversations.destroy_all
+ end
+
+ context 'with A AND B OR C filter chain' do
+ let(:conversation) { create(:conversation, account: account, inbox: inbox, assignee: user_1) }
+ let(:filter_payload) do
+ [
+ {
+ attribute_key: 'status',
+ filter_operator: 'equal_to',
+ values: ['open'],
+ query_operator: 'AND'
+ }.with_indifferent_access,
+ {
+ attribute_key: 'priority',
+ filter_operator: 'equal_to',
+ values: ['urgent'],
+ query_operator: 'OR'
+ }.with_indifferent_access,
+ {
+ attribute_key: 'display_id',
+ filter_operator: 'equal_to',
+ values: ['12345'],
+ query_operator: nil
+ }.with_indifferent_access
+ ]
+ end
+
+ before do
+ conversation.update!(
+ status: 'open',
+ priority: 'urgent',
+ display_id: '12345',
+ additional_attributes: { 'browser_language': 'en' }
+ )
+ end
+
+ it 'matches when all conditions are true' do
+ params[:payload] = filter_payload
+ result = described_class.new(params, user_1).perform
+ expect(result[:conversations].length).to be 1
+ end
+
+ it 'matches when first condition is false but third is true' do
+ conversation.update!(status: 'resolved', priority: 'urgent', display_id: '12345')
+ params[:payload] = filter_payload
+ result = described_class.new(params, user_1).perform
+ expect(result[:conversations].length).to be 1
+ end
+
+ it 'matches when first and second condition is false but third is true' do
+ conversation.update!(status: 'resolved', priority: 'low', display_id: '12345')
+ params[:payload] = filter_payload
+ result = described_class.new(params, user_1).perform
+ expect(result[:conversations].length).to be 1
+ end
+
+ it 'does not match when all conditions are false' do
+ conversation.update!(status: 'resolved', priority: 'low', display_id: '67890')
+ params[:payload] = filter_payload
+ result = described_class.new(params, user_1).perform
+ expect(result[:conversations].length).to be 0
+ end
+ end
+
+ context 'with A OR B AND C filter chain' do
+ let(:conversation) { create(:conversation, account: account, inbox: inbox, assignee: user_1) }
+ let(:filter_payload) do
+ [
+ {
+ attribute_key: 'status',
+ filter_operator: 'equal_to',
+ values: ['open'],
+ query_operator: 'OR'
+ }.with_indifferent_access,
+ {
+ attribute_key: 'priority',
+ filter_operator: 'equal_to',
+ values: ['low'],
+ query_operator: 'AND'
+ }.with_indifferent_access,
+ {
+ attribute_key: 'display_id',
+ filter_operator: 'equal_to',
+ values: ['67890'],
+ query_operator: nil
+ }.with_indifferent_access
+ ]
+ end
+
+ before do
+ conversation.update!(
+ status: 'open',
+ priority: 'urgent',
+ display_id: '12345',
+ additional_attributes: { 'browser_language': 'en' }
+ )
+ end
+
+ it 'matches when first condition is true' do
+ params[:payload] = filter_payload
+ result = described_class.new(params, user_1).perform
+ expect(result[:conversations].length).to be 1
+ end
+
+ it 'matches when second and third conditions are true' do
+ conversation.update!(status: 'resolved', priority: 'low', display_id: '67890')
+ params[:payload] = filter_payload
+ result = described_class.new(params, user_1).perform
+ expect(result[:conversations].length).to be 1
+ end
+ end
+
+ context 'with complex filter chain A AND B OR C AND D' do
+ let(:conversation) { create(:conversation, account: account, inbox: inbox, assignee: user_1) }
+ let(:filter_payload) do
+ [
+ {
+ attribute_key: 'status',
+ filter_operator: 'equal_to',
+ values: ['open'],
+ query_operator: 'AND'
+ }.with_indifferent_access,
+ {
+ attribute_key: 'priority',
+ filter_operator: 'equal_to',
+ values: ['urgent'],
+ query_operator: 'OR'
+ }.with_indifferent_access,
+ {
+ attribute_key: 'display_id',
+ filter_operator: 'equal_to',
+ values: ['67890'],
+ query_operator: 'AND'
+ }.with_indifferent_access,
+ {
+ attribute_key: 'browser_language',
+ filter_operator: 'equal_to',
+ values: ['tr'],
+ query_operator: nil
+ }.with_indifferent_access
+ ]
+ end
+
+ before do
+ conversation.update!(
+ status: 'open',
+ priority: 'urgent',
+ display_id: '12345',
+ additional_attributes: { 'browser_language': 'en' },
+ custom_attributes: { conversation_type: 'platinum' }
+ )
+ end
+
+ it 'matches when first two conditions are true' do
+ params[:payload] = filter_payload
+ result = described_class.new(params, user_1).perform
+ expect(result[:conversations].length).to be 1
+ end
+
+ it 'matches when last two conditions are true' do
+ conversation.update!(
+ status: 'resolved',
+ priority: 'low',
+ display_id: '67890',
+ additional_attributes: { 'browser_language': 'tr' }
+ )
+ params[:payload] = filter_payload
+ result = described_class.new(params, user_1).perform
+ expect(result[:conversations].length).to be 1
+ end
+ end
+
+ context 'with mixed operators filter chain' do
+ let(:conversation) { create(:conversation, account: account, inbox: inbox, assignee: user_1) }
+ let(:filter_payload) do
+ [
+ {
+ attribute_key: 'status',
+ filter_operator: 'equal_to',
+ values: ['open'],
+ query_operator: 'AND'
+ }.with_indifferent_access,
+ {
+ attribute_key: 'priority',
+ filter_operator: 'equal_to',
+ values: ['urgent'],
+ query_operator: 'OR'
+ }.with_indifferent_access,
+ {
+ attribute_key: 'display_id',
+ filter_operator: 'equal_to',
+ values: ['67890'],
+ query_operator: 'AND'
+ }.with_indifferent_access,
+ {
+ attribute_key: 'conversation_type',
+ filter_operator: 'equal_to',
+ values: ['platinum'],
+ custom_attribute_type: '',
+ query_operator: nil
+ }.with_indifferent_access
+ ]
+ end
+
+ before do
+ conversation.update!(
+ status: 'open',
+ priority: 'urgent',
+ display_id: '12345',
+ additional_attributes: { 'browser_language': 'en' },
+ custom_attributes: { conversation_type: 'platinum' }
+ )
+ end
+
+ it 'matches when all conditions in the chain are true' do
+ params[:payload] = filter_payload
+ result = described_class.new(params, user_1).perform
+ expect(result[:conversations].length).to be 1
+ end
+
+ it 'does not match when the last condition is false' do
+ conversation.update!(custom_attributes: { conversation_type: 'silver' })
+ params[:payload] = filter_payload
+ result = described_class.new(params, user_1).perform
+ expect(result[:conversations].length).to be 1
+ end
+ end
+ end
end
diff --git a/spec/services/internal/remove_stale_contacts_service_spec.rb b/spec/services/internal/remove_stale_contacts_service_spec.rb
new file mode 100644
index 000000000..d00c0e3ca
--- /dev/null
+++ b/spec/services/internal/remove_stale_contacts_service_spec.rb
@@ -0,0 +1,41 @@
+require 'rails_helper'
+
+RSpec.describe Internal::RemoveStaleContactsService do
+ describe '#perform' do
+ let(:account) { create(:account) }
+
+ it 'does not delete contacts with conversations' do
+ # Contact with NULL values and conversation
+ contact1 = create(:contact, account: account, email: nil, phone_number: nil, identifier: nil, created_at: 31.days.ago)
+ create(:conversation, contact: contact1)
+
+ # Contact with empty strings and conversation
+ contact2 = create(:contact, account: account, email: '', phone_number: '', identifier: '', created_at: 31.days.ago)
+ create(:conversation, contact: contact2)
+
+ service = described_class.new(account: account)
+ expect { service.perform }.not_to change(Contact, :count)
+ end
+
+ it 'does not delete contacts with identification' do
+ create(:contact, :with_email, account: account, phone_number: '', identifier: nil, created_at: 31.days.ago)
+ create(:contact, :with_phone_number, account: account, email: nil, identifier: '', created_at: 31.days.ago)
+ create(:contact, account: account, identifier: 'test123', created_at: 31.days.ago)
+
+ create(:contact, :with_email, account: account, phone_number: '', identifier: nil, created_at: 31.days.ago)
+ create(:contact, :with_phone_number, account: account, email: nil, identifier: nil, created_at: 31.days.ago)
+ create(:contact, account: account, email: '', phone_number: nil, identifier: 'test1234', created_at: 31.days.ago)
+
+ service = described_class.new(account: account)
+ expect { service.perform }.not_to change(Contact, :count)
+ end
+
+ it 'deletes stale contacts' do
+ create(:contact, account: account, created_at: 31.days.ago)
+ create(:contact, account: account, created_at: 1.day.ago)
+
+ service = described_class.new(account: account)
+ expect { service.perform }.to change(Contact, :count).by(-1)
+ end
+ end
+end
diff --git a/spec/services/whatsapp/send_on_whatsapp_service_spec.rb b/spec/services/whatsapp/send_on_whatsapp_service_spec.rb
index 88f3f7740..a0e3e893a 100644
--- a/spec/services/whatsapp/send_on_whatsapp_service_spec.rb
+++ b/spec/services/whatsapp/send_on_whatsapp_service_spec.rb
@@ -18,6 +18,7 @@ describe Whatsapp::SendOnWhatsappService do
context 'when a valid message' do
let(:whatsapp_request) { instance_double(HTTParty::Response) }
let!(:whatsapp_channel) { create(:channel_whatsapp, sync_templates: false) }
+
let!(:contact_inbox) { create(:contact_inbox, inbox: whatsapp_channel.inbox, source_id: '123456789') }
let!(:conversation) { create(:conversation, contact_inbox: contact_inbox, inbox: whatsapp_channel.inbox) }
let(:api_key) { 'test_key' }
@@ -35,6 +36,21 @@ describe Whatsapp::SendOnWhatsappService do
}
end
+ let(:named_template_body) do
+ {
+ messaging_product: 'whatsapp',
+ to: '123456789',
+ template: {
+ name: 'ticket_status_updated',
+ language: { 'policy': 'deterministic', 'code': 'en_US' },
+ components: [{ 'type': 'body',
+ 'parameters': [{ 'type': 'text', parameter_name: 'last_name', 'text': 'Dale' },
+ { 'type': 'text', parameter_name: 'ticket_id', 'text': '2332' }] }]
+ },
+ type: 'template'
+ }
+ end
+
let(:success_response) { { 'messages' => [{ 'id' => '123456789' }] }.to_json }
it 'calls channel.send_message when with in 24 hour limit' do
@@ -82,6 +98,31 @@ describe Whatsapp::SendOnWhatsappService do
expect(message.reload.source_id).to eq('123456789')
end
+ it 'calls channel.send_template with named params if template parameter type is NAMED' do
+ whatsapp_cloud_channel = create(:channel_whatsapp, provider: 'whatsapp_cloud', sync_templates: false, validate_provider_config: false)
+ cloud_contact_inbox = create(:contact_inbox, inbox: whatsapp_cloud_channel.inbox, source_id: '123456789')
+ cloud_conversation = create(:conversation, contact_inbox: cloud_contact_inbox, inbox: whatsapp_cloud_channel.inbox)
+
+ named_template_params = {
+ name: 'ticket_status_updated',
+ language: 'en_US',
+ category: 'UTILITY',
+ processed_params: { 'last_name' => 'Dale', 'ticket_id' => '2332' }
+ }
+
+ stub_request(:post, "https://graph.facebook.com/v13.0/#{whatsapp_cloud_channel.provider_config['phone_number_id']}/messages")
+ .with(
+ :headers => { 'Content-Type' => 'application/json', 'Authorization' => "Bearer #{whatsapp_cloud_channel.provider_config['api_key']}" },
+ :body => named_template_body.to_json
+ ).to_return(status: 200, body: success_response, headers: { 'content-type' => 'application/json' })
+ message = create(:message,
+ additional_attributes: { template_params: named_template_params },
+ content: 'Your package will be delivered in 3 business days.', conversation: cloud_conversation, message_type: :outgoing)
+
+ described_class.new(message: message).perform
+ expect(message.reload.source_id).to eq('123456789')
+ end
+
it 'calls channel.send_template when template has regexp characters' do
message = create(
:message,
diff --git a/vitest.setup.js b/vitest.setup.js
index 63b7a3581..1bed8ee3e 100644
--- a/vitest.setup.js
+++ b/vitest.setup.js
@@ -13,5 +13,5 @@ config.global.plugins = [i18n, FloatingVue];
config.global.stubs = {
WootModal: { template: '
' },
WootModalHeader: { template: '
' },
- WootButton: { template: '
' },
+ NextButton: { template: '
' },
};