-
- {{ webhook.url }}
+
+
+ {{ webhook.name }}
+
+ {{ webhook.url }}
+
+
+
+ {{ webhook.url }}
+
diff --git a/app/models/webhook.rb b/app/models/webhook.rb
index 105ffdc91..3fafb4354 100644
--- a/app/models/webhook.rb
+++ b/app/models/webhook.rb
@@ -3,6 +3,7 @@
# Table name: webhooks
#
# id :bigint not null, primary key
+# name :string
# subscriptions :jsonb
# url :string
# webhook_type :integer default("account_type")
diff --git a/app/views/api/v1/accounts/webhooks/_webhook.json.jbuilder b/app/views/api/v1/accounts/webhooks/_webhook.json.jbuilder
index fac8fdcf2..5406cf183 100644
--- a/app/views/api/v1/accounts/webhooks/_webhook.json.jbuilder
+++ b/app/views/api/v1/accounts/webhooks/_webhook.json.jbuilder
@@ -1,4 +1,5 @@
json.id webhook.id
+json.name webhook.name
json.url webhook.url
json.account_id webhook.account_id
json.subscriptions webhook.subscriptions
diff --git a/db/migrate/20251010143218_add_name_to_webhooks.rb b/db/migrate/20251010143218_add_name_to_webhooks.rb
new file mode 100644
index 000000000..693ecc35a
--- /dev/null
+++ b/db/migrate/20251010143218_add_name_to_webhooks.rb
@@ -0,0 +1,5 @@
+class AddNameToWebhooks < ActiveRecord::Migration[7.1]
+ def change
+ add_column :webhooks, :name, :string, null: true
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 45165d5c5..0aeea5cc9 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -1230,6 +1230,7 @@ ActiveRecord::Schema[7.1].define(version: 2025_10_22_152158) do
t.datetime "updated_at", null: false
t.integer "webhook_type", default: 0
t.jsonb "subscriptions", default: ["conversation_status_changed", "conversation_updated", "conversation_created", "contact_created", "contact_updated", "message_created", "message_updated", "webwidget_triggered"]
+ t.string "name"
t.index ["account_id", "url"], name: "index_webhooks_on_account_id_and_url", unique: true
end
diff --git a/spec/controllers/api/v1/accounts/webhook_controller_spec.rb b/spec/controllers/api/v1/accounts/webhook_controller_spec.rb
index 3a68d8921..86f4d4e7e 100644
--- a/spec/controllers/api/v1/accounts/webhook_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/webhook_controller_spec.rb
@@ -3,7 +3,7 @@ require 'rails_helper'
RSpec.describe 'Webhooks API', type: :request do
let(:account) { create(:account) }
let(:inbox) { create(:inbox, account: account) }
- let(:webhook) { create(:webhook, account: account, inbox: inbox, url: 'https://hello.com') }
+ let(:webhook) { create(:webhook, account: account, inbox: inbox, url: 'https://hello.com', name: 'My Webhook') }
let(:administrator) { create(:user, account: account, role: :administrator) }
let(:agent) { create(:user, account: account, role: :agent) }
@@ -49,6 +49,16 @@ RSpec.describe 'Webhooks API', type: :request do
expect(response.parsed_body['payload']['webhook']['url']).to eql 'https://hello.com'
end
+ it 'creates webhook with name' do
+ post "/api/v1/accounts/#{account.id}/webhooks",
+ params: { account_id: account.id, inbox_id: inbox.id, url: 'https://hello.com', name: 'My Webhook' },
+ headers: administrator.create_new_auth_token,
+ as: :json
+ expect(response).to have_http_status(:success)
+
+ expect(response.parsed_body['payload']['webhook']['name']).to eql 'My Webhook'
+ end
+
it 'throws error when invalid url provided' do
post "/api/v1/accounts/#{account.id}/webhooks",
params: { account_id: account.id, inbox_id: inbox.id, url: 'javascript:alert(1)' },
@@ -103,11 +113,12 @@ RSpec.describe 'Webhooks API', type: :request do
context 'when it is an authenticated admin user' do
it 'updates webhook' do
put "/api/v1/accounts/#{account.id}/webhooks/#{webhook.id}",
- params: { url: 'https://hello.com' },
+ params: { url: 'https://hello.com', name: 'Another Webhook' },
headers: administrator.create_new_auth_token,
as: :json
expect(response).to have_http_status(:success)
expect(response.parsed_body['payload']['webhook']['url']).to eql 'https://hello.com'
+ expect(response.parsed_body['payload']['webhook']['name']).to eql 'Another Webhook'
end
end
end
diff --git a/spec/factories/webhooks.rb b/spec/factories/webhooks.rb
index 42acc2be6..a4a875c84 100644
--- a/spec/factories/webhooks.rb
+++ b/spec/factories/webhooks.rb
@@ -3,6 +3,7 @@ FactoryBot.define do
account_id { 1 }
inbox_id { 1 }
url { 'https://api.chatwoot.com' }
+ name { 'My Webhook' }
subscriptions do
%w[
conversation_status_changed
diff --git a/swagger/definitions/request/webhooks/create_update_payload.yml b/swagger/definitions/request/webhooks/create_update_payload.yml
index 2f4a718e4..485d532e4 100644
--- a/swagger/definitions/request/webhooks/create_update_payload.yml
+++ b/swagger/definitions/request/webhooks/create_update_payload.yml
@@ -4,6 +4,9 @@ properties:
type: string
description: The url where the events should be sent
example: https://example.com/webhook
+ name:
+ type: string
+ description: The name of the webhook
subscriptions:
type: array
items:
diff --git a/swagger/definitions/resource/webhook.yml b/swagger/definitions/resource/webhook.yml
index a9881b8e4..da5cb112a 100644
--- a/swagger/definitions/resource/webhook.yml
+++ b/swagger/definitions/resource/webhook.yml
@@ -6,6 +6,9 @@ properties:
url:
type: string
description: The url to which the events will be send
+ name:
+ type: string
+ description: The name of the webhook
subscriptions:
type: array
items:
diff --git a/swagger/swagger.json b/swagger/swagger.json
index 7a3e5b02d..8d539c259 100644
--- a/swagger/swagger.json
+++ b/swagger/swagger.json
@@ -9127,6 +9127,10 @@
"type": "string",
"description": "The url to which the events will be send"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
@@ -10706,6 +10710,10 @@
"description": "The url where the events should be sent",
"example": "https://example.com/webhook"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
diff --git a/swagger/tag_groups/application_swagger.json b/swagger/tag_groups/application_swagger.json
index 72902b3b8..2fd0cbdee 100644
--- a/swagger/tag_groups/application_swagger.json
+++ b/swagger/tag_groups/application_swagger.json
@@ -7634,6 +7634,10 @@
"type": "string",
"description": "The url to which the events will be send"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
@@ -9213,6 +9217,10 @@
"description": "The url where the events should be sent",
"example": "https://example.com/webhook"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
diff --git a/swagger/tag_groups/client_swagger.json b/swagger/tag_groups/client_swagger.json
index 6d8b7701d..cf356e609 100644
--- a/swagger/tag_groups/client_swagger.json
+++ b/swagger/tag_groups/client_swagger.json
@@ -1934,6 +1934,10 @@
"type": "string",
"description": "The url to which the events will be send"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
@@ -3513,6 +3517,10 @@
"description": "The url where the events should be sent",
"example": "https://example.com/webhook"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
diff --git a/swagger/tag_groups/other_swagger.json b/swagger/tag_groups/other_swagger.json
index 9e8c57c04..ed1073d0b 100644
--- a/swagger/tag_groups/other_swagger.json
+++ b/swagger/tag_groups/other_swagger.json
@@ -1349,6 +1349,10 @@
"type": "string",
"description": "The url to which the events will be send"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
@@ -2928,6 +2932,10 @@
"description": "The url where the events should be sent",
"example": "https://example.com/webhook"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
diff --git a/swagger/tag_groups/platform_swagger.json b/swagger/tag_groups/platform_swagger.json
index 7c79f1c5b..1bf31a212 100644
--- a/swagger/tag_groups/platform_swagger.json
+++ b/swagger/tag_groups/platform_swagger.json
@@ -2110,6 +2110,10 @@
"type": "string",
"description": "The url to which the events will be send"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
@@ -3689,6 +3693,10 @@
"description": "The url where the events should be sent",
"example": "https://example.com/webhook"
},
+ "name": {
+ "type": "string",
+ "description": "The name of the webhook"
+ },
"subscriptions": {
"type": "array",
"items": {
From b4a252a45944b7c21bf2ebb79c72ac76bfcd2344 Mon Sep 17 00:00:00 2001
From: Vishnu Narayanan
Date: Thu, 13 Nov 2025 20:17:59 +0530
Subject: [PATCH 61/80] perf: speed up docker builds (#12859)
- Use separate keys to avoid cache overwrites across different
architecture builds
https://linear.app/chatwoot/issue/CW-5945/perf-speed-up-docker-builds
### 25 mins ---> 5mins
## before
## after
---
.github/workflows/test_docker_build.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/test_docker_build.yml b/.github/workflows/test_docker_build.yml
index 460c4ba1f..b27d90408 100644
--- a/.github/workflows/test_docker_build.yml
+++ b/.github/workflows/test_docker_build.yml
@@ -36,5 +36,5 @@ jobs:
platforms: ${{ matrix.platform }}
push: false
load: false
- cache-from: type=gha
- cache-to: type=gha,mode=max
+ cache-from: type=gha,scope=${{ matrix.platform }}
+ cache-to: type=gha,mode=max,scope=${{ matrix.platform }}
From 651645fbd2c069b01950ab7ff094ac20f5b49ab2 Mon Sep 17 00:00:00 2001
From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Date: Thu, 13 Nov 2025 22:16:13 +0530
Subject: [PATCH 62/80] chore: Update missing places with new colors (#12862)
# Pull Request Template
## Description
This PR updates the colors in places that were missed during the color
update migration.
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
---
.../dashboard/components/ui/Dropdown/DropdownButton.vue | 1 +
.../dashboard/routes/dashboard/settings/inbox/FinishSetup.vue | 2 +-
.../routes/dashboard/settings/inbox/channels/Whatsapp.vue | 4 ++--
.../settings/inbox/settingsPage/ConfigurationPage.vue | 2 +-
4 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/app/javascript/dashboard/components/ui/Dropdown/DropdownButton.vue b/app/javascript/dashboard/components/ui/Dropdown/DropdownButton.vue
index 7289267c1..5ca8bde2b 100644
--- a/app/javascript/dashboard/components/ui/Dropdown/DropdownButton.vue
+++ b/app/javascript/dashboard/components/ui/Dropdown/DropdownButton.vue
@@ -23,6 +23,7 @@ defineProps({
slate
sm
class="relative"
+ no-animation
:icon="icon"
:trailing-icon="trailingIcon"
>
diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/FinishSetup.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/FinishSetup.vue
index b19416137..46a189b39 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/inbox/FinishSetup.vue
+++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/FinishSetup.vue
@@ -197,7 +197,7 @@ onMounted(() => {
v-if="shouldShowWhatsAppWebhookDetails"
class="w-[50%] max-w-[50%] ml-[25%]"
>
-
+
{{ $t('INBOX_MGMT.ADD.WHATSAPP.API_CALLBACK.WEBHOOK_URL') }}
diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Whatsapp.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Whatsapp.vue
index c6c021a45..b8b8126c7 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Whatsapp.vue
+++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/channels/Whatsapp.vue
@@ -73,10 +73,10 @@ const handleManualLinkClick = () => {
-
+
{{ $t('INBOX_MGMT.ADD.WHATSAPP.SELECT_PROVIDER.TITLE') }}
-
+
{{ $t('INBOX_MGMT.ADD.WHATSAPP.SELECT_PROVIDER.DESCRIPTION') }}
diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/ConfigurationPage.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/ConfigurationPage.vue
index 186fcc48e..578a788cd 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/ConfigurationPage.vue
+++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/ConfigurationPage.vue
@@ -322,7 +322,7 @@ export default {
"
>
-
+
{{
$t(
'INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_EMBEDDED_SIGNUP_DESCRIPTION'
From eed1825d5a3b21d9a2e1b0e829a93a10e2d974e0 Mon Sep 17 00:00:00 2001
From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Date: Thu, 13 Nov 2025 22:16:25 +0530
Subject: [PATCH 63/80] fix: Brand installation name not showing (#12861)
# Pull Request Template
## Description
Fixes
https://linear.app/chatwoot/issue/CW-5946/fix-brand-installation-name-issue-in-dyte
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
---
.../routes/dashboard/settings/integrations/NewHook.vue | 6 ++++--
.../settings/integrations/SingleIntegrationHooks.vue | 5 ++++-
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/app/javascript/dashboard/routes/dashboard/settings/integrations/NewHook.vue b/app/javascript/dashboard/routes/dashboard/settings/integrations/NewHook.vue
index 5fe350215..1a4d36fee 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/integrations/NewHook.vue
+++ b/app/javascript/dashboard/routes/dashboard/settings/integrations/NewHook.vue
@@ -4,6 +4,7 @@ import { mapGetters } from 'vuex';
import { useAlert } from 'dashboard/composables';
import { useIntegrationHook } from 'dashboard/composables/useIntegrationHook';
import { FormKit } from '@formkit/vue';
+import { useBranding } from 'shared/composables/useBranding';
import NextButton from 'dashboard/components-next/button/Button.vue';
@@ -23,8 +24,9 @@ export default {
const { integration, isHookTypeInbox } = useIntegrationHook(
props.integrationId
);
+ const { replaceInstallationName } = useBranding();
- return { integration, isHookTypeInbox };
+ return { integration, isHookTypeInbox, replaceInstallationName };
},
data() {
return {
@@ -117,7 +119,7 @@ export default {
import { defineProps, defineEmits } from 'vue';
import { useIntegrationHook } from 'dashboard/composables/useIntegrationHook';
+import { useBranding } from 'shared/composables/useBranding';
import Button from 'dashboard/components-next/button/Button.vue';
const props = defineProps({
@@ -15,6 +16,8 @@ defineEmits(['add', 'delete']);
const { integration, hasConnectedHooks } = useIntegrationHook(
props.integrationId
);
+
+const { replaceInstallationName } = useBranding();
@@ -37,7 +40,7 @@ const { integration, hasConnectedHooks } = useIntegrationHook(
{{ integration.name }}
- {{ integration.description }}
+ {{ replaceInstallationName(integration.description) }}
From 559d1b65768e131853ce00a15aea1a12d8359352 Mon Sep 17 00:00:00 2001
From: Vinay Keerthi <11478411+stonecharioteer@users.noreply.github.com>
Date: Fri, 14 Nov 2025 12:35:38 +0530
Subject: [PATCH 64/80] fix: migrate from deprecated annotate gem to annotaterb
(#12845)
## Description
The `annotate` gem has been deprecated and users are experiencing
annotation errors with the new Rails 7 `serialize` syntax. This PR
migrates to `annotaterb`, the actively maintained fork.
Users reported errors when running `make db`:
```
Unable to annotate app/models/installation_config.rb: no implicit conversion of Hash into String
Unable to annotate app/models/installation_config.rb: no implicit conversion of nil into Array
```
This PR updates the Gemfile and rake configuration to use `annotaterb`
instead.
Fixes #11673
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
Tested locally with the following steps:
1. Run `bundle install` - successfully installed annotaterb 4.20.0
2. Run `RAILS_ENV=development bundle exec rails db:chatwoot_prepare` -
completed without annotation errors
3. Run `RAILS_ENV=development bundle exec rails annotate_rb:models` -
successfully annotated all models including InstallationConfig
4. Verified InstallationConfig model annotations are present and correct
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] My changes generate no new warnings
- [x] New and existing unit tests pass locally with my changes
---
Gemfile | 2 +-
Gemfile.lock | 8 ++++----
lib/tasks/auto_annotate_models.rake | 9 +++++----
3 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/Gemfile b/Gemfile
index abbd3332f..4b9d978d4 100644
--- a/Gemfile
+++ b/Gemfile
@@ -207,7 +207,7 @@ group :production do
end
group :development do
- gem 'annotate'
+ gem 'annotaterb'
gem 'bullet'
gem 'letter_opener'
gem 'scss_lint', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index 99e75b33c..fa3a5e788 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -128,9 +128,9 @@ GEM
selectize-rails (~> 0.6)
ai-agents (0.4.3)
ruby_llm (~> 1.3)
- annotate (3.2.0)
- activerecord (>= 3.2, < 8.0)
- rake (>= 10.4, < 14.0)
+ annotaterb (4.20.0)
+ activerecord (>= 6.0.0)
+ activesupport (>= 6.0.0)
ast (2.4.3)
attr_extras (7.1.0)
audited (5.4.1)
@@ -992,7 +992,7 @@ DEPENDENCIES
administrate-field-active_storage (>= 1.0.3)
administrate-field-belongs_to_search (>= 0.9.0)
ai-agents (>= 0.4.3)
- annotate
+ annotaterb
attr_extras
audited (~> 5.4, >= 5.4.1)
aws-sdk-s3
diff --git a/lib/tasks/auto_annotate_models.rake b/lib/tasks/auto_annotate_models.rake
index 8a89739b6..9dcd13126 100644
--- a/lib/tasks/auto_annotate_models.rake
+++ b/lib/tasks/auto_annotate_models.rake
@@ -2,11 +2,14 @@
# NOTE: are sensitive to local FS writes, and besides -- it's just not proper
# NOTE: to have a dev-mode tool do its thing in production.
if Rails.env.development?
- require 'annotate'
+ require 'annotate_rb'
+
+ AnnotateRb::Core.load_rake_tasks
+
task :set_annotation_options do
# You can override any of these by setting an environment variable of the
# same name.
- Annotate.set_defaults(
+ AnnotateRb::Options.set_defaults(
'additional_file_patterns' => [],
'routes' => 'false',
'models' => 'true',
@@ -55,6 +58,4 @@ if Rails.env.development?
'with_comment' => 'true'
)
end
-
- Annotate.load_tasks
end
From 945a08eadb74ec4534d0e3b4bd7b788ed03d5c98 Mon Sep 17 00:00:00 2001
From: Sojan Jose
Date: Thu, 13 Nov 2025 23:49:06 -0800
Subject: [PATCH 65/80] chore: disable worker MemoryHigh throttling in systemd
unit (#12871)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- set MemoryHigh to infinity in deployment/chatwoot-worker.1.service so
the worker is throttled only by the existing
MemoryMax hard limit
- prevents cgroup reclaim from slowing Sidekiq under transient spikes
while still keeping the hard stop at 1.5 GB
---
deployment/chatwoot-worker.1.service | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/deployment/chatwoot-worker.1.service b/deployment/chatwoot-worker.1.service
index ea893d20c..6cc169c9e 100644
--- a/deployment/chatwoot-worker.1.service
+++ b/deployment/chatwoot-worker.1.service
@@ -17,7 +17,7 @@ StandardInput=null
SyslogIdentifier=%p
MemoryMax=1.5G
-MemoryHigh=1.4G
+MemoryHigh=infinity
MemorySwapMax=0
OOMPolicy=stop
From 32da4eec275118105f4f8a0541327542c5bdc6a5 Mon Sep 17 00:00:00 2001
From: Chatwoot Bot <92152627+chatwoot-bot@users.noreply.github.com>
Date: Fri, 14 Nov 2025 01:54:38 -0800
Subject: [PATCH 66/80] chore: Update translations (#12818)
---
.../i18n/locale/am/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/am/report.json | 2 +
.../dashboard/i18n/locale/am/settings.json | 10 +++
.../i18n/locale/ar/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/ar/report.json | 2 +
.../dashboard/i18n/locale/ar/settings.json | 10 +++
.../i18n/locale/az/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/az/report.json | 2 +
.../dashboard/i18n/locale/az/settings.json | 10 +++
.../i18n/locale/bg/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/bg/report.json | 2 +
.../dashboard/i18n/locale/bg/settings.json | 10 +++
.../i18n/locale/bn/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/bn/report.json | 2 +
.../dashboard/i18n/locale/bn/settings.json | 10 +++
.../i18n/locale/ca/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/ca/report.json | 2 +
.../dashboard/i18n/locale/ca/settings.json | 10 +++
.../i18n/locale/cs/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/cs/report.json | 2 +
.../dashboard/i18n/locale/cs/settings.json | 10 +++
.../i18n/locale/da/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/da/report.json | 2 +
.../dashboard/i18n/locale/da/settings.json | 10 +++
.../dashboard/i18n/locale/de/contact.json | 32 +++++-----
.../i18n/locale/de/conversation.json | 44 ++++++-------
.../i18n/locale/de/generalSettings.json | 26 ++++----
.../dashboard/i18n/locale/de/inboxMgmt.json | 10 +--
.../i18n/locale/de/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/de/report.json | 2 +
.../dashboard/i18n/locale/de/settings.json | 10 +++
.../i18n/locale/el/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/el/report.json | 2 +
.../dashboard/i18n/locale/el/settings.json | 10 +++
.../i18n/locale/es/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/es/report.json | 2 +
.../dashboard/i18n/locale/es/settings.json | 10 +++
.../i18n/locale/et/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/et/report.json | 2 +
.../dashboard/i18n/locale/et/settings.json | 10 +++
.../i18n/locale/fa/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/fa/report.json | 2 +
.../dashboard/i18n/locale/fa/settings.json | 10 +++
.../i18n/locale/fi/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/fi/report.json | 2 +
.../dashboard/i18n/locale/fi/settings.json | 10 +++
.../i18n/locale/fr/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/fr/report.json | 2 +
.../dashboard/i18n/locale/fr/settings.json | 10 +++
.../i18n/locale/he/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/he/report.json | 2 +
.../dashboard/i18n/locale/he/settings.json | 10 +++
.../i18n/locale/hi/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/hi/report.json | 2 +
.../dashboard/i18n/locale/hi/settings.json | 10 +++
.../i18n/locale/hr/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/hr/report.json | 2 +
.../dashboard/i18n/locale/hr/settings.json | 10 +++
.../i18n/locale/hu/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/hu/report.json | 2 +
.../dashboard/i18n/locale/hu/settings.json | 10 +++
.../i18n/locale/hy/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/hy/report.json | 2 +
.../dashboard/i18n/locale/hy/settings.json | 10 +++
.../i18n/locale/id/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/id/report.json | 2 +
.../dashboard/i18n/locale/id/settings.json | 10 +++
.../i18n/locale/is/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/is/report.json | 2 +
.../dashboard/i18n/locale/is/settings.json | 10 +++
.../i18n/locale/it/conversation.json | 6 +-
.../dashboard/i18n/locale/it/inboxMgmt.json | 8 +--
.../i18n/locale/it/integrations.json | 57 +++++++----------
.../dashboard/i18n/locale/it/report.json | 2 +
.../dashboard/i18n/locale/it/settings.json | 18 ++++--
.../i18n/locale/ja/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/ja/report.json | 2 +
.../dashboard/i18n/locale/ja/settings.json | 10 +++
.../i18n/locale/ka/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/ka/report.json | 2 +
.../dashboard/i18n/locale/ka/settings.json | 10 +++
.../i18n/locale/ko/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/ko/report.json | 2 +
.../dashboard/i18n/locale/ko/settings.json | 10 +++
.../i18n/locale/lt/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/lt/report.json | 2 +
.../dashboard/i18n/locale/lt/settings.json | 10 +++
.../i18n/locale/lv/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/lv/report.json | 2 +
.../dashboard/i18n/locale/lv/settings.json | 10 +++
.../i18n/locale/ml/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/ml/report.json | 2 +
.../dashboard/i18n/locale/ml/settings.json | 10 +++
.../i18n/locale/ms/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/ms/report.json | 2 +
.../dashboard/i18n/locale/ms/settings.json | 10 +++
.../i18n/locale/ne/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/ne/report.json | 2 +
.../dashboard/i18n/locale/ne/settings.json | 10 +++
.../i18n/locale/nl/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/nl/report.json | 2 +
.../dashboard/i18n/locale/nl/settings.json | 10 +++
.../i18n/locale/no/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/no/report.json | 2 +
.../dashboard/i18n/locale/no/settings.json | 10 +++
.../i18n/locale/pl/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/pl/report.json | 2 +
.../dashboard/i18n/locale/pl/settings.json | 10 +++
.../i18n/locale/pt/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/pt/report.json | 2 +
.../dashboard/i18n/locale/pt/settings.json | 10 +++
.../i18n/locale/pt_BR/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/pt_BR/report.json | 2 +
.../dashboard/i18n/locale/pt_BR/settings.json | 10 +++
.../i18n/locale/ro/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/ro/report.json | 2 +
.../dashboard/i18n/locale/ro/settings.json | 10 +++
.../i18n/locale/ru/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/ru/report.json | 2 +
.../dashboard/i18n/locale/ru/settings.json | 10 +++
.../i18n/locale/sh/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/sh/report.json | 2 +
.../dashboard/i18n/locale/sh/settings.json | 10 +++
.../i18n/locale/sk/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/sk/report.json | 2 +
.../dashboard/i18n/locale/sk/settings.json | 10 +++
.../i18n/locale/sl/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/sl/report.json | 2 +
.../dashboard/i18n/locale/sl/settings.json | 10 +++
.../i18n/locale/sq/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/sq/report.json | 2 +
.../dashboard/i18n/locale/sq/settings.json | 10 +++
.../i18n/locale/sr/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/sr/report.json | 2 +
.../dashboard/i18n/locale/sr/settings.json | 10 +++
.../i18n/locale/sv/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/sv/report.json | 2 +
.../dashboard/i18n/locale/sv/settings.json | 10 +++
.../i18n/locale/ta/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/ta/report.json | 2 +
.../dashboard/i18n/locale/ta/settings.json | 10 +++
.../i18n/locale/th/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/th/report.json | 2 +
.../dashboard/i18n/locale/th/settings.json | 10 +++
.../i18n/locale/tl/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/tl/report.json | 2 +
.../dashboard/i18n/locale/tl/settings.json | 10 +++
.../i18n/locale/tr/conversation.json | 6 +-
.../dashboard/i18n/locale/tr/inbox.json | 12 ++--
.../dashboard/i18n/locale/tr/inboxMgmt.json | 62 +++++++++----------
.../i18n/locale/tr/integrations.json | 45 +++++---------
.../dashboard/i18n/locale/tr/login.json | 14 ++---
.../dashboard/i18n/locale/tr/report.json | 2 +
.../dashboard/i18n/locale/tr/settings.json | 14 ++++-
.../dashboard/i18n/locale/tr/signup.json | 12 ++--
.../i18n/locale/uk/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/uk/report.json | 2 +
.../dashboard/i18n/locale/uk/settings.json | 10 +++
.../i18n/locale/ur/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/ur/report.json | 2 +
.../dashboard/i18n/locale/ur/settings.json | 10 +++
.../i18n/locale/ur_IN/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/ur_IN/report.json | 2 +
.../dashboard/i18n/locale/ur_IN/settings.json | 10 +++
.../i18n/locale/vi/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/vi/report.json | 2 +
.../dashboard/i18n/locale/vi/settings.json | 10 +++
.../i18n/locale/zh_CN/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/zh_CN/report.json | 2 +
.../dashboard/i18n/locale/zh_CN/settings.json | 10 +++
.../i18n/locale/zh_TW/integrations.json | 41 +++++-------
.../dashboard/i18n/locale/zh_TW/report.json | 2 +
.../dashboard/i18n/locale/zh_TW/settings.json | 10 +++
config/locales/am.yml | 1 +
config/locales/ar.yml | 1 +
config/locales/az.yml | 1 +
config/locales/bg.yml | 1 +
config/locales/bn.yml | 1 +
config/locales/ca.yml | 1 +
config/locales/cs.yml | 1 +
config/locales/da.yml | 1 +
config/locales/de.yml | 1 +
config/locales/el.yml | 1 +
config/locales/es.yml | 1 +
config/locales/et.yml | 1 +
config/locales/fa.yml | 1 +
config/locales/fi.yml | 1 +
config/locales/fr.yml | 1 +
config/locales/he.yml | 1 +
config/locales/hi.yml | 1 +
config/locales/hr.yml | 1 +
config/locales/hu.yml | 1 +
config/locales/hy.yml | 1 +
config/locales/id.yml | 1 +
config/locales/is.yml | 1 +
config/locales/it.yml | 1 +
config/locales/ja.yml | 1 +
config/locales/ka.yml | 1 +
config/locales/ko.yml | 1 +
config/locales/lt.yml | 1 +
config/locales/lv.yml | 1 +
config/locales/ml.yml | 1 +
config/locales/ms.yml | 1 +
config/locales/ne.yml | 1 +
config/locales/nl.yml | 1 +
config/locales/no.yml | 1 +
config/locales/pl.yml | 1 +
config/locales/pt.yml | 1 +
config/locales/pt_BR.yml | 1 +
config/locales/ro.yml | 1 +
config/locales/ru.yml | 1 +
config/locales/sh.yml | 1 +
config/locales/sk.yml | 1 +
config/locales/sl.yml | 1 +
config/locales/sq.yml | 1 +
config/locales/sr.yml | 1 +
config/locales/sv.yml | 1 +
config/locales/ta.yml | 1 +
config/locales/th.yml | 1 +
config/locales/tl.yml | 1 +
config/locales/tr.yml | 1 +
config/locales/uk.yml | 1 +
config/locales/ur.yml | 1 +
config/locales/ur_IN.yml | 1 +
config/locales/vi.yml | 1 +
config/locales/zh_CN.yml | 1 +
config/locales/zh_TW.yml | 1 +
227 files changed, 1644 insertions(+), 1536 deletions(-)
diff --git a/app/javascript/dashboard/i18n/locale/am/integrations.json b/app/javascript/dashboard/i18n/locale/am/integrations.json
index ccc46ee1d..9500e2fbc 100644
--- a/app/javascript/dashboard/i18n/locale/am/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/am/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Settings",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/am/report.json b/app/javascript/dashboard/i18n/locale/am/report.json
index c622170b0..dbf59f603 100644
--- a/app/javascript/dashboard/i18n/locale/am/report.json
+++ b/app/javascript/dashboard/i18n/locale/am/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Last 7 days",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "Last 30 days",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/am/settings.json b/app/javascript/dashboard/i18n/locale/am/settings.json
index 812b0cd8b..50cf38b58 100644
--- a/app/javascript/dashboard/i18n/locale/am/settings.json
+++ b/app/javascript/dashboard/i18n/locale/am/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Settings",
"HOME": "Home",
"AGENTS": "Agents",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/ar/integrations.json b/app/javascript/dashboard/i18n/locale/ar/integrations.json
index f48d263ac..2145f7701 100644
--- a/app/javascript/dashboard/i18n/locale/ar/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ar/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "رابط Webhook",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "قائد",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "الإعدادات",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/ar/report.json b/app/javascript/dashboard/i18n/locale/ar/report.json
index 8aeb7d9fa..ac8e46365 100644
--- a/app/javascript/dashboard/i18n/locale/ar/report.json
+++ b/app/javascript/dashboard/i18n/locale/ar/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "آخر 7 أيام",
"LAST_14_DAYS": "آخر 14 يوماً",
"LAST_30_DAYS": "آخر 30 يوماً",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "آخر 3 أشهر",
"LAST_6_MONTHS": "آخر 6 أشهر",
"LAST_YEAR": "العام الماضي",
diff --git a/app/javascript/dashboard/i18n/locale/ar/settings.json b/app/javascript/dashboard/i18n/locale/ar/settings.json
index 22b9cb254..fa09f590a 100644
--- a/app/javascript/dashboard/i18n/locale/ar/settings.json
+++ b/app/javascript/dashboard/i18n/locale/ar/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "تم تعليق الحساب",
"MESSAGE": "تم تعليق حسابك. يرجى الاتصال بفريق الدعم للمزيد من المعلومات."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "قنوات التواصل",
+ "CAPTAIN_SETTINGS": "الإعدادات",
"HOME": "الرئيسية",
"AGENTS": "وكيل الدعم",
"AGENT_BOTS": "الروبوتات",
diff --git a/app/javascript/dashboard/i18n/locale/az/integrations.json b/app/javascript/dashboard/i18n/locale/az/integrations.json
index ccc46ee1d..9500e2fbc 100644
--- a/app/javascript/dashboard/i18n/locale/az/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/az/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Settings",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/az/report.json b/app/javascript/dashboard/i18n/locale/az/report.json
index c622170b0..dbf59f603 100644
--- a/app/javascript/dashboard/i18n/locale/az/report.json
+++ b/app/javascript/dashboard/i18n/locale/az/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Last 7 days",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "Last 30 days",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/az/settings.json b/app/javascript/dashboard/i18n/locale/az/settings.json
index 812b0cd8b..50cf38b58 100644
--- a/app/javascript/dashboard/i18n/locale/az/settings.json
+++ b/app/javascript/dashboard/i18n/locale/az/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Settings",
"HOME": "Home",
"AGENTS": "Agents",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/bg/integrations.json b/app/javascript/dashboard/i18n/locale/bg/integrations.json
index 0eddb3a10..8c503eac6 100644
--- a/app/javascript/dashboard/i18n/locale/bg/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/bg/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Settings",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/bg/report.json b/app/javascript/dashboard/i18n/locale/bg/report.json
index 5ba9c2508..fb1f34d3c 100644
--- a/app/javascript/dashboard/i18n/locale/bg/report.json
+++ b/app/javascript/dashboard/i18n/locale/bg/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Last 7 days",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "Last 30 days",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/bg/settings.json b/app/javascript/dashboard/i18n/locale/bg/settings.json
index 7879190b6..3d1cd4fe3 100644
--- a/app/javascript/dashboard/i18n/locale/bg/settings.json
+++ b/app/javascript/dashboard/i18n/locale/bg/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Settings",
"HOME": "Home",
"AGENTS": "Агенти",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/bn/integrations.json b/app/javascript/dashboard/i18n/locale/bn/integrations.json
index ccc46ee1d..9500e2fbc 100644
--- a/app/javascript/dashboard/i18n/locale/bn/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/bn/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Settings",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/bn/report.json b/app/javascript/dashboard/i18n/locale/bn/report.json
index c622170b0..dbf59f603 100644
--- a/app/javascript/dashboard/i18n/locale/bn/report.json
+++ b/app/javascript/dashboard/i18n/locale/bn/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Last 7 days",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "Last 30 days",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/bn/settings.json b/app/javascript/dashboard/i18n/locale/bn/settings.json
index 812b0cd8b..50cf38b58 100644
--- a/app/javascript/dashboard/i18n/locale/bn/settings.json
+++ b/app/javascript/dashboard/i18n/locale/bn/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Settings",
"HOME": "Home",
"AGENTS": "Agents",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/ca/integrations.json b/app/javascript/dashboard/i18n/locale/ca/integrations.json
index d8d32d02c..f24fb0115 100644
--- a/app/javascript/dashboard/i18n/locale/ca/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ca/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "URL del webhook",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Configuracions",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/ca/report.json b/app/javascript/dashboard/i18n/locale/ca/report.json
index 2a3d6cd32..1db2cca6a 100644
--- a/app/javascript/dashboard/i18n/locale/ca/report.json
+++ b/app/javascript/dashboard/i18n/locale/ca/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Últims 7 dies",
"LAST_14_DAYS": "Últims 14 dies",
"LAST_30_DAYS": "Últims 30 dies",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Últims tres mesos",
"LAST_6_MONTHS": "Últims sis mesos",
"LAST_YEAR": "Darrer any",
diff --git a/app/javascript/dashboard/i18n/locale/ca/settings.json b/app/javascript/dashboard/i18n/locale/ca/settings.json
index bf9ec5edc..f46d812c2 100644
--- a/app/javascript/dashboard/i18n/locale/ca/settings.json
+++ b/app/javascript/dashboard/i18n/locale/ca/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Compte suspès",
"MESSAGE": "El teu compte està suspès. Posa't en contacte amb l'equip d'assistència per obtenir més informació."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Safates d'entrada",
+ "CAPTAIN_SETTINGS": "Configuracions",
"HOME": "Inici",
"AGENTS": "Agents",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/cs/integrations.json b/app/javascript/dashboard/i18n/locale/cs/integrations.json
index 73d0c365e..df6e1f936 100644
--- a/app/javascript/dashboard/i18n/locale/cs/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/cs/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "URL webového háčku",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Nastavení",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/cs/report.json b/app/javascript/dashboard/i18n/locale/cs/report.json
index 6cf765f24..2831eeeb0 100644
--- a/app/javascript/dashboard/i18n/locale/cs/report.json
+++ b/app/javascript/dashboard/i18n/locale/cs/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Posledních 7 dní",
"LAST_14_DAYS": "Posledních 14 dní",
"LAST_30_DAYS": "Posledních 30 dní",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Poslední 3 měsíce",
"LAST_6_MONTHS": "Posledních 6 měsíců",
"LAST_YEAR": "Poslední rok",
diff --git a/app/javascript/dashboard/i18n/locale/cs/settings.json b/app/javascript/dashboard/i18n/locale/cs/settings.json
index 616e16942..c6e26c413 100644
--- a/app/javascript/dashboard/i18n/locale/cs/settings.json
+++ b/app/javascript/dashboard/i18n/locale/cs/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Schránky",
+ "CAPTAIN_SETTINGS": "Nastavení",
"HOME": "Domů",
"AGENTS": "Agenti",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/da/integrations.json b/app/javascript/dashboard/i18n/locale/da/integrations.json
index 30847d37d..bee4e7081 100644
--- a/app/javascript/dashboard/i18n/locale/da/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/da/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Indstillinger",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/da/report.json b/app/javascript/dashboard/i18n/locale/da/report.json
index 3b81e2a18..fb93cb681 100644
--- a/app/javascript/dashboard/i18n/locale/da/report.json
+++ b/app/javascript/dashboard/i18n/locale/da/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Seneste 7 dage",
"LAST_14_DAYS": "Seneste 14 dage",
"LAST_30_DAYS": "Seneste 30 dage",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Seneste 3 måneder",
"LAST_6_MONTHS": "Seneste 6 måneder",
"LAST_YEAR": "Sidste år",
diff --git a/app/javascript/dashboard/i18n/locale/da/settings.json b/app/javascript/dashboard/i18n/locale/da/settings.json
index b2db02ef5..02e958cec 100644
--- a/app/javascript/dashboard/i18n/locale/da/settings.json
+++ b/app/javascript/dashboard/i18n/locale/da/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Konto Suspenderet",
"MESSAGE": "Din konto er suspenderet. Gå ud til supportteamet for mere information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Indbakker",
+ "CAPTAIN_SETTINGS": "Indstillinger",
"HOME": "Hjem",
"AGENTS": "Agenter",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/de/contact.json b/app/javascript/dashboard/i18n/locale/de/contact.json
index c13b81468..8907118f6 100644
--- a/app/javascript/dashboard/i18n/locale/de/contact.json
+++ b/app/javascript/dashboard/i18n/locale/de/contact.json
@@ -18,9 +18,9 @@
"CREATED_AT_LABEL": "Erstellt",
"NEW_MESSAGE": "Neue Nachricht",
"CALL": "Anruf",
- "CALL_UNDER_DEVELOPMENT": "Calling is under development",
+ "CALL_UNDER_DEVELOPMENT": "Anrufe sind in der Entwicklung",
"VOICE_INBOX_PICKER": {
- "TITLE": "Choose a voice inbox"
+ "TITLE": "Spracheingang wählen"
},
"CONVERSATIONS": {
"NO_RECORDS_FOUND": "Es sind keine vorherigen Gespräche mit diesem Kontakt verbunden.",
@@ -554,12 +554,12 @@
"WROTE": "schrieb",
"YOU": "Sie",
"SAVE": "Notiz speichern",
- "ADD_NOTE": "Add contact note",
+ "ADD_NOTE": "Füge eine Kontakt-Notiz hinzu",
"EXPAND": "Erweitern",
"COLLAPSE": "Einklappen",
"NO_NOTES": "Keine Notizen, Sie können Notizen auf der Kontakt-Detailseite hinzufügen.",
"EMPTY_STATE": "Es gibt keine Notizen zu diesem Kontakt. Sie können eine Notiz hinzufügen, indem Sie diese in das obige Feld eingeben.",
- "CONVERSATION_EMPTY_STATE": "There are no notes yet. Use the Add note button to create one."
+ "CONVERSATION_EMPTY_STATE": "Es sind noch keine Notizen vorhanden. Benutzen Sie die Schaltfläche \"Notiz hinzufügen\" um eine zu erstellen."
}
},
"EMPTY_STATE": {
@@ -574,21 +574,21 @@
"CONTACTS_BULK_ACTIONS": {
"ASSIGN_LABELS": "Labels zuweisen",
"ASSIGN_LABELS_SUCCESS": "Labels erfolgreich zugewiesen.",
- "ASSIGN_LABELS_FAILED": "Failed to assign labels",
- "DESCRIPTION": "Select the labels you want to add to the selected contacts.",
- "NO_LABELS_FOUND": "No labels available yet.",
+ "ASSIGN_LABELS_FAILED": "Fehler beim Zuweisen der Labels",
+ "DESCRIPTION": "Wählen Sie die Labels aus, die zu den ausgewählten Kontakten hinzugefügt werden sollen.",
+ "NO_LABELS_FOUND": "Noch keine Labels vorhanden.",
"SELECTED_COUNT": "{count} selected",
- "CLEAR_SELECTION": "Clear selection",
- "SELECT_ALL": "Select all ({count})",
+ "CLEAR_SELECTION": "Auswahl löschen",
+ "SELECT_ALL": "Alle auswählen ({count})",
"DELETE_CONTACTS": "Löschen",
- "DELETE_SUCCESS": "Contacts deleted successfully.",
- "DELETE_FAILED": "Failed to delete contacts.",
+ "DELETE_SUCCESS": "Kontakte erfolgreich gelöscht.",
+ "DELETE_FAILED": "Kontakte konnten nicht gelöscht werden.",
"DELETE_DIALOG": {
- "TITLE": "Delete selected contacts",
- "SINGULAR_TITLE": "Delete selected contact",
- "DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
- "SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
- "CONFIRM_MULTIPLE": "Delete contacts",
+ "TITLE": "Ausgewählte Kontakte löschen",
+ "SINGULAR_TITLE": "Ausgewählten Kontakt löschen",
+ "DESCRIPTION": "Dies wird {count} ausgewählte Kontakte dauerhaft löschen. Diese Aktion kann nicht rückgängig gemacht werden.",
+ "SINGULAR_DESCRIPTION": "Der ausgewählte Kontakt wird dauerhaft gelöscht. Diese Aktion kann nicht rückgängig gemacht werden.",
+ "CONFIRM_MULTIPLE": "Kontakte löschen",
"CONFIRM_SINGLE": "Kontakt löschen"
}
},
diff --git a/app/javascript/dashboard/i18n/locale/de/conversation.json b/app/javascript/dashboard/i18n/locale/de/conversation.json
index 56b39edb9..b30f38ebe 100644
--- a/app/javascript/dashboard/i18n/locale/de/conversation.json
+++ b/app/javascript/dashboard/i18n/locale/de/conversation.json
@@ -36,10 +36,10 @@
"NOT_ASSIGNED_TO_YOU": "Diese Konversation ist Ihnen nicht zugeordnet. Möchten Sie dieses Gespräch sich selbst zuordnen?",
"ASSIGN_TO_ME": "Mir zuweisen",
"BOT_HANDOFF_MESSAGE": "Sie antworten auf eine Unterhaltung, die derzeit von einem Assistenten oder einem Bot bearbeitet wird.",
- "BOT_HANDOFF_ACTION": "Mark open and assign to you",
- "BOT_HANDOFF_REOPEN_ACTION": "Mark conversation open",
- "BOT_HANDOFF_SUCCESS": "Conversation has been handed over to you",
- "BOT_HANDOFF_ERROR": "Failed to take over the conversation. Please try again.",
+ "BOT_HANDOFF_ACTION": "Als geöffnet markieren und Ihnen zuweisen",
+ "BOT_HANDOFF_REOPEN_ACTION": "Gespräch als geöffnet markieren",
+ "BOT_HANDOFF_SUCCESS": "Die Unterhaltung wurde dir übergeben",
+ "BOT_HANDOFF_ERROR": "Die Unterhaltung konnte nicht übernommen werden. Bitte versuche es erneut.",
"TWILIO_WHATSAPP_CAN_REPLY": "Sie können auf diese Konversation nur mit einer Nachrichtenvorlage antworten wegen",
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "24-Stunden-Nachrichtenfenster-Beschränkung",
"OLD_INSTAGRAM_INBOX_REPLY_BANNER": "Dieser Instagram-Account wurde in den neuen Instagram-Kanal übertragen. Alle neuen Nachrichten werden dort erscheinen. Sie werden keine Nachrichten mehr von dieser Unterhaltung senden können.",
@@ -72,15 +72,15 @@
"HIDE_LABELS": "Labels ausblenden"
},
"VOICE_CALL": {
- "INCOMING_CALL": "Incoming call",
- "OUTGOING_CALL": "Outgoing call",
- "CALL_IN_PROGRESS": "Call in progress",
- "NO_ANSWER": "No answer",
- "MISSED_CALL": "Missed call",
- "CALL_ENDED": "Call ended",
- "NOT_ANSWERED_YET": "Not answered yet",
- "THEY_ANSWERED": "They answered",
- "YOU_ANSWERED": "You answered"
+ "INCOMING_CALL": "Eingehender Anruf",
+ "OUTGOING_CALL": "Ausgehender Anruf",
+ "CALL_IN_PROGRESS": "Anruf läuft",
+ "NO_ANSWER": "Keine Antwort",
+ "MISSED_CALL": "Entgangener Anruf",
+ "CALL_ENDED": "Anruf beendet",
+ "NOT_ANSWERED_YET": "Noch nicht beantwortet",
+ "THEY_ANSWERED": "Sie antworteten",
+ "YOU_ANSWERED": "Sie haben beantwortet"
},
"HEADER": {
"RESOLVE_ACTION": "Fall schließen",
@@ -160,9 +160,9 @@
"AGENTS_LOADING": "Agenten werden geladen...",
"ASSIGN_TEAM": "Team zuweisen",
"DELETE": "Unterhaltung löschen",
- "OPEN_IN_NEW_TAB": "Open in new tab",
- "COPY_LINK": "Copy conversation link",
- "COPY_LINK_SUCCESS": "Conversation link copied to clipboard",
+ "OPEN_IN_NEW_TAB": "In neuem Tab öffnen",
+ "COPY_LINK": "Konversationslink kopieren",
+ "COPY_LINK_SUCCESS": "Konversationslink in Zwischenablage kopiert",
"API": {
"AGENT_ASSIGNMENT": {
"SUCCESFUL": "Konversations-ID {conversationId} zugewiesen zu \"{agentName}\"",
@@ -229,11 +229,11 @@
}
},
"QUOTED_REPLY": {
- "ENABLE_TOOLTIP": "Include quoted email thread",
- "DISABLE_TOOLTIP": "Don't include quoted email thread",
- "REMOVE_PREVIEW": "Remove quoted email thread",
- "COLLAPSE": "Collapse preview",
- "EXPAND": "Expand preview"
+ "ENABLE_TOOLTIP": "Zitierten E-Mail-Thread einbeziehen",
+ "DISABLE_TOOLTIP": "Zitierten E-Mail-Thread nicht einbeziehen",
+ "REMOVE_PREVIEW": "Zitierte E-Mail-Themen entfernen",
+ "COLLAPSE": "Vorschau ausblenden",
+ "EXPAND": "Vorschau erweitern"
}
},
"VISIBLE_TO_AGENTS": "Privater Hinweis: Nur für Sie und Ihr Team sichtbar",
@@ -338,7 +338,7 @@
"CONTACT_ATTRIBUTES": "Kontakt-Attribute",
"PREVIOUS_CONVERSATION": "Vorherige Konversationen",
"MACROS": "Makros",
- "LINEAR_ISSUES": "Linked Linear Issues",
+ "LINEAR_ISSUES": "Verknüpfte lineare Probleme",
"SHOPIFY_ORDERS": "Shopify Orders"
},
"SHOPIFY": {
diff --git a/app/javascript/dashboard/i18n/locale/de/generalSettings.json b/app/javascript/dashboard/i18n/locale/de/generalSettings.json
index bf67ac1b0..33c2c2843 100644
--- a/app/javascript/dashboard/i18n/locale/de/generalSettings.json
+++ b/app/javascript/dashboard/i18n/locale/de/generalSettings.json
@@ -3,7 +3,7 @@
"LIMIT_MESSAGES": {
"CONVERSATION": "Sie haben das Konversationslimit überschritten. Der Hacker Plan erlaubt nur 500 Unterhaltungen.",
"INBOXES": "Sie haben das Posteingang-Limit überschritten. Der Hacker-Plan unterstützt nur Live-Chat der Webseite. Zusätzliche Posteingänge wie E-Mail, WhatsApp usw. erfordern einen kostenpflichtigen Tarif.",
- "AGENTS": "You have exceeded the agent limit. Your plan only allows {allowedAgents} agents.",
+ "AGENTS": "Sie haben das Agenten-Limit überschritten. Ihr Plan erlaubt nur {allowedAgents} Agenten.",
"NON_ADMIN": "Bitte kontaktieren Sie Ihren Administrator, um den Plan zu upgraden und alle Funktionen weiterzunutzen."
},
"TITLE": "Kontoeinstellungen",
@@ -25,13 +25,13 @@
"DISMISS": "Stornieren",
"PLACE_HOLDER": "Bitte {accountName} zur Bestätigung eingeben"
},
- "SUCCESS": "Account marked for deletion",
- "FAILURE": "Could not delete account, try again!",
+ "SUCCESS": "Konto zur Löschung markiert",
+ "FAILURE": "Konto konnte nicht gelöscht werden, versuche es erneut!",
"SCHEDULED_DELETION": {
- "TITLE": "Account Scheduled for Deletion",
- "MESSAGE_MANUAL": "This account is scheduled for deletion on {deletionDate}. This was requested by an administrator. You can cancel the deletion before this date.",
- "MESSAGE_INACTIVITY": "This account is scheduled for deletion on {deletionDate} due to account inactivity. You can cancel the deletion before this date.",
- "CLEAR_BUTTON": "Cancel Scheduled Deletion"
+ "TITLE": "Konto für Löschung geplant",
+ "MESSAGE_MANUAL": "Dieses Konto ist für das Löschen auf {deletionDate} geplant. Dies wurde von einem Administrator angefordert. Sie können das Löschen vor diesem Datum abbrechen.",
+ "MESSAGE_INACTIVITY": "Dieses Konto ist für die Löschung auf {deletionDate} aufgrund von Kontoinaktivität vorgesehen. Sie können die Löschung vor diesem Datum abbrechen.",
+ "CLEAR_BUTTON": "Geplante Löschung abbrechen"
}
},
"FORM": {
@@ -45,13 +45,13 @@
"NOTE": "Diese ID ist erforderlich, wenn Sie eine API-basierte Integration erstellen"
},
"AUTO_RESOLVE": {
- "TITLE": "Auto-resolve conversations",
- "NOTE": "This configuration would allow you to automatically resolve the conversation after a certain period of inactivity.",
+ "TITLE": "Unterhaltungen automatisch auflösen",
+ "NOTE": "Diese Konfiguration würde es Ihnen ermöglichen, die Unterhaltung nach einer gewissen Zeit der Inaktivität automatisch zu beenden.",
"DURATION": {
- "LABEL": "Inactivity duration",
- "HELP": "Time period of inactivity after which conversation is auto-resolved",
+ "LABEL": "Dauer der Inaktivität",
+ "HELP": "Zeit der Inaktivität, nach der die Unterhaltung automatisch gelöst wird",
"PLACEHOLDER": "30",
- "ERROR": "Auto resolve duration should be between 10 minutes and 999 days",
+ "ERROR": "Automatische Auflösungsdauer sollte zwischen 10 Minuten und 999 Tagen liegen",
"API": {
"SUCCESS": "Auto resolve settings updated successfully",
"ERROR": "Failed to update auto resolve settings"
@@ -108,7 +108,7 @@
"LABEL": "Inactivity duration for resolution",
"HELP": "Duration after a conversation should auto resolve if there is no activity",
"PLACEHOLDER": "30",
- "ERROR": "Auto resolve duration should be between 10 minutes and 999 days",
+ "ERROR": "Automatische Auflösungsdauer sollte zwischen 10 Minuten und 999 Tagen liegen",
"API": {
"SUCCESS": "Auto resolve settings updated successfully",
"ERROR": "Failed to update auto resolve settings"
diff --git a/app/javascript/dashboard/i18n/locale/de/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/de/inboxMgmt.json
index 1b23f7613..fe86cc204 100644
--- a/app/javascript/dashboard/i18n/locale/de/inboxMgmt.json
+++ b/app/javascript/dashboard/i18n/locale/de/inboxMgmt.json
@@ -296,17 +296,17 @@
"WAITING_FOR_AUTH": "Waiting for authentication...",
"INVALID_BUSINESS_DATA": "Invalid business data received from Facebook. Please try again.",
"SIGNUP_ERROR": "Signup error occurred",
- "AUTH_NOT_COMPLETED": "Authentication not completed. Please restart the process.",
- "SUCCESS_FALLBACK": "WhatsApp Business Account has been successfully configured",
- "MANUAL_FALLBACK": "If your number is already connected to the WhatsApp Business Platform (API), or if you’re a tech provider onboarding your own number, please use the {link} flow",
- "MANUAL_LINK_TEXT": "manual setup flow"
+ "AUTH_NOT_COMPLETED": "Authentifizierung nicht abgeschlossen. Bitte starte den Prozess neu.",
+ "SUCCESS_FALLBACK": "WhatsApp Business Account wurde erfolgreich konfiguriert",
+ "MANUAL_FALLBACK": "Wenn Ihre Nummer bereits mit der WhatsApp Business Plattform (API) verbunden ist, oder wenn Sie als Technologieanbieter Ihre eigene Nummer an Bord haben, verwenden Sie bitte den {link} Flow",
+ "MANUAL_LINK_TEXT": "Manueller Einrichtungsablauf"
},
"API": {
"ERROR_MESSAGE": "Wir konnten den WhatsApp-Kanal nicht speichern"
}
},
"VOICE": {
- "TITLE": "Voice Channel",
+ "TITLE": "Sprachkanal",
"DESC": "Integrate Twilio Voice and start supporting your customers via phone calls.",
"PHONE_NUMBER": {
"LABEL": "Telefonnummer",
diff --git a/app/javascript/dashboard/i18n/locale/de/integrations.json b/app/javascript/dashboard/i18n/locale/de/integrations.json
index 5186b9f63..bf4d70074 100644
--- a/app/javascript/dashboard/i18n/locale/de/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/de/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook-URL",
"PLACEHOLDER": "Beispiel: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Kapitän",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Probiere diese Prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Einstellungen",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/de/report.json b/app/javascript/dashboard/i18n/locale/de/report.json
index 820676f3f..b61ce23eb 100644
--- a/app/javascript/dashboard/i18n/locale/de/report.json
+++ b/app/javascript/dashboard/i18n/locale/de/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Letzten 7 Tage",
"LAST_14_DAYS": "Letzten 14 Tage",
"LAST_30_DAYS": "Letzte 30 Tage",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Die letzten 3 Monate",
"LAST_6_MONTHS": "Die letzten 6 Monate",
"LAST_YEAR": "Letztes Jahr",
diff --git a/app/javascript/dashboard/i18n/locale/de/settings.json b/app/javascript/dashboard/i18n/locale/de/settings.json
index 190880321..50e1cf7a5 100644
--- a/app/javascript/dashboard/i18n/locale/de/settings.json
+++ b/app/javascript/dashboard/i18n/locale/de/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Konto gesperrt",
"MESSAGE": "Ihr Account wurde gesperrt. Wenden Sie sich für weitere Informationen bitte an das Support-Team."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Posteingänge",
+ "CAPTAIN_SETTINGS": "Einstellungen",
"HOME": "Hauptseite",
"AGENTS": "Agenten",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/el/integrations.json b/app/javascript/dashboard/i18n/locale/el/integrations.json
index ab132c61e..67ca0056e 100644
--- a/app/javascript/dashboard/i18n/locale/el/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/el/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Σύνδεσμος Webhook",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Ρυθμίσεις",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/el/report.json b/app/javascript/dashboard/i18n/locale/el/report.json
index c050a93c9..aa2a68208 100644
--- a/app/javascript/dashboard/i18n/locale/el/report.json
+++ b/app/javascript/dashboard/i18n/locale/el/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Τελευταίες 7 ημέρες",
"LAST_14_DAYS": "Τελευταίες 14 ημέρες",
"LAST_30_DAYS": "Τελευταίες 30 ημέρες",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Τελευταίοι 3 μήνες",
"LAST_6_MONTHS": "Τελευταίοι 6 μήνες",
"LAST_YEAR": "Τελευταίο έτος",
diff --git a/app/javascript/dashboard/i18n/locale/el/settings.json b/app/javascript/dashboard/i18n/locale/el/settings.json
index da4c4dec5..2e8026e32 100644
--- a/app/javascript/dashboard/i18n/locale/el/settings.json
+++ b/app/javascript/dashboard/i18n/locale/el/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Αναστολή Λογαριασμού",
"MESSAGE": "Ο λογαριασμός σας έχει ανασταλεί. Επικοινωνήστε με την ομάδα υποστήριξης για περισσότερες πληροφορίες."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Κιβώτια Εισερχομένων",
+ "CAPTAIN_SETTINGS": "Ρυθμίσεις",
"HOME": "Αρχική",
"AGENTS": "Πράκτορες",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/es/integrations.json b/app/javascript/dashboard/i18n/locale/es/integrations.json
index ed03df719..d8306bd80 100644
--- a/app/javascript/dashboard/i18n/locale/es/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/es/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "URL de Webhook",
"PLACEHOLDER": "Ejemplo: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Capitán",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Prueba estas sugerencias",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Ajustes",
"BASIC_SETTINGS": {
"TITLE": "Configuraciones básicas",
"DESCRIPTION": ""
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/es/report.json b/app/javascript/dashboard/i18n/locale/es/report.json
index 1db50b270..9302dd634 100644
--- a/app/javascript/dashboard/i18n/locale/es/report.json
+++ b/app/javascript/dashboard/i18n/locale/es/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Últimos 7 días",
"LAST_14_DAYS": "Últimos 14 días",
"LAST_30_DAYS": "Últimos 30 días",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Últimos 3 meses",
"LAST_6_MONTHS": "Últimos 6 meses",
"LAST_YEAR": "Último año",
diff --git a/app/javascript/dashboard/i18n/locale/es/settings.json b/app/javascript/dashboard/i18n/locale/es/settings.json
index 37a1bfda4..d3d580143 100644
--- a/app/javascript/dashboard/i18n/locale/es/settings.json
+++ b/app/javascript/dashboard/i18n/locale/es/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Cuenta suspendida",
"MESSAGE": "Tu cuenta está suspendida. Comuníquese con el equipo de soporte para obtener más información."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Cerrar sesión"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documentos",
"CAPTAIN_RESPONSES": "Preguntas frecuentes",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Entradas",
+ "CAPTAIN_SETTINGS": "Ajustes",
"HOME": "Inicio",
"AGENTS": "Agentes",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/et/integrations.json b/app/javascript/dashboard/i18n/locale/et/integrations.json
index ccc46ee1d..9500e2fbc 100644
--- a/app/javascript/dashboard/i18n/locale/et/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/et/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Settings",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/et/report.json b/app/javascript/dashboard/i18n/locale/et/report.json
index c622170b0..dbf59f603 100644
--- a/app/javascript/dashboard/i18n/locale/et/report.json
+++ b/app/javascript/dashboard/i18n/locale/et/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Last 7 days",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "Last 30 days",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/et/settings.json b/app/javascript/dashboard/i18n/locale/et/settings.json
index 812b0cd8b..50cf38b58 100644
--- a/app/javascript/dashboard/i18n/locale/et/settings.json
+++ b/app/javascript/dashboard/i18n/locale/et/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Settings",
"HOME": "Home",
"AGENTS": "Agents",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/fa/integrations.json b/app/javascript/dashboard/i18n/locale/fa/integrations.json
index 6c6be064f..e635d491f 100644
--- a/app/javascript/dashboard/i18n/locale/fa/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/fa/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "آدرس URL وب هوک",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "تنظیمات",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/fa/report.json b/app/javascript/dashboard/i18n/locale/fa/report.json
index f979b1b48..9596444e1 100644
--- a/app/javascript/dashboard/i18n/locale/fa/report.json
+++ b/app/javascript/dashboard/i18n/locale/fa/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "در ۷ روز گذشته",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "در ۳۰ روز گذشته",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "۳ ماه گذشته",
"LAST_6_MONTHS": "۶ ماه گذشته",
"LAST_YEAR": "پارسال",
diff --git a/app/javascript/dashboard/i18n/locale/fa/settings.json b/app/javascript/dashboard/i18n/locale/fa/settings.json
index ae309c5bc..4c989b0fa 100644
--- a/app/javascript/dashboard/i18n/locale/fa/settings.json
+++ b/app/javascript/dashboard/i18n/locale/fa/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "حسابکاربری معلق شده است",
"MESSAGE": "حسابکاربری شما به حالت تعلیق درآمده. لطفا برای اطلاعات بیشتر با تیم پشتیبانی تماس بگیرید."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "صندوقهای ورودی",
+ "CAPTAIN_SETTINGS": "تنظیمات",
"HOME": "صفحه اصلی",
"AGENTS": "ایجنت ها",
"AGENT_BOTS": "رباتها",
diff --git a/app/javascript/dashboard/i18n/locale/fi/integrations.json b/app/javascript/dashboard/i18n/locale/fi/integrations.json
index dda703541..f17f88ecd 100644
--- a/app/javascript/dashboard/i18n/locale/fi/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/fi/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhookin URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Asetukset",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/fi/report.json b/app/javascript/dashboard/i18n/locale/fi/report.json
index fc442d094..22db228b2 100644
--- a/app/javascript/dashboard/i18n/locale/fi/report.json
+++ b/app/javascript/dashboard/i18n/locale/fi/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Viimeiset 7 päivää",
"LAST_14_DAYS": "Viimeiset 14 päivää",
"LAST_30_DAYS": "Viimeiset 30 päivää",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/fi/settings.json b/app/javascript/dashboard/i18n/locale/fi/settings.json
index 3fbcfe345..69cd048e1 100644
--- a/app/javascript/dashboard/i18n/locale/fi/settings.json
+++ b/app/javascript/dashboard/i18n/locale/fi/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Saapuneet-kansiot",
+ "CAPTAIN_SETTINGS": "Asetukset",
"HOME": "Koti",
"AGENTS": "Edustajat",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/fr/integrations.json b/app/javascript/dashboard/i18n/locale/fr/integrations.json
index 1c0ed950d..5a9e549a4 100644
--- a/app/javascript/dashboard/i18n/locale/fr/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/fr/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Saisie de conversation désactivée"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "URL du Webhook",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Impossible de trouver l'assistant. Veuillez réessayer."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Paramètres",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/fr/report.json b/app/javascript/dashboard/i18n/locale/fr/report.json
index 684e4d197..5c41536e9 100644
--- a/app/javascript/dashboard/i18n/locale/fr/report.json
+++ b/app/javascript/dashboard/i18n/locale/fr/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "7 derniers jours",
"LAST_14_DAYS": "14 derniers jours",
"LAST_30_DAYS": "30 derniers jours",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "3 derniers mois",
"LAST_6_MONTHS": "6 derniers mois",
"LAST_YEAR": "Année dernière",
diff --git a/app/javascript/dashboard/i18n/locale/fr/settings.json b/app/javascript/dashboard/i18n/locale/fr/settings.json
index f04045ea6..66d7cefba 100644
--- a/app/javascript/dashboard/i18n/locale/fr/settings.json
+++ b/app/javascript/dashboard/i18n/locale/fr/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Compte Suspendu",
"MESSAGE": "Votre compte est suspendu. Veuillez contacter le support pour plus d'informations."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Outils",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Terrain de jeu",
+ "CAPTAIN_INBOXES": "Boîtes de réception",
+ "CAPTAIN_SETTINGS": "Paramètres",
"HOME": "Accueil",
"AGENTS": "Agents",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/he/integrations.json b/app/javascript/dashboard/i18n/locale/he/integrations.json
index e28279a74..843c6360b 100644
--- a/app/javascript/dashboard/i18n/locale/he/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/he/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "כתובת אתר של Webhook",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "טייס משנה",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "הגדרות",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/he/report.json b/app/javascript/dashboard/i18n/locale/he/report.json
index c342d4649..6c84b77a1 100644
--- a/app/javascript/dashboard/i18n/locale/he/report.json
+++ b/app/javascript/dashboard/i18n/locale/he/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "7 הימים האחרונים",
"LAST_14_DAYS": "14 הימים האחרונים",
"LAST_30_DAYS": "30 הימים האחרונים",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "3 החודשים האחרונים",
"LAST_6_MONTHS": "6 החודשים האחרונים",
"LAST_YEAR": "שנה שעברה",
diff --git a/app/javascript/dashboard/i18n/locale/he/settings.json b/app/javascript/dashboard/i18n/locale/he/settings.json
index 1601016eb..44c077268 100644
--- a/app/javascript/dashboard/i18n/locale/he/settings.json
+++ b/app/javascript/dashboard/i18n/locale/he/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "חשבון מושעה",
"MESSAGE": "החשבון שלך מושעה. אנא פנה לצוות התמיכה לקבלת מידע נוסף."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "תיבות דואר נכנס",
+ "CAPTAIN_SETTINGS": "הגדרות",
"HOME": "בית",
"AGENTS": "סוכנים",
"AGENT_BOTS": "בוטים",
diff --git a/app/javascript/dashboard/i18n/locale/hi/integrations.json b/app/javascript/dashboard/i18n/locale/hi/integrations.json
index 4ce9d2077..c39ce064c 100644
--- a/app/javascript/dashboard/i18n/locale/hi/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/hi/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Settings",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/hi/report.json b/app/javascript/dashboard/i18n/locale/hi/report.json
index 22e285c19..a2ad6bd4a 100644
--- a/app/javascript/dashboard/i18n/locale/hi/report.json
+++ b/app/javascript/dashboard/i18n/locale/hi/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Last 7 days",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "Last 30 days",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/hi/settings.json b/app/javascript/dashboard/i18n/locale/hi/settings.json
index 256f77c04..aec3e852d 100644
--- a/app/javascript/dashboard/i18n/locale/hi/settings.json
+++ b/app/javascript/dashboard/i18n/locale/hi/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Settings",
"HOME": "Home",
"AGENTS": "Agents",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/hr/integrations.json b/app/javascript/dashboard/i18n/locale/hr/integrations.json
index 505226f13..472e5fd69 100644
--- a/app/javascript/dashboard/i18n/locale/hr/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/hr/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Settings",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/hr/report.json b/app/javascript/dashboard/i18n/locale/hr/report.json
index 727964e50..c31c93369 100644
--- a/app/javascript/dashboard/i18n/locale/hr/report.json
+++ b/app/javascript/dashboard/i18n/locale/hr/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Last 7 days",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "Last 30 days",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/hr/settings.json b/app/javascript/dashboard/i18n/locale/hr/settings.json
index 51e35e25b..721a1aecc 100644
--- a/app/javascript/dashboard/i18n/locale/hr/settings.json
+++ b/app/javascript/dashboard/i18n/locale/hr/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Settings",
"HOME": "Home",
"AGENTS": "Agenti",
"AGENT_BOTS": "Botovi",
diff --git a/app/javascript/dashboard/i18n/locale/hu/integrations.json b/app/javascript/dashboard/i18n/locale/hu/integrations.json
index 090dc241e..a6a0654fb 100644
--- a/app/javascript/dashboard/i18n/locale/hu/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/hu/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Beállítások",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/hu/report.json b/app/javascript/dashboard/i18n/locale/hu/report.json
index 1231d8d90..45e014b95 100644
--- a/app/javascript/dashboard/i18n/locale/hu/report.json
+++ b/app/javascript/dashboard/i18n/locale/hu/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Utolsó 7 nap",
"LAST_14_DAYS": "Utolsó 14 nap",
"LAST_30_DAYS": "Utolsó 30 nap",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Elmúlt 3 hónapban",
"LAST_6_MONTHS": "Elmúlt 6 hónapban",
"LAST_YEAR": "Elmúlt 1 évben",
diff --git a/app/javascript/dashboard/i18n/locale/hu/settings.json b/app/javascript/dashboard/i18n/locale/hu/settings.json
index 0bda60edd..5228bdc84 100644
--- a/app/javascript/dashboard/i18n/locale/hu/settings.json
+++ b/app/javascript/dashboard/i18n/locale/hu/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Felfüggesztett Fiók",
"MESSAGE": "A fiókod felfüggesztés alatt van. Bővebb információkért, kérlek, lépj kapcsolatba az ügfyélszolgálattal."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Fiókok",
+ "CAPTAIN_SETTINGS": "Beállítások",
"HOME": "Nyitólap",
"AGENTS": "Ügynökök",
"AGENT_BOTS": "Botok",
diff --git a/app/javascript/dashboard/i18n/locale/hy/integrations.json b/app/javascript/dashboard/i18n/locale/hy/integrations.json
index c5b554ee7..0566abd9a 100644
--- a/app/javascript/dashboard/i18n/locale/hy/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/hy/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Settings",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/hy/report.json b/app/javascript/dashboard/i18n/locale/hy/report.json
index 22e285c19..a2ad6bd4a 100644
--- a/app/javascript/dashboard/i18n/locale/hy/report.json
+++ b/app/javascript/dashboard/i18n/locale/hy/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Last 7 days",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "Last 30 days",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/hy/settings.json b/app/javascript/dashboard/i18n/locale/hy/settings.json
index 812b0cd8b..50cf38b58 100644
--- a/app/javascript/dashboard/i18n/locale/hy/settings.json
+++ b/app/javascript/dashboard/i18n/locale/hy/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Settings",
"HOME": "Home",
"AGENTS": "Agents",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/id/integrations.json b/app/javascript/dashboard/i18n/locale/id/integrations.json
index 725743dad..ce14316bb 100644
--- a/app/javascript/dashboard/i18n/locale/id/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/id/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "URL Webhook",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Pengaturan",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/id/report.json b/app/javascript/dashboard/i18n/locale/id/report.json
index e41778480..35393f1da 100644
--- a/app/javascript/dashboard/i18n/locale/id/report.json
+++ b/app/javascript/dashboard/i18n/locale/id/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "7 hari terakhir",
"LAST_14_DAYS": "14 hari terakhir",
"LAST_30_DAYS": "30 hari terakhir",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "3 bulan terakhir",
"LAST_6_MONTHS": "6 bulan terakhir",
"LAST_YEAR": "Tahun terakhir",
diff --git a/app/javascript/dashboard/i18n/locale/id/settings.json b/app/javascript/dashboard/i18n/locale/id/settings.json
index 75324f02f..aad964a87 100644
--- a/app/javascript/dashboard/i18n/locale/id/settings.json
+++ b/app/javascript/dashboard/i18n/locale/id/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Akun Ditangguhkan",
"MESSAGE": "Akun Anda ditangguhkan. Silakan hubungi tim dukungan untuk informasi lebih lanjut."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Kotak masuk",
+ "CAPTAIN_SETTINGS": "Pengaturan",
"HOME": "Beranda",
"AGENTS": "Agen",
"AGENT_BOTS": "Bot Agen",
diff --git a/app/javascript/dashboard/i18n/locale/is/integrations.json b/app/javascript/dashboard/i18n/locale/is/integrations.json
index d349fd38a..100ab01e9 100644
--- a/app/javascript/dashboard/i18n/locale/is/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/is/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Stillingar",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/is/report.json b/app/javascript/dashboard/i18n/locale/is/report.json
index d65764ba5..923b60935 100644
--- a/app/javascript/dashboard/i18n/locale/is/report.json
+++ b/app/javascript/dashboard/i18n/locale/is/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Síðustu 7 daga",
"LAST_14_DAYS": "Síðustu 14 daga",
"LAST_30_DAYS": "Síðustu 30 daga",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Síðustu 3 mánuði",
"LAST_6_MONTHS": "Síðustu 6 mánuði",
"LAST_YEAR": "Síðasta ár",
diff --git a/app/javascript/dashboard/i18n/locale/is/settings.json b/app/javascript/dashboard/i18n/locale/is/settings.json
index 076f19542..cba19a2b0 100644
--- a/app/javascript/dashboard/i18n/locale/is/settings.json
+++ b/app/javascript/dashboard/i18n/locale/is/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Reikningnum þínum er lokað. Vinsamlegast hafðu samband við þjónustusviðið okkar til að fá frekari upplýsingar."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Innhólf",
+ "CAPTAIN_SETTINGS": "Stillingar",
"HOME": "Home",
"AGENTS": "Þjónustufulltrúar",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/it/conversation.json b/app/javascript/dashboard/i18n/locale/it/conversation.json
index 89b4e0b4f..4506fe827 100644
--- a/app/javascript/dashboard/i18n/locale/it/conversation.json
+++ b/app/javascript/dashboard/i18n/locale/it/conversation.json
@@ -85,7 +85,7 @@
"HEADER": {
"RESOLVE_ACTION": "Risolvi",
"REOPEN_ACTION": "Riapri",
- "OPEN_ACTION": "Aperte",
+ "OPEN_ACTION": "Apri",
"MORE_ACTIONS": "Più azioni",
"OPEN": "Altro",
"CLOSE": "Chiudi",
@@ -208,7 +208,7 @@
"": "",
"EMAIL_HEAD": {
"TO": "A",
- "ADD_BCC": "Aggiungi Bcc",
+ "ADD_BCC": "Aggiungi Ccn",
"CC": {
"LABEL": "Cc",
"PLACEHOLDER": "Email separate da virgole",
@@ -296,7 +296,7 @@
},
"ONBOARDING": {
"TITLE": "Ciao👋 Benvenuto in {installationName}!",
- "DESCRIPTION": "Grazie per esserti registrato. Vogliamo che tu ottenga il massimo da {installationName}. Ecco alcune cose che puoi fare in {installationName} per rendere l'esperienza migliore.",
+ "DESCRIPTION": "Grazie per averci scelto! Vogliamo che tu ottenga il massimo da {installationName}. Ecco alcune cose che puoi fare in {installationName} per massimizzare la tua esperienza.",
"GREETING_MORNING": "👋 Buongiorno, {name}. Benvenuto in {installationName}.",
"GREETING_AFTERNOON": "👋 Buon pomeriggio, {name}. Benvenuto in {installationName}.",
"GREETING_EVENING": "👋 Buona sera, {name}. Benvenuto su {installationName}.",
diff --git a/app/javascript/dashboard/i18n/locale/it/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/it/inboxMgmt.json
index 63bd21067..1b98fb807 100644
--- a/app/javascript/dashboard/i18n/locale/it/inboxMgmt.json
+++ b/app/javascript/dashboard/i18n/locale/it/inboxMgmt.json
@@ -86,7 +86,7 @@
},
"CHANNEL_WELCOME_TAGLINE": {
"LABEL": "Titolo di benvenuto",
- "PLACEHOLDER": "Rendiamo semplice connetterci con noi. Chiedete qualsiasi cosa o condividete il vostro feedback."
+ "PLACEHOLDER": "Siamo qui per aiutarti. Facci una domanda o condividi il tuo feedback."
},
"CHANNEL_GREETING_MESSAGE": {
"LABEL": "Messaggio di saluto del canale",
@@ -523,8 +523,8 @@
"FINISH": {
"TITLE": "L'Inbox è pronta!",
"MESSAGE": "Ora puoi interagire con i tuoi clienti attraverso il nuovo canale. Buona assistenza",
- "BUTTON_TEXT": "Portami lì",
- "MORE_SETTINGS": "Altre impostazioni",
+ "BUTTON_TEXT": "Fatto",
+ "MORE_SETTINGS": "Impostazioni Aggiuntive",
"WEBSITE_SUCCESS": "Hai completato la creazione di un canale sito web. Copia il codice mostrato qui sotto e incollalo sul tuo sito. La prossima volta che un cliente usa la live chat, la conversazione apparirà automaticamente nella tua inbox.",
"WHATSAPP_QR_INSTRUCTION": "Scansiona il QR Code qui sopra per testare rapidamente la tua Inbox WhatsApp",
"MESSENGER_QR_INSTRUCTION": "Scansiona il QR Code qui sopra per testare rapidamente la tua Inbox Facebook Messenger",
@@ -918,7 +918,7 @@
},
"WELCOME_TAGLINE": {
"LABEL": "Titolo di benvenuto",
- "PLACE_HOLDER": "Rendiamo semplice connetterci con noi. Chiedete qualsiasi cosa o condividete il vostro feedback."
+ "PLACE_HOLDER": "Siamo qui per aiutarti. Facci una domanda o condividi il tuo feedback."
},
"REPLY_TIME": {
"LABEL": "Tempo di risposta",
diff --git a/app/javascript/dashboard/i18n/locale/it/integrations.json b/app/javascript/dashboard/i18n/locale/it/integrations.json
index 334ee8889..804385262 100644
--- a/app/javascript/dashboard/i18n/locale/it/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/it/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Digitazione conversazione disattiva"
}
},
+ "NAME": {
+ "LABEL": "Nome Webhook",
+ "PLACEHOLDER": "Inserisci un nome per il webhook"
+ },
"END_POINT": {
"LABEL": "URL del webhook",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Scopri di più",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistenti",
+ "SWITCH_ASSISTANT": "Cambia assistenti",
+ "NEW_ASSISTANT": "Crea Assistente"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Prova questi prompt",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Impossibile trovare l'assistente. Riprova."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistente"
- },
+ "HEADER": "Impostazioni",
"BASIC_SETTINGS": {
"TITLE": "Impostazioni di base",
"DESCRIPTION": "Personalizza ciò che l'assistente dice quando termina una conversazione o la trasferisce a un umano."
@@ -502,15 +509,16 @@
"TITLE": "Guardrail",
"DESCRIPTION": "Mantieni l’assistente concentrato: risponde solo ai tipi di domande che desideri, evitando argomenti fuori tema o non consentiti."
},
- "SCENARIOS": {
- "TITLE": "Scenari",
- "DESCRIPTION": "Fornisci contesto aggiuntivo al tuo assistente, ad esempio “cosa fare quando un utente è bloccato” o “come comportarsi durante una richiesta di rimborso”."
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Linee guida per le risposte",
"DESCRIPTION": "Imposta il tono e la struttura delle risposte del tuo assistente: chiare e amichevoli? Brevi e dirette? Dettagliate e formali?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Elimina Assistente",
+ "DESCRIPTION": "Questa azione è permanente. L'eliminazione di questo assistente la rimuoverà da tutte le inbox connesse e cancellerà definitivamente tutte le knowledge generate.",
+ "BUTTON_TEXT": "Elimina {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrail",
"DESCRIPTION": "Mantieni l’assistente concentrato: risponde solo ai tipi di domande che desideri, evitando argomenti fuori tema o non consentiti.",
- "BREADCRUMB": {
- "TITLE": "Guardrail"
- },
"BULK_ACTION": {
"SELECTED": "{count} elemento selezionato | {count} elementi selezionati",
"SELECT_ALL": "Seleziona tutto ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Linee Guida per le Risposte",
"DESCRIPTION": "Imposta il tono e la struttura delle risposte del tuo assistente: chiare e amichevoli? Brevi e dirette? Dettagliate e formali?",
- "BREADCRUMB": {
- "TITLE": "Linee Guida per le Risposte"
- },
"BULK_ACTION": {
"SELECTED": "{count} elemento selezionato | {count} elementi selezionati",
"SELECT_ALL": "Seleziona tutto ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenari",
"DESCRIPTION": "Fornisci contesto aggiuntivo al tuo assistente, ad esempio “cosa fare quando un utente è bloccato” o “come comportarsi durante una richiesta di rimborso”.",
- "BREADCRUMB": {
- "TITLE": "Scenari"
- },
"BULK_ACTION": {
"SELECTED": "{count} elemento selezionato | {count} elementi selezionati",
"SELECT_ALL": "Seleziona tutto ({count})",
@@ -691,17 +690,17 @@
}
},
"DOCUMENTS": {
- "HEADER": "Documents",
- "ADD_NEW": "Create a new document",
+ "HEADER": "Documenti",
+ "ADD_NEW": "Crea un nuovo documento",
"RELATED_RESPONSES": {
"TITLE": "FAQ Correlate",
"DESCRIPTION": "Queste FAQ vengono generate direttamente dai Documenti."
},
- "FORM_DESCRIPTION": "Enter the URL of the document to add it as a knowledge source and choose the assistant to associate it with.",
+ "FORM_DESCRIPTION": "Inserisci l'URL del documento per aggiungerlo come fonte e scegli l'assistente con cui associarlo.",
"CREATE": {
- "TITLE": "Add a document",
- "SUCCESS_MESSAGE": "The document has been successfully created",
- "ERROR_MESSAGE": "There was an error creating the document, please try again."
+ "TITLE": "Aggiungi un documento",
+ "SUCCESS_MESSAGE": "Il documento è stato creato correttamente",
+ "ERROR_MESSAGE": "Si è verificato un errore durante la creazione del documento, riprova."
},
"FORM": {
"TYPE": {
@@ -711,8 +710,8 @@
},
"URL": {
"LABEL": "URL",
- "PLACEHOLDER": "Enter the URL of the document",
- "ERROR": "Please provide a valid URL for the document"
+ "PLACEHOLDER": "Inserisci l'URL del documento",
+ "ERROR": "Inserisci un URL valido per il documento"
},
"PDF_FILE": {
"LABEL": "File PDF",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Nome Documento (Opzionale)",
"PLACEHOLDER": "Inserisci un nome per il documento"
- },
- "ASSISTANT": {
- "LABEL": "Assistente",
- "PLACEHOLDER": "Seleziona l'assistente",
- "ERROR": "Il campo assistente è richiesto"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Risposta",
"PLACEHOLDER": "Inserisci qui la risposta",
"ERROR": "Inserisci una risposta valida."
- },
- "ASSISTANT": {
- "LABEL": "Assistente",
- "PLACEHOLDER": "Seleziona un assistente",
- "ERROR": "Seleziona un assistente."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/it/report.json b/app/javascript/dashboard/i18n/locale/it/report.json
index 52b8e1685..13694e2af 100644
--- a/app/javascript/dashboard/i18n/locale/it/report.json
+++ b/app/javascript/dashboard/i18n/locale/it/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Ultimi 7 giorni",
"LAST_14_DAYS": "Ultimi 14 giorni",
"LAST_30_DAYS": "Ultimi 30 giorni",
+ "THIS_MONTH": "Questo mese",
+ "LAST_MONTH": "Il mese scorso",
"LAST_3_MONTHS": "Ultimi 3 mesi",
"LAST_6_MONTHS": "Ultimi 6 mesi",
"LAST_YEAR": "Ultimo anno",
diff --git a/app/javascript/dashboard/i18n/locale/it/settings.json b/app/javascript/dashboard/i18n/locale/it/settings.json
index 4e84259c6..de761061a 100644
--- a/app/javascript/dashboard/i18n/locale/it/settings.json
+++ b/app/javascript/dashboard/i18n/locale/it/settings.json
@@ -27,10 +27,10 @@
"CARD": {
"ENTER_KEY": {
"HEADING": "Invio (↵)",
- "CONTENT": "Invia messaggi premendo il tasto INVIO invece di fare clic sul pulsante Invia."
+ "CONTENT": "Invia messaggi premendo il tasto Invio invece di fare clic sul pulsante Invia."
},
"CMD_ENTER_KEY": {
- "HEADING": "Cmd/Ctrl + Enter (⌘ + ↵)",
+ "HEADING": "Cmd/Ctrl + Invio (⌘ + ↵)",
"CONTENT": "Invia messaggi premendo Cmd/Ctrl + Invio invece di dover cliccare sul pulsante Invia."
}
}
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Sospeso",
"MESSAGE": "Il tuo account è sospeso. Contatta il team di supporto per ulteriori informazioni."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "Nessun account trovato",
+ "MESSAGE_CLOUD": "Non fai parte di nessun account al momento. Se pensi che sia un errore, contatta il nostro team di supporto.",
+ "MESSAGE_SELF_HOSTED": "Non fai parte di nessun account al momento. Per favore contatta il tuo amministratore.",
+ "LOGOUT": "Disconnetti"
}
},
"COMPONENTS": {
@@ -299,12 +305,16 @@
"REPORTS": "Report",
"SETTINGS": "Impostazioni",
"CONTACTS": "Contatti",
- "ACTIVE": "Attiva",
+ "ACTIVE": "Attivi",
"CAPTAIN": "Captain",
"CAPTAIN_ASSISTANTS": "Assistenti",
"CAPTAIN_DOCUMENTS": "Documenti",
"CAPTAIN_RESPONSES": "FAQ",
"CAPTAIN_TOOLS": "Strumenti",
+ "CAPTAIN_SCENARIOS": "Scenari",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inbox",
+ "CAPTAIN_SETTINGS": "Impostazioni",
"HOME": "Home",
"AGENTS": "Operatori",
"AGENT_BOTS": "Bots",
@@ -324,7 +334,7 @@
"BILLING": "Fatturazione",
"CUSTOM_VIEWS_FOLDER": "Cartelle",
"CUSTOM_VIEWS_SEGMENTS": "Segmenti",
- "ALL_CONTACTS": "Tutti I Contatti",
+ "ALL_CONTACTS": "Tutti i Contatti",
"TAGGED_WITH": "Etichettato con",
"NEW_LABEL": "Nuova etichetta",
"NEW_TEAM": "Nuovo team",
diff --git a/app/javascript/dashboard/i18n/locale/ja/integrations.json b/app/javascript/dashboard/i18n/locale/ja/integrations.json
index 7af145aae..eb11e38ee 100644
--- a/app/javascript/dashboard/i18n/locale/ja/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ja/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "例: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "キャプテン",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "アシスタント",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "コパイロット",
"TRY_THESE_PROMPTS": "これらのプロンプトを試してください",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "アシスタント"
- },
+ "HEADER": "設定",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "アシスタントを削除",
+ "DESCRIPTION": "この操作は永久的です。アシスタントを削除すると、すべての接続された受信トレイから削除され、生成されたすべての知識が永久に消去されます。",
+ "BUTTON_TEXT": "{assistantName}を削除"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "アシスタント",
- "PLACEHOLDER": "アシスタントを選択",
- "ERROR": "アシスタントの選択が必要です"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "回答",
"PLACEHOLDER": "ここに回答を入力",
"ERROR": "有効な回答を入力してください。"
- },
- "ASSISTANT": {
- "LABEL": "アシスタント",
- "PLACEHOLDER": "アシスタントを選択",
- "ERROR": "アシスタントを選択してください。"
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/ja/report.json b/app/javascript/dashboard/i18n/locale/ja/report.json
index 75f715780..d90524f4e 100644
--- a/app/javascript/dashboard/i18n/locale/ja/report.json
+++ b/app/javascript/dashboard/i18n/locale/ja/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "過去 7 日間",
"LAST_14_DAYS": "過去 14 日間",
"LAST_30_DAYS": "過去 30 日間",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "過去 3 ヶ月",
"LAST_6_MONTHS": "過去 6 ヶ月",
"LAST_YEAR": "過去 1 年",
diff --git a/app/javascript/dashboard/i18n/locale/ja/settings.json b/app/javascript/dashboard/i18n/locale/ja/settings.json
index 297fb854a..27874b6fa 100644
--- a/app/javascript/dashboard/i18n/locale/ja/settings.json
+++ b/app/javascript/dashboard/i18n/locale/ja/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "アカウント停止中",
"MESSAGE": "アカウントが停止されています。詳細についてはサポートチームにお問い合わせください。"
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "ログアウト"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "ドキュメント",
"CAPTAIN_RESPONSES": "FAQ",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "受信トレイ",
+ "CAPTAIN_SETTINGS": "設定",
"HOME": "ホーム",
"AGENTS": "担当者",
"AGENT_BOTS": "ボット",
diff --git a/app/javascript/dashboard/i18n/locale/ka/integrations.json b/app/javascript/dashboard/i18n/locale/ka/integrations.json
index c5b554ee7..0566abd9a 100644
--- a/app/javascript/dashboard/i18n/locale/ka/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ka/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Settings",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/ka/report.json b/app/javascript/dashboard/i18n/locale/ka/report.json
index 22e285c19..a2ad6bd4a 100644
--- a/app/javascript/dashboard/i18n/locale/ka/report.json
+++ b/app/javascript/dashboard/i18n/locale/ka/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Last 7 days",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "Last 30 days",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/ka/settings.json b/app/javascript/dashboard/i18n/locale/ka/settings.json
index ea45db5fa..ac11edc13 100644
--- a/app/javascript/dashboard/i18n/locale/ka/settings.json
+++ b/app/javascript/dashboard/i18n/locale/ka/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "ინსტრუმენტები",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Settings",
"HOME": "Home",
"AGENTS": "Agents",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/ko/integrations.json b/app/javascript/dashboard/i18n/locale/ko/integrations.json
index 9d0fd597a..8bc57201a 100644
--- a/app/javascript/dashboard/i18n/locale/ko/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ko/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "웹훅 URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "설정",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/ko/report.json b/app/javascript/dashboard/i18n/locale/ko/report.json
index be85b62c7..b53d52e6f 100644
--- a/app/javascript/dashboard/i18n/locale/ko/report.json
+++ b/app/javascript/dashboard/i18n/locale/ko/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "지난 7일",
"LAST_14_DAYS": "지난 14일",
"LAST_30_DAYS": "지난 30일",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/ko/settings.json b/app/javascript/dashboard/i18n/locale/ko/settings.json
index 4e4af2242..b55c84e9b 100644
--- a/app/javascript/dashboard/i18n/locale/ko/settings.json
+++ b/app/javascript/dashboard/i18n/locale/ko/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "받은 메시지함",
+ "CAPTAIN_SETTINGS": "설정",
"HOME": "홈",
"AGENTS": "에이전트",
"AGENT_BOTS": "봇",
diff --git a/app/javascript/dashboard/i18n/locale/lt/integrations.json b/app/javascript/dashboard/i18n/locale/lt/integrations.json
index 0bba965a7..266d5c56f 100644
--- a/app/javascript/dashboard/i18n/locale/lt/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/lt/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Nustatymai",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/lt/report.json b/app/javascript/dashboard/i18n/locale/lt/report.json
index f5fcc3d52..cbd0536d9 100644
--- a/app/javascript/dashboard/i18n/locale/lt/report.json
+++ b/app/javascript/dashboard/i18n/locale/lt/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Paskutines 7 dienas",
"LAST_14_DAYS": "Paskutines 14 dienų",
"LAST_30_DAYS": "Paskutines 30 dienų",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Paskutinius 3 mėnesius",
"LAST_6_MONTHS": "Paskutinius 6 mėnesius",
"LAST_YEAR": "Paskutinius metus",
diff --git a/app/javascript/dashboard/i18n/locale/lt/settings.json b/app/javascript/dashboard/i18n/locale/lt/settings.json
index 7b0b24e1c..e2958313b 100644
--- a/app/javascript/dashboard/i18n/locale/lt/settings.json
+++ b/app/javascript/dashboard/i18n/locale/lt/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Paskyra laikinai sustabdyta",
"MESSAGE": "Jūsų paskyra laikinai sustabdyta. Norėdami gauti daugiau informacijos, susisiekite su palaikymo komanda."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Gautų laiškų aplankai",
+ "CAPTAIN_SETTINGS": "Nustatymai",
"HOME": "Pagrindinis",
"AGENTS": "Agentai",
"AGENT_BOTS": "Botai",
diff --git a/app/javascript/dashboard/i18n/locale/lv/integrations.json b/app/javascript/dashboard/i18n/locale/lv/integrations.json
index cb5dca8a2..7ffcdc6cf 100644
--- a/app/javascript/dashboard/i18n/locale/lv/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/lv/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Piemēram: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Kapteinis",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Asistenti",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Kopilots",
"TRY_THESE_PROMPTS": "Pamēģiniet",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Asistents"
- },
+ "HEADER": "Iestatījumi",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Dzēst Asistentu",
+ "DESCRIPTION": "Šī darbība ir pastāvīga. Dzēšot šo asistentu, tas tiks noņemts no visām pievienotajām iesūtnēm un neatgriezeniski dzēstas visas ģenerētās zināšanas.",
+ "BUTTON_TEXT": "Dzēst {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Asistents",
- "PLACEHOLDER": "Izvēlēties asistentu",
- "ERROR": "Asistenta lauks ir obligāti jāaizpilda"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Atbilde",
"PLACEHOLDER": "Ievadiet atbildi šeit",
"ERROR": "Lūdzu, ievadiet derīgu atbildi."
- },
- "ASSISTANT": {
- "LABEL": "Asistents",
- "PLACEHOLDER": "Izvēlieties asistentu",
- "ERROR": "Lūdzu, izvēlieties asistentu."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/lv/report.json b/app/javascript/dashboard/i18n/locale/lv/report.json
index b7a04d026..305da8164 100644
--- a/app/javascript/dashboard/i18n/locale/lv/report.json
+++ b/app/javascript/dashboard/i18n/locale/lv/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Pēdējās 7 dienas",
"LAST_14_DAYS": "Pēdējās 14 dienas",
"LAST_30_DAYS": "Pēdējās 30 dienas",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Pēdējie 3 mēneši",
"LAST_6_MONTHS": "Pēdējie 6 mēneši",
"LAST_YEAR": "Pagājušais gads",
diff --git a/app/javascript/dashboard/i18n/locale/lv/settings.json b/app/javascript/dashboard/i18n/locale/lv/settings.json
index 663754aec..78f7a4d12 100644
--- a/app/javascript/dashboard/i18n/locale/lv/settings.json
+++ b/app/javascript/dashboard/i18n/locale/lv/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Konts Iesaldēts",
"MESSAGE": "Jūsu konts ir iesaldēts. Lai iegūtu papildu informāciju, lūdzu, sazinieties ar atbalsta komandu."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Izrakstīties"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Dokumenti",
"CAPTAIN_RESPONSES": "Bieži uzdotie jautājumi",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Iesūtnes",
+ "CAPTAIN_SETTINGS": "Iestatījumi",
"HOME": "Sākums",
"AGENTS": "Aģenti",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/ml/integrations.json b/app/javascript/dashboard/i18n/locale/ml/integrations.json
index 0c3e2d8cd..35c3b24b9 100644
--- a/app/javascript/dashboard/i18n/locale/ml/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ml/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "വെബ്ഹുക്ക് യുആർഎൽ",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "ക്രമീകരണങ്ങൾ",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/ml/report.json b/app/javascript/dashboard/i18n/locale/ml/report.json
index 3416089ff..fbbcca17c 100644
--- a/app/javascript/dashboard/i18n/locale/ml/report.json
+++ b/app/javascript/dashboard/i18n/locale/ml/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "കഴിഞ്ഞ 7 ദിവസം",
"LAST_14_DAYS": "കഴിഞ്ഞ 14 ദിവസം",
"LAST_30_DAYS": "കഴിഞ്ഞ 30 ദിവസം",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "കഴിഞ്ഞ 3 മാസം",
"LAST_6_MONTHS": "കഴിഞ്ഞ 6 മാസം",
"LAST_YEAR": "കഴിഞ്ഞ വർഷം",
diff --git a/app/javascript/dashboard/i18n/locale/ml/settings.json b/app/javascript/dashboard/i18n/locale/ml/settings.json
index 4fa67d25e..a745f4e84 100644
--- a/app/javascript/dashboard/i18n/locale/ml/settings.json
+++ b/app/javascript/dashboard/i18n/locale/ml/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "ഇൻബോക്സുകൾ",
+ "CAPTAIN_SETTINGS": "ക്രമീകരണങ്ങൾ",
"HOME": "ഹോം",
"AGENTS": "ഏജന്റുമാർ",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/ms/integrations.json b/app/javascript/dashboard/i18n/locale/ms/integrations.json
index 4aa2fb33e..e530f8fb9 100644
--- a/app/javascript/dashboard/i18n/locale/ms/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ms/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Settings",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/ms/report.json b/app/javascript/dashboard/i18n/locale/ms/report.json
index e72366e45..a70387666 100644
--- a/app/javascript/dashboard/i18n/locale/ms/report.json
+++ b/app/javascript/dashboard/i18n/locale/ms/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Last 7 days",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "Last 30 days",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/ms/settings.json b/app/javascript/dashboard/i18n/locale/ms/settings.json
index 57032fa82..712408895 100644
--- a/app/javascript/dashboard/i18n/locale/ms/settings.json
+++ b/app/javascript/dashboard/i18n/locale/ms/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Settings",
"HOME": "Home",
"AGENTS": "Ejen",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/ne/integrations.json b/app/javascript/dashboard/i18n/locale/ne/integrations.json
index d14e0f161..d6c7739e6 100644
--- a/app/javascript/dashboard/i18n/locale/ne/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ne/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Settings",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/ne/report.json b/app/javascript/dashboard/i18n/locale/ne/report.json
index 22e285c19..a2ad6bd4a 100644
--- a/app/javascript/dashboard/i18n/locale/ne/report.json
+++ b/app/javascript/dashboard/i18n/locale/ne/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Last 7 days",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "Last 30 days",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/ne/settings.json b/app/javascript/dashboard/i18n/locale/ne/settings.json
index 28cc081e0..698e5476d 100644
--- a/app/javascript/dashboard/i18n/locale/ne/settings.json
+++ b/app/javascript/dashboard/i18n/locale/ne/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Settings",
"HOME": "Home",
"AGENTS": "Agents",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/nl/integrations.json b/app/javascript/dashboard/i18n/locale/nl/integrations.json
index 7cf3c4242..57dedc0c9 100644
--- a/app/javascript/dashboard/i18n/locale/nl/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/nl/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Instellingen",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/nl/report.json b/app/javascript/dashboard/i18n/locale/nl/report.json
index 821a4f86c..d10ce7d5e 100644
--- a/app/javascript/dashboard/i18n/locale/nl/report.json
+++ b/app/javascript/dashboard/i18n/locale/nl/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Afgelopen 7 dagen",
"LAST_14_DAYS": "Afgelopen 14 dagen",
"LAST_30_DAYS": "Laatste 30 dagen",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/nl/settings.json b/app/javascript/dashboard/i18n/locale/nl/settings.json
index e75351d6d..542998bac 100644
--- a/app/javascript/dashboard/i18n/locale/nl/settings.json
+++ b/app/javascript/dashboard/i18n/locale/nl/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxen",
+ "CAPTAIN_SETTINGS": "Instellingen",
"HOME": "Startpagina",
"AGENTS": "Medewerkers",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/no/integrations.json b/app/javascript/dashboard/i18n/locale/no/integrations.json
index c13484bc3..d162c8412 100644
--- a/app/javascript/dashboard/i18n/locale/no/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/no/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Innstillinger",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/no/report.json b/app/javascript/dashboard/i18n/locale/no/report.json
index 1cffe8c80..9dcfa688b 100644
--- a/app/javascript/dashboard/i18n/locale/no/report.json
+++ b/app/javascript/dashboard/i18n/locale/no/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Siste 7 dager",
"LAST_14_DAYS": "Siste 14 dager",
"LAST_30_DAYS": "Siste 30 dager",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/no/settings.json b/app/javascript/dashboard/i18n/locale/no/settings.json
index 7ed01e244..df9483f5a 100644
--- a/app/javascript/dashboard/i18n/locale/no/settings.json
+++ b/app/javascript/dashboard/i18n/locale/no/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Innbokser",
+ "CAPTAIN_SETTINGS": "Innstillinger",
"HOME": "Hjem",
"AGENTS": "Agenter",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/pl/integrations.json b/app/javascript/dashboard/i18n/locale/pl/integrations.json
index 237f584ae..741f7fc9c 100644
--- a/app/javascript/dashboard/i18n/locale/pl/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/pl/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Adres URL webhooka",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Ustawienia",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/pl/report.json b/app/javascript/dashboard/i18n/locale/pl/report.json
index 75e475b07..9a82f5b8b 100644
--- a/app/javascript/dashboard/i18n/locale/pl/report.json
+++ b/app/javascript/dashboard/i18n/locale/pl/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Ostatnie 7 dni",
"LAST_14_DAYS": "Ostatnie 14 dni",
"LAST_30_DAYS": "Ostatnie 30 dni",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Ostatnie 3 miesiące",
"LAST_6_MONTHS": "Ostatnie 6 miesięcy",
"LAST_YEAR": "Ostatni rok",
diff --git a/app/javascript/dashboard/i18n/locale/pl/settings.json b/app/javascript/dashboard/i18n/locale/pl/settings.json
index 0314c4375..974e9c138 100644
--- a/app/javascript/dashboard/i18n/locale/pl/settings.json
+++ b/app/javascript/dashboard/i18n/locale/pl/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Konto zawieszone",
"MESSAGE": "Twoje konto zostało zawieszone. Skontaktuj się z zespołem pomocy technicznej w celu uzyskania dodatkowych informacji."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Zarządzanie skrzynkami",
+ "CAPTAIN_SETTINGS": "Ustawienia",
"HOME": "Strona główna",
"AGENTS": "Agenci",
"AGENT_BOTS": "Boty",
diff --git a/app/javascript/dashboard/i18n/locale/pt/integrations.json b/app/javascript/dashboard/i18n/locale/pt/integrations.json
index 4506492ff..4d485528e 100644
--- a/app/javascript/dashboard/i18n/locale/pt/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/pt/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversa: a escrever desligada"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "URL do webhook",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Não foi possível encontrar o assistente. Por favor, tente novamente."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Configurações",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Selecionar todas ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Selecionar todas ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Selecionar todas ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/pt/report.json b/app/javascript/dashboard/i18n/locale/pt/report.json
index 44796931d..43b97d46d 100644
--- a/app/javascript/dashboard/i18n/locale/pt/report.json
+++ b/app/javascript/dashboard/i18n/locale/pt/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Últimos 7 Dias",
"LAST_14_DAYS": "Últimos 14 Dias",
"LAST_30_DAYS": "Últimos 30 Dias",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Últimos 3 meses",
"LAST_6_MONTHS": "Últimos 6 meses",
"LAST_YEAR": "Último ano",
diff --git a/app/javascript/dashboard/i18n/locale/pt/settings.json b/app/javascript/dashboard/i18n/locale/pt/settings.json
index 8e71ed9a2..7c2ae657c 100644
--- a/app/javascript/dashboard/i18n/locale/pt/settings.json
+++ b/app/javascript/dashboard/i18n/locale/pt/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Conta Suspensa",
"MESSAGE": "A sua conta está suspensa. Entre em contato com a equipa de suporte para obter mais informações."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Ferramentas",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Caixas de Entrada",
+ "CAPTAIN_SETTINGS": "Configurações",
"HOME": "Principal",
"AGENTS": "Agentes",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/pt_BR/integrations.json b/app/javascript/dashboard/i18n/locale/pt_BR/integrations.json
index 9d2319aae..b9311d051 100644
--- a/app/javascript/dashboard/i18n/locale/pt_BR/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/pt_BR/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Status de Digitação desativado"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "URL do Webhook",
"PLACEHOLDER": "Exemplo: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Capitão",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistentes",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copiloto",
"TRY_THESE_PROMPTS": "Experimente estes comandos",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Não foi possível encontrar o assistente. Tente novamente."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistente"
- },
+ "HEADER": "Configurações",
"BASIC_SETTINGS": {
"TITLE": "Configurações básicas",
"DESCRIPTION": "Personalize o que o assistente diz quando termina uma conversa ou transfere para um humano."
@@ -502,15 +509,16 @@
"TITLE": "Proteções",
"DESCRIPTION": "Mantém as coisas no caminho — apenas os tipos de perguntas que você quer que seu assistente responda, nada fora de limites ou fora do tópico."
},
- "SCENARIOS": {
- "TITLE": "Cenários",
- "DESCRIPTION": "Dê algum contexto ao seu assistente — como \"o que fazer quando um usuário estiver com problemas\", ou \"como agir durante uma solicitação de reembolso\"."
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Diretrizes de resposta",
"DESCRIPTION": "O jeito e a estrutura das respostas do seu assistente — tranquilo e amigável? Curto e ágil? Detalhado e formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Excluir Assistente",
+ "DESCRIPTION": "Esta ação é permanente. Excluir este assistente irá removê-lo de todas as caixas de entrada conectadas e apagará permanentemente todo o conhecimento gerado.",
+ "BUTTON_TEXT": "Excluir {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Proteções",
"DESCRIPTION": "Mantém as coisas no caminho — apenas os tipos de perguntas que você quer que seu assistente responda, nada fora de limites ou fora do tópico.",
- "BREADCRUMB": {
- "TITLE": "Proteções"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selecionado | {count} itens selecionados",
"SELECT_ALL": "Selecionar todos ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Diretrizes de Resposta",
"DESCRIPTION": "O jeito e a estrutura das respostas do seu assistente — tranquilo e amigável? Curto e ágil? Detalhado e formal?",
- "BREADCRUMB": {
- "TITLE": "Diretrizes de Resposta"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selecionado | {count} itens selecionados",
"SELECT_ALL": "Selecionar todos ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Cenários",
"DESCRIPTION": "Dê algum contexto ao seu assistente — como \"o que fazer quando um usuário estiver com problemas\", ou \"como agir durante uma solicitação de reembolso\".",
- "BREADCRUMB": {
- "TITLE": "Cenários"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selecionado | {count} itens selecionados",
"SELECT_ALL": "Selecionar todos ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Nome do documento (opcional)",
"PLACEHOLDER": "Insira um nome para o documento"
- },
- "ASSISTANT": {
- "LABEL": "Assistente",
- "PLACEHOLDER": "Selecione o assistente",
- "ERROR": "O campo Assistente é obrigatório"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Responder",
"PLACEHOLDER": "Digite a resposta aqui",
"ERROR": "Por favor, forneça uma resposta válida."
- },
- "ASSISTANT": {
- "LABEL": "Assistente",
- "PLACEHOLDER": "Selecione um assistente",
- "ERROR": "Por favor, selecione um assistente."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/pt_BR/report.json b/app/javascript/dashboard/i18n/locale/pt_BR/report.json
index 7f1140fdd..426e895c1 100644
--- a/app/javascript/dashboard/i18n/locale/pt_BR/report.json
+++ b/app/javascript/dashboard/i18n/locale/pt_BR/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Últimos 7 dias",
"LAST_14_DAYS": "Últimos 14 dias",
"LAST_30_DAYS": "Últimos 30 dias",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Últimos 3 meses",
"LAST_6_MONTHS": "Últimos 6 meses",
"LAST_YEAR": "Ano passado",
diff --git a/app/javascript/dashboard/i18n/locale/pt_BR/settings.json b/app/javascript/dashboard/i18n/locale/pt_BR/settings.json
index 8c4f3050c..b3afb42d0 100644
--- a/app/javascript/dashboard/i18n/locale/pt_BR/settings.json
+++ b/app/javascript/dashboard/i18n/locale/pt_BR/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Conta Suspensa",
"MESSAGE": "Sua conta está suspensa. Entre em contato com a equipe de suporte para obter mais informações."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Encerrar sessão"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documentos",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Ferramentas",
+ "CAPTAIN_SCENARIOS": "Cenários",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Caixas de Entrada",
+ "CAPTAIN_SETTINGS": "Configurações",
"HOME": "Principal",
"AGENTS": "Agentes",
"AGENT_BOTS": "Robôs",
diff --git a/app/javascript/dashboard/i18n/locale/ro/integrations.json b/app/javascript/dashboard/i18n/locale/ro/integrations.json
index 26c4a59d3..8ec2f80f3 100644
--- a/app/javascript/dashboard/i18n/locale/ro/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ro/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "URL Webhook",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Setări",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/ro/report.json b/app/javascript/dashboard/i18n/locale/ro/report.json
index 9c712852f..a41f15393 100644
--- a/app/javascript/dashboard/i18n/locale/ro/report.json
+++ b/app/javascript/dashboard/i18n/locale/ro/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Ultimele 7 zile",
"LAST_14_DAYS": "Ultimele 14 zile",
"LAST_30_DAYS": "Ultimele 30 zile",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Ultimele 3 luni",
"LAST_6_MONTHS": "Ultimele 6 luni",
"LAST_YEAR": "Anul trecut",
diff --git a/app/javascript/dashboard/i18n/locale/ro/settings.json b/app/javascript/dashboard/i18n/locale/ro/settings.json
index def3181f6..7c976827d 100644
--- a/app/javascript/dashboard/i18n/locale/ro/settings.json
+++ b/app/javascript/dashboard/i18n/locale/ro/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Cont suspendat",
"MESSAGE": "Contul tău este suspendat. Vă rugăm să contactați echipa de asistență pentru mai multe informații."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Căsuțe",
+ "CAPTAIN_SETTINGS": "Setări",
"HOME": "Acasa",
"AGENTS": "Agenți",
"AGENT_BOTS": "Boți",
diff --git a/app/javascript/dashboard/i18n/locale/ru/integrations.json b/app/javascript/dashboard/i18n/locale/ru/integrations.json
index 50b5aa94f..eaa271564 100644
--- a/app/javascript/dashboard/i18n/locale/ru/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ru/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Печатание во время разговора выключено"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "URL вебхука",
"PLACEHOLDER": "Пример: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Капитан",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Ассистенты",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Попробуйте эти запросы",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Не удалось найти помощника. Пожалуйста, попробуйте еще раз."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Ассистент"
- },
+ "HEADER": "Настройки",
"BASIC_SETTINGS": {
"TITLE": "Основные настройки",
"DESCRIPTION": "Настройте то, что говорит ассистент, завершая диалог или передавая человеку."
@@ -502,15 +509,16 @@
"TITLE": "Ограждения",
"DESCRIPTION": "Сохраняет вещи в нужном контексте — только те вопросы, которые вы хотите, чтобы ваш ассистент отвечал, ничего запрещённого или не по теме."
},
- "SCENARIOS": {
- "TITLE": "Сценарии",
- "DESCRIPTION": "Дайте своему ассистенту определенный контекст, например «что делать, когда пользователь застрял» или «как действовать во время запроса на возмещение»."
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Рекомендации по ответу",
"DESCRIPTION": "Вайб и структура ответов помощника – ясные и дружелюбные? Коротко и непросто? Детально и формально?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Удалить ассистента",
+ "DESCRIPTION": "Это действие необратимо. Удаление этого ассистента удалит его из всех подключенных источников и навсегда удалит все сгенерированные знания.",
+ "BUTTON_TEXT": "Удалить {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Ограждения",
"DESCRIPTION": "Сохраняет вещи в нужном контексте — только те вопросы, которые вы хотите, чтобы ваш ассистент отвечал, ничего запрещённого или не по теме.",
- "BREADCRUMB": {
- "TITLE": "Ограждения"
- },
"BULK_ACTION": {
"SELECTED": "{count} элемент выбран | {count} элементов выбрано",
"SELECT_ALL": "Выбрать все ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Руководство по ограждению",
"DESCRIPTION": "Вайб и структура ответов помощника – ясные и дружелюбные? Коротко и непросто? Детально и формально?",
- "BREADCRUMB": {
- "TITLE": "Руководство по ограждению"
- },
"BULK_ACTION": {
"SELECTED": "{count} элемент выбран | {count} элементов выбрано",
"SELECT_ALL": "Выбрать все ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Сценарии",
"DESCRIPTION": "Дайте своему ассистенту определенный контекст, например «что делать, когда пользователь застрял» или «как действовать во время запроса на возмещение».",
- "BREADCRUMB": {
- "TITLE": "Сценарии"
- },
"BULK_ACTION": {
"SELECTED": "{count} элемент выбран | {count} элементов выбрано",
"SELECT_ALL": "Выбрать все ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Название документа (необязательно)",
"PLACEHOLDER": "Введите название документа"
- },
- "ASSISTANT": {
- "LABEL": "Ассистент",
- "PLACEHOLDER": "Выберите ассистента",
- "ERROR": "Необходимо заполнить поле ассистента"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Ответ",
"PLACEHOLDER": "Введите ответ",
"ERROR": "Пожалуйста, введите корректный ответ."
- },
- "ASSISTANT": {
- "LABEL": "Ассистент",
- "PLACEHOLDER": "Выбрать ассистента",
- "ERROR": "Выбрать ассистента"
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/ru/report.json b/app/javascript/dashboard/i18n/locale/ru/report.json
index c01aa0b0c..abb9be29b 100644
--- a/app/javascript/dashboard/i18n/locale/ru/report.json
+++ b/app/javascript/dashboard/i18n/locale/ru/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Последние 7 дней",
"LAST_14_DAYS": "Последние 14 дней",
"LAST_30_DAYS": "Последние 30 дней",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Последние 3 месяца",
"LAST_6_MONTHS": "Последние 6 месяцев",
"LAST_YEAR": "За прошлый год",
diff --git a/app/javascript/dashboard/i18n/locale/ru/settings.json b/app/javascript/dashboard/i18n/locale/ru/settings.json
index 6215481fe..9c9b7ea59 100644
--- a/app/javascript/dashboard/i18n/locale/ru/settings.json
+++ b/app/javascript/dashboard/i18n/locale/ru/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Аккаунт заблокирован",
"MESSAGE": "Ваша учетная запись приостановлена. Пожалуйста, обратитесь в службу поддержки для получения дополнительной информации."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Выйти из системы"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Документы",
"CAPTAIN_RESPONSES": "FAQ",
"CAPTAIN_TOOLS": "Инструменты",
+ "CAPTAIN_SCENARIOS": "Сценарии",
+ "CAPTAIN_PLAYGROUND": "Площадка",
+ "CAPTAIN_INBOXES": "Источники",
+ "CAPTAIN_SETTINGS": "Настройки",
"HOME": "Главная",
"AGENTS": "Операторы",
"AGENT_BOTS": "Боты",
diff --git a/app/javascript/dashboard/i18n/locale/sh/integrations.json b/app/javascript/dashboard/i18n/locale/sh/integrations.json
index c5b554ee7..0566abd9a 100644
--- a/app/javascript/dashboard/i18n/locale/sh/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/sh/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Settings",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/sh/report.json b/app/javascript/dashboard/i18n/locale/sh/report.json
index 22e285c19..a2ad6bd4a 100644
--- a/app/javascript/dashboard/i18n/locale/sh/report.json
+++ b/app/javascript/dashboard/i18n/locale/sh/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Last 7 days",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "Last 30 days",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/sh/settings.json b/app/javascript/dashboard/i18n/locale/sh/settings.json
index 812b0cd8b..50cf38b58 100644
--- a/app/javascript/dashboard/i18n/locale/sh/settings.json
+++ b/app/javascript/dashboard/i18n/locale/sh/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Settings",
"HOME": "Home",
"AGENTS": "Agents",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/sk/integrations.json b/app/javascript/dashboard/i18n/locale/sk/integrations.json
index 942461242..963814952 100644
--- a/app/javascript/dashboard/i18n/locale/sk/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/sk/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Nastavenia",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/sk/report.json b/app/javascript/dashboard/i18n/locale/sk/report.json
index 882ed9cab..65d7182d0 100644
--- a/app/javascript/dashboard/i18n/locale/sk/report.json
+++ b/app/javascript/dashboard/i18n/locale/sk/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Posledných 7 dní",
"LAST_14_DAYS": "Posledných 14 dní",
"LAST_30_DAYS": "Posledných 30 dní",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Posledné 3 mesiace",
"LAST_6_MONTHS": "Posledných 6 mesiacov",
"LAST_YEAR": "Posledný rok",
diff --git a/app/javascript/dashboard/i18n/locale/sk/settings.json b/app/javascript/dashboard/i18n/locale/sk/settings.json
index 719146e9e..7fc93a668 100644
--- a/app/javascript/dashboard/i18n/locale/sk/settings.json
+++ b/app/javascript/dashboard/i18n/locale/sk/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Nastavenia",
"HOME": "Home",
"AGENTS": "Agenti",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/sl/integrations.json b/app/javascript/dashboard/i18n/locale/sl/integrations.json
index 1ae3a96b5..91018d11f 100644
--- a/app/javascript/dashboard/i18n/locale/sl/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/sl/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Settings",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/sl/report.json b/app/javascript/dashboard/i18n/locale/sl/report.json
index efcfb05af..6aaaabb7e 100644
--- a/app/javascript/dashboard/i18n/locale/sl/report.json
+++ b/app/javascript/dashboard/i18n/locale/sl/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Last 7 days",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "Last 30 days",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/sl/settings.json b/app/javascript/dashboard/i18n/locale/sl/settings.json
index b5df89409..ab3ecd93b 100644
--- a/app/javascript/dashboard/i18n/locale/sl/settings.json
+++ b/app/javascript/dashboard/i18n/locale/sl/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Settings",
"HOME": "Home",
"AGENTS": "Agents",
"AGENT_BOTS": "Boti",
diff --git a/app/javascript/dashboard/i18n/locale/sq/integrations.json b/app/javascript/dashboard/i18n/locale/sq/integrations.json
index 8a4a1c41e..6305a2c82 100644
--- a/app/javascript/dashboard/i18n/locale/sq/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/sq/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Settings",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Kufizime",
"DESCRIPTION": "I mban gjërat në vijë—vetëm llojet e pyetjeve që dëshironi që asistenti juaj t’u përgjigjet, asgjë e ndaluar apo jashtë teme.",
- "BREADCRUMB": {
- "TITLE": "Kufizime"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Zgjidh të gjitha ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "Stili dhe struktura e përgjigjeve të asistentit tuaj—të qarta dhe miqësore? Të shkurtra dhe koncize? Të detajuara dhe formale?",
- "BREADCRUMB": {
- "TITLE": "Udhëzime për përgjigjet"
- },
"BULK_ACTION": {
"SELECTED": "{count, plural, one {{count} element i përzgjedhur} other {{count} elemente të përzgjedhura}}",
"SELECT_ALL": "Zgjidh të gjitha ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Skenarë",
"DESCRIPTION": "Jepini asistentit pak kontekst—si p.sh. “çfarë të bëjë kur një përdorues ngec” ose “si të veprojë gjatë një kërkese për rimbursim”.",
- "BREADCRUMB": {
- "TITLE": "Skenarë"
- },
"BULK_ACTION": {
"SELECTED": "{count, plural, one {{count} element i përzgjedhur} other {{count} elemente të përzgjedhura}}",
"SELECT_ALL": "Zgjidh të gjitha ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/sq/report.json b/app/javascript/dashboard/i18n/locale/sq/report.json
index 4ac743070..bee450314 100644
--- a/app/javascript/dashboard/i18n/locale/sq/report.json
+++ b/app/javascript/dashboard/i18n/locale/sq/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Last 7 days",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "Last 30 days",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/sq/settings.json b/app/javascript/dashboard/i18n/locale/sq/settings.json
index a05b4a5d8..bbe97e7bc 100644
--- a/app/javascript/dashboard/i18n/locale/sq/settings.json
+++ b/app/javascript/dashboard/i18n/locale/sq/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Skenarë",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Settings",
"HOME": "Home",
"AGENTS": "Agents",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/sr/integrations.json b/app/javascript/dashboard/i18n/locale/sr/integrations.json
index 3c18faba8..b1f2a0c04 100644
--- a/app/javascript/dashboard/i18n/locale/sr/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/sr/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Adresa veb zakačke",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Podešavanja",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/sr/report.json b/app/javascript/dashboard/i18n/locale/sr/report.json
index 5c2d928c7..94048d504 100644
--- a/app/javascript/dashboard/i18n/locale/sr/report.json
+++ b/app/javascript/dashboard/i18n/locale/sr/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Poslednjih 7 dana",
"LAST_14_DAYS": "Poslednjih 14 dana",
"LAST_30_DAYS": "Poslednjih 30 dana",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Poslednja 3 meseca",
"LAST_6_MONTHS": "Poslednjih 6 meseci",
"LAST_YEAR": "Poslednja godina",
diff --git a/app/javascript/dashboard/i18n/locale/sr/settings.json b/app/javascript/dashboard/i18n/locale/sr/settings.json
index 2bcf552c1..fd70709da 100644
--- a/app/javascript/dashboard/i18n/locale/sr/settings.json
+++ b/app/javascript/dashboard/i18n/locale/sr/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Nalog je suspendovan",
"MESSAGE": "Vaš nalog je suspendovan. Molim vas kontaktirajte tim za podršku za dodatne informacije."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Prijemni sandučići",
+ "CAPTAIN_SETTINGS": "Podešavanja",
"HOME": "Početak",
"AGENTS": "Agenti",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/sv/integrations.json b/app/javascript/dashboard/i18n/locale/sv/integrations.json
index 74f4c7a4d..eb206fa68 100644
--- a/app/javascript/dashboard/i18n/locale/sv/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/sv/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Inställningar",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/sv/report.json b/app/javascript/dashboard/i18n/locale/sv/report.json
index 6768aaa8b..3f0b24c94 100644
--- a/app/javascript/dashboard/i18n/locale/sv/report.json
+++ b/app/javascript/dashboard/i18n/locale/sv/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "De senaste 7 dagarna",
"LAST_14_DAYS": "De senaste 14 dagarna",
"LAST_30_DAYS": "De senaste 30 dagarna",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/sv/settings.json b/app/javascript/dashboard/i18n/locale/sv/settings.json
index f545647b2..da9d452da 100644
--- a/app/javascript/dashboard/i18n/locale/sv/settings.json
+++ b/app/javascript/dashboard/i18n/locale/sv/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inkorgar",
+ "CAPTAIN_SETTINGS": "Inställningar",
"HOME": "Hem",
"AGENTS": "Agenter",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/ta/integrations.json b/app/javascript/dashboard/i18n/locale/ta/integrations.json
index 0ababba9d..b71f3824e 100644
--- a/app/javascript/dashboard/i18n/locale/ta/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ta/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "வெப்ஹூக் URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "அமைப்புகள்",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/ta/report.json b/app/javascript/dashboard/i18n/locale/ta/report.json
index 68b0af4fc..2a8f390fe 100644
--- a/app/javascript/dashboard/i18n/locale/ta/report.json
+++ b/app/javascript/dashboard/i18n/locale/ta/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "கடந்த 7 நாட்கள்",
"LAST_14_DAYS": "கடந்த 14 நாட்கள்",
"LAST_30_DAYS": "கடந்த 30 நாட்கள்",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/ta/settings.json b/app/javascript/dashboard/i18n/locale/ta/settings.json
index 8881d2028..3d25fc4d0 100644
--- a/app/javascript/dashboard/i18n/locale/ta/settings.json
+++ b/app/javascript/dashboard/i18n/locale/ta/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "இன்பாக்ஸ்கள்",
+ "CAPTAIN_SETTINGS": "அமைப்புகள்",
"HOME": "முகப்பு",
"AGENTS": "ஏஜென்ட்கள்",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/th/integrations.json b/app/javascript/dashboard/i18n/locale/th/integrations.json
index 2fc7f5b40..7c30cbb08 100644
--- a/app/javascript/dashboard/i18n/locale/th/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/th/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "ลิ้ง Webhook",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "ตั้งค่า",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/th/report.json b/app/javascript/dashboard/i18n/locale/th/report.json
index beb3b7a33..2a042a17c 100644
--- a/app/javascript/dashboard/i18n/locale/th/report.json
+++ b/app/javascript/dashboard/i18n/locale/th/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "7 วันที่ผ่านมา",
"LAST_14_DAYS": "14 วันที่ผ่านมา",
"LAST_30_DAYS": "30 วันที่ผ่านมา",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "3 เดือนที่ผ่านมา",
"LAST_6_MONTHS": "6 เดือนที่ผ่านมา",
"LAST_YEAR": "ปีที่ผ่านมา",
diff --git a/app/javascript/dashboard/i18n/locale/th/settings.json b/app/javascript/dashboard/i18n/locale/th/settings.json
index 065d9fcb2..ede5c3cdf 100644
--- a/app/javascript/dashboard/i18n/locale/th/settings.json
+++ b/app/javascript/dashboard/i18n/locale/th/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "กล่องข้อความ",
+ "CAPTAIN_SETTINGS": "ตั้งค่า",
"HOME": "หน้าหลัก",
"AGENTS": "พนักงาน",
"AGENT_BOTS": "บอท",
diff --git a/app/javascript/dashboard/i18n/locale/tl/integrations.json b/app/javascript/dashboard/i18n/locale/tl/integrations.json
index ccc46ee1d..9500e2fbc 100644
--- a/app/javascript/dashboard/i18n/locale/tl/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/tl/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Settings",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/tl/report.json b/app/javascript/dashboard/i18n/locale/tl/report.json
index c622170b0..dbf59f603 100644
--- a/app/javascript/dashboard/i18n/locale/tl/report.json
+++ b/app/javascript/dashboard/i18n/locale/tl/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Last 7 days",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "Last 30 days",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/tl/settings.json b/app/javascript/dashboard/i18n/locale/tl/settings.json
index 812b0cd8b..50cf38b58 100644
--- a/app/javascript/dashboard/i18n/locale/tl/settings.json
+++ b/app/javascript/dashboard/i18n/locale/tl/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Settings",
"HOME": "Home",
"AGENTS": "Agents",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/tr/conversation.json b/app/javascript/dashboard/i18n/locale/tr/conversation.json
index d793d6675..570bf19ac 100644
--- a/app/javascript/dashboard/i18n/locale/tr/conversation.json
+++ b/app/javascript/dashboard/i18n/locale/tr/conversation.json
@@ -229,9 +229,9 @@
}
},
"QUOTED_REPLY": {
- "ENABLE_TOOLTIP": "Include quoted email thread",
- "DISABLE_TOOLTIP": "Don't include quoted email thread",
- "REMOVE_PREVIEW": "Remove quoted email thread",
+ "ENABLE_TOOLTIP": "Alıntılanan e-posta zincirini dahil et",
+ "DISABLE_TOOLTIP": "Alıntılanan e-posta zincirini dahil etme",
+ "REMOVE_PREVIEW": "Alıntılanan e-posta zincirini kaldır",
"COLLAPSE": "Önizlemeyi daralt",
"EXPAND": "Önizlemeyi genişlet"
}
diff --git a/app/javascript/dashboard/i18n/locale/tr/inbox.json b/app/javascript/dashboard/i18n/locale/tr/inbox.json
index 69d93cc31..3602e0eaf 100644
--- a/app/javascript/dashboard/i18n/locale/tr/inbox.json
+++ b/app/javascript/dashboard/i18n/locale/tr/inbox.json
@@ -82,13 +82,13 @@
"ERROR": "WhatsApp'a yeniden bağlanılamadı. Lütfen tekrar deneyin.",
"WHATSAPP_APP_ID_MISSING": "WhatsApp Uygulama Kimliği yapılandırılmamış. Lütfen yöneticinize başvurun.",
"WHATSAPP_CONFIG_ID_MISSING": "WhatsApp Yapılandırma Kimliği yapılandırılmamış. Lütfen yöneticinize başvurun.",
- "CONFIGURATION_ERROR": "Configuration error occurred during reauthorization.",
- "FACEBOOK_LOAD_ERROR": "Failed to load Facebook SDK. Please try again.",
+ "CONFIGURATION_ERROR": "Yeniden yetkilendirme sırasında yapılandırma hatası oluştu.",
+ "FACEBOOK_LOAD_ERROR": "Facebook SDK yüklenemedi. Lütfen tekrar deneyin.",
"TROUBLESHOOTING": {
- "TITLE": "Troubleshooting",
- "POPUP_BLOCKED": "Ensure pop-ups are allowed for this site",
- "COOKIES": "Third-party cookies must be enabled",
- "ADMIN_ACCESS": "You need admin access to the WhatsApp Business Account"
+ "TITLE": "Sorun Giderme",
+ "POPUP_BLOCKED": "Bu site için açılır pencerelere izin verildiğinden emin olun",
+ "COOKIES": "Üçüncü taraf çerezlerin etkinleştirilmesi gerekir",
+ "ADMIN_ACCESS": "WhatsApp Business Hesabına yönetici erişiminizin olması gerekir"
}
}
}
diff --git a/app/javascript/dashboard/i18n/locale/tr/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/tr/inboxMgmt.json
index 7beb86c96..9af6714e7 100644
--- a/app/javascript/dashboard/i18n/locale/tr/inboxMgmt.json
+++ b/app/javascript/dashboard/i18n/locale/tr/inboxMgmt.json
@@ -5,8 +5,8 @@
"LEARN_MORE": "Learn more about inboxes",
"RECONNECTION_REQUIRED": "Your inbox is disconnected. You won't receive new messages until you reauthorize it.",
"CLICK_TO_RECONNECT": "Click here to reconnect.",
- "WHATSAPP_REGISTRATION_INCOMPLETE": "Your WhatsApp Business registration isn’t complete. Please check your display name status in Meta Business Manager before reconnecting.",
- "COMPLETE_REGISTRATION": "Complete Registration",
+ "WHATSAPP_REGISTRATION_INCOMPLETE": "WhatsApp Business kaydınız tamamlanmadı. Yeniden bağlanmadan önce lütfen Meta Business Manager'da görünen adınızın (display name) durumunu kontrol edin.",
+ "COMPLETE_REGISTRATION": "Kaydı Tamamla",
"LIST": {
"404": "Bu hesaba bağlı gelen kutusu yok."
},
@@ -337,9 +337,9 @@
},
"CONFIGURATION": {
"TWILIO_VOICE_URL_TITLE": "Twilio Ses URL",
- "TWILIO_VOICE_URL_SUBTITLE": "Configure this URL as the Voice URL on your Twilio phone number and TwiML App.",
- "TWILIO_STATUS_URL_TITLE": "Twilio Status Callback URL",
- "TWILIO_STATUS_URL_SUBTITLE": "Configure this URL as the Status Callback URL on your Twilio phone number."
+ "TWILIO_VOICE_URL_SUBTITLE": "Bu URL'yi Twilio telefon numaranızda ve TwiML Uygulamanızda Sesli Görüşme URL'si (Voice URL) olarak yapılandırın.",
+ "TWILIO_STATUS_URL_TITLE": "Twilio Durum Geri Çağırma URL'si (Status Callback URL)",
+ "TWILIO_STATUS_URL_SUBTITLE": "Bu URL'yi Twilio telefon numaranızda Durum Geri Çağırma URL'si (Status Callback URL) olarak yapılandırın."
},
"SUBMIT_BUTTON": "Ses Kanalı Oluştur",
"API": {
@@ -441,7 +441,7 @@
},
"WHATSAPP": {
"TITLE": "WhatsApp",
- "DESCRIPTION": "Support your customers on WhatsApp"
+ "DESCRIPTION": "Müşterilerinize WhatsApp üzerinden destek sağlayın"
},
"EMAIL": {
"TITLE": "E-Posta",
@@ -638,25 +638,25 @@
},
"ACCOUNT_MODE": {
"LABEL": "Hesap modu",
- "TOOLTIP": "Current operating mode of your WhatsApp account"
+ "TOOLTIP": "WhatsApp hesabınızın mevcut çalışma modu"
}
},
"VALUES": {
"TIERS": {
- "TIER_250": "250 customers per 24h",
- "TIER_1000": "1K customers per 24h",
- "TIER_1K": "1K customers per 24h",
- "TIER_10K": "10K customers per 24h",
- "TIER_100K": "100K customers per 24h",
- "TIER_UNLIMITED": "Unlimited customers per 24h",
+ "TIER_250": "24 saatte 250 müşteri",
+ "TIER_1000": "24 saatte 1000 müşteri",
+ "TIER_1K": "24 saatte 1000 müşteri",
+ "TIER_10K": "24 saatte 10000 müşteri",
+ "TIER_100K": "24 saatte 100000 müşteri",
+ "TIER_UNLIMITED": "24 saatte sınırsız müşteri",
"UNKNOWN": "Değerlendirme mevcut değil"
},
"STATUSES": {
"APPROVED": "Approved",
"PENDING_REVIEW": "İnceleme Bekliyor",
- "AVAILABLE_WITHOUT_REVIEW": "Available Without Review",
+ "AVAILABLE_WITHOUT_REVIEW": "İnceleme Olmadan Kullanılabilir",
"REJECTED": "Reddedildi",
- "DECLINED": "Declined",
+ "DECLINED": "Reddedildi",
"NON_EXISTS": "Mevcut değil"
},
"MODES": {
@@ -678,8 +678,8 @@
"MESSENGER_SUB_HEAD": "Bu düğmeyi gövde etiketinizin içine yerleştirin",
"ALLOWED_DOMAINS": {
"TITLE": "İzin Verilen Alan Adları",
- "SUBTITLE": "Add wildcard or regular domains separated by commas (leave blank to allow all), e.g. *.chatwoot.dev, chatwoot.com.",
- "PLACEHOLDER": "Enter domains separated by commas (eg: *.chatwoot.dev, chatwoot.com)"
+ "SUBTITLE": "Virgülle ayrılmış joker karakterli veya normal alan adları ekleyin (hepsine izin vermek için boş bırakın), örneğin *.chatwoot.dev, chatwoot.com.",
+ "PLACEHOLDER": "Virgülle ayrılmış alan adlarını girin (ör: *.chatwoot.dev, chatwoot.com)"
},
"INBOX_AGENTS": "Kullanıcılar",
"INBOX_AGENTS_SUB_TEXT": "Bu gelen kutusuna aracı ekleyin veya aracıları kaldırın",
@@ -716,26 +716,26 @@
"WHATSAPP_SECTION_UPDATE_PLACEHOLDER": "Yeni API Anahtarını buraya girin",
"WHATSAPP_SECTION_UPDATE_BUTTON": "Güncelleme",
"WHATSAPP_EMBEDDED_SIGNUP_TITLE": "WhatsApp Embedded Signup",
- "WHATSAPP_EMBEDDED_SIGNUP_SUBHEADER": "This inbox is connected through WhatsApp embedded signup.",
- "WHATSAPP_EMBEDDED_SIGNUP_DESCRIPTION": "You can reconfigure this inbox to update your WhatsApp Business settings.",
+ "WHATSAPP_EMBEDDED_SIGNUP_SUBHEADER": "Bu gelen kutusu, WhatsApp embedded signup yoluyla bağlandı.",
+ "WHATSAPP_EMBEDDED_SIGNUP_DESCRIPTION": "WhatsApp Business ayarlarınızı güncellemek için bu gelen kutusunu yeniden yapılandırabilirsiniz.",
"WHATSAPP_RECONFIGURE_BUTTON": "Yeniden yapılandır",
- "WHATSAPP_CONNECT_TITLE": "Connect to WhatsApp Business",
- "WHATSAPP_CONNECT_SUBHEADER": "Upgrade to WhatsApp embedded signup for easier management.",
- "WHATSAPP_CONNECT_DESCRIPTION": "Connect this inbox to WhatsApp Business for enhanced features and easier management.",
+ "WHATSAPP_CONNECT_TITLE": "WhatsApp Business'a Bağlan",
+ "WHATSAPP_CONNECT_SUBHEADER": "Daha kolay yönetim için WhatsApp gömülü kayda (embedded signup) yükseltin.",
+ "WHATSAPP_CONNECT_DESCRIPTION": "Gelişmiş özellikler ve daha kolay yönetim için bu gelen kutusunu WhatsApp Business'a bağlayın.",
"WHATSAPP_CONNECT_BUTTON": "Bağlan",
- "WHATSAPP_CONNECT_SUCCESS": "Successfully connected to WhatsApp Business!",
- "WHATSAPP_CONNECT_ERROR": "Failed to connect to WhatsApp Business. Please try again.",
- "WHATSAPP_RECONFIGURE_SUCCESS": "Successfully reconfigured WhatsApp Business!",
- "WHATSAPP_RECONFIGURE_ERROR": "Failed to reconfigure WhatsApp Business. Please try again.",
+ "WHATSAPP_CONNECT_SUCCESS": "WhatsApp Business'a başarıyla bağlandı!",
+ "WHATSAPP_CONNECT_ERROR": "WhatsApp Business'a bağlanılamadı. Lütfen tekrar deneyin.",
+ "WHATSAPP_RECONFIGURE_SUCCESS": "WhatsApp Business başarıyla yeniden yapılandırıldı!",
+ "WHATSAPP_RECONFIGURE_ERROR": "WhatsApp Business yeniden yapılandırılamadı. Lütfen tekrar deneyin.",
"WHATSAPP_APP_ID_MISSING": "WhatsApp Uygulama Kimliği yapılandırılmamış. Lütfen yöneticinize başvurun.",
"WHATSAPP_CONFIG_ID_MISSING": "WhatsApp Yapılandırma Kimliği yapılandırılmamış. Lütfen yöneticinize başvurun.",
- "WHATSAPP_LOGIN_CANCELLED": "WhatsApp login was cancelled. Please try again.",
+ "WHATSAPP_LOGIN_CANCELLED": "WhatsApp oturum açma işlemi iptal edildi. Lütfen tekrar deneyin.",
"WHATSAPP_WEBHOOK_TITLE": "Webhook Onay Anahtarı",
"WHATSAPP_WEBHOOK_SUBHEADER": "Bu belirteç, webhook uç noktasının gerçekliğini doğrulamak için kullanılır.",
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Şablonları Senkronize Et",
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "WhatsApp'tan mesaj şablonlarını manuel olarak senkronize ederek mevcut şablonlarınızı güncelleyin.",
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Şablonları Senkronize Et",
- "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.",
+ "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Şablon senkronizasyonu başarıyla başlatıldı. Güncellenmesi birkaç dakika sürebilir.",
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Sohbet Öncesi Form Ayarlarını Güncelleme"
},
"HELP_CENTER": {
@@ -981,15 +981,15 @@
"EMAIL_PROVIDERS": {
"MICROSOFT": {
"TITLE": "Microsoft",
- "DESCRIPTION": "Connect with Microsoft"
+ "DESCRIPTION": "Microsoft ile giriş yap"
},
"GOOGLE": {
"TITLE": "Google",
- "DESCRIPTION": "Connect with Google"
+ "DESCRIPTION": "Google ile giriş yap"
},
"OTHER_PROVIDERS": {
"TITLE": "Diğer Sağlayıcılar",
- "DESCRIPTION": "Connect with Other Providers"
+ "DESCRIPTION": "Diğer Sağlayıcılar ile giriş yap"
}
},
"CHANNELS": {
diff --git a/app/javascript/dashboard/i18n/locale/tr/integrations.json b/app/javascript/dashboard/i18n/locale/tr/integrations.json
index 56d9582f3..1e4118d0f 100644
--- a/app/javascript/dashboard/i18n/locale/tr/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/tr/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Konuşmada Yazıyor Kapalı"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Web kancası URL'si",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Asistan bulunamadı. Lütfen tekrar deneyin."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Ayarlar",
"BASIC_SETTINGS": {
"TITLE": "Temel ayarlar",
"DESCRIPTION": "Konuşmayı sonlandırırken veya bir operatöre aktarırken asistanın söyleyeceği sözleri özelleştirin."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,11 +537,8 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
- "SELECTED": "{count} item selected | {count} items selected",
+ "SELECTED": "{count} eşya seçildi | {count} eşya seçildi",
"SELECT_ALL": "Tümünü seç ({count})",
"UNSELECT_ALL": "Tümünü kaldır ({count})",
"BULK_DELETE_BUTTON": "Sil"
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} eşya seçildi | {count} eşya seçildi",
"SELECT_ALL": "Tümünü seç ({count})",
@@ -625,11 +627,8 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
- "SELECTED": "{count} item selected | {count} items selected",
+ "SELECTED": "{count} eşya seçildi | {count} eşya seçildi",
"SELECT_ALL": "Tümünü seç ({count})",
"UNSELECT_ALL": "Tümünü kaldır ({count})",
"BULK_DELETE_BUTTON": "Sil"
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Belge Adı (İsteğe Bağlı)",
"PLACEHOLDER": "Belgeye bir ad girin"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/tr/login.json b/app/javascript/dashboard/i18n/locale/tr/login.json
index 8460a575b..6b4b4a693 100644
--- a/app/javascript/dashboard/i18n/locale/tr/login.json
+++ b/app/javascript/dashboard/i18n/locale/tr/login.json
@@ -24,17 +24,17 @@
"CREATE_NEW_ACCOUNT": "Yeni hesap oluştur",
"SUBMIT": "Oturum aç",
"SAML": {
- "LABEL": "Login via SSO",
- "TITLE": "Initiate Single Sign-on (SSO)",
- "SUBTITLE": "Enter your work email to access your organization",
+ "LABEL": "SSO ile giriş yapın",
+ "TITLE": "Tek Oturum Açma (SSO)",
+ "SUBTITLE": "Kuruluşunuza erişmek için iş e-posta adresinizi girin",
"BACK_TO_LOGIN": "Şifre ile giriş yap",
"WORK_EMAIL": {
- "LABEL": "Work Email",
- "PLACEHOLDER": "Enter your work email"
+ "LABEL": "İş E-Postası",
+ "PLACEHOLDER": "İş e-posta adresinizi girin"
},
- "SUBMIT": "Continue with SSO",
+ "SUBMIT": "SSO ile devam et",
"API": {
- "ERROR_MESSAGE": "SSO authentication failed. Please check your credentials and try again."
+ "ERROR_MESSAGE": "SSO (Tek Oturum Açma) kimlik doğrulaması başarısız oldu. Lütfen kimlik bilgilerinizi kontrol edin ve tekrar deneyin."
}
}
}
diff --git a/app/javascript/dashboard/i18n/locale/tr/report.json b/app/javascript/dashboard/i18n/locale/tr/report.json
index 9d0d74741..ae3d54d3f 100644
--- a/app/javascript/dashboard/i18n/locale/tr/report.json
+++ b/app/javascript/dashboard/i18n/locale/tr/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Son 7 gün",
"LAST_14_DAYS": "Son 14 gün",
"LAST_30_DAYS": "Son 30 gün",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Son 3 ay",
"LAST_6_MONTHS": "Son 6 ay",
"LAST_YEAR": "Geçen yıl",
diff --git a/app/javascript/dashboard/i18n/locale/tr/settings.json b/app/javascript/dashboard/i18n/locale/tr/settings.json
index 120acd2f4..88bc7346f 100644
--- a/app/javascript/dashboard/i18n/locale/tr/settings.json
+++ b/app/javascript/dashboard/i18n/locale/tr/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Hesap Askıya Alındı",
"MESSAGE": "Hesabınız askıya alındı. Daha fazla bilgi için lütfen destek ekibine ulaşın."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "Hesap bulunamadı",
+ "MESSAGE_CLOUD": "Şu anda herhangi bir hesabın parçası değilsiniz. Bunun bir hata olduğunu düşünüyorsanız, lütfen destek ekibimizle iletişime geçin.",
+ "MESSAGE_SELF_HOSTED": "Şu anda herhangi bir hesabın parçası değilsiniz. Lütfen yöneticinizle iletişime geçin.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Araçlar",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Oyun Alanı",
+ "CAPTAIN_INBOXES": "Gelen kutuları",
+ "CAPTAIN_SETTINGS": "Ayarlar",
"HOME": "Anasayfa",
"AGENTS": "Kullanıcılar",
"AGENT_BOTS": "Botlar",
@@ -419,8 +429,8 @@
"PLACEHOLDER": "-----BEGIN CERTIFICATE-----\nMIIC..."
},
"FINGERPRINT": {
- "LABEL": "Fingerprint",
- "TOOLTIP": "SHA-1 fingerprint of the certificate - Use this to verify the certificate in your IdP configuration"
+ "LABEL": "Parmak izi",
+ "TOOLTIP": "Sertifikanın SHA-1 parmak izi – Bunu, Kimlik Sağlayıcısı (IdP) yapılandırmanızda sertifikayı doğrulamak için kullanın"
},
"COPY_SUCCESS": "Kod başarıyla panoya kopyalandı",
"SP_ENTITY_ID": {
diff --git a/app/javascript/dashboard/i18n/locale/tr/signup.json b/app/javascript/dashboard/i18n/locale/tr/signup.json
index c804e8968..9900d3ba6 100644
--- a/app/javascript/dashboard/i18n/locale/tr/signup.json
+++ b/app/javascript/dashboard/i18n/locale/tr/signup.json
@@ -28,11 +28,11 @@
"PLACEHOLDER": "Parola",
"ERROR": "Parola çok kısa.",
"IS_INVALID_PASSWORD": "Şifre en az 1 büyük harf, 1 küçük harf, 1 rakam ve 1 özel karakter içermelidir.",
- "REQUIREMENTS_LENGTH": "At least 6 characters long",
- "REQUIREMENTS_UPPERCASE": "At least one uppercase letter",
- "REQUIREMENTS_LOWERCASE": "At least one lowercase letter",
- "REQUIREMENTS_NUMBER": "At least one number",
- "REQUIREMENTS_SPECIAL": "At least one special character"
+ "REQUIREMENTS_LENGTH": "En az 6 karakter uzunluğunda olmalı",
+ "REQUIREMENTS_UPPERCASE": "En az bir büyük harf içermeli",
+ "REQUIREMENTS_LOWERCASE": "En az bir küçük harf içermeli",
+ "REQUIREMENTS_NUMBER": "En az bir rakam içermeli",
+ "REQUIREMENTS_SPECIAL": "En az bir özel karakter içermeli"
},
"CONFIRM_PASSWORD": {
"LABEL": "Parolayı onayla",
@@ -40,7 +40,7 @@
"ERROR": "Parola eşleşmiyor."
},
"API": {
- "SUCCESS_MESSAGE": "Registration Successful",
+ "SUCCESS_MESSAGE": "Başarıyla Kayıt Olundu",
"ERROR_MESSAGE": "Woot sunucusuna bağlanılamadı. Lütfen tekrar deneyin."
},
"SUBMIT": "Hesap oluştur",
diff --git a/app/javascript/dashboard/i18n/locale/uk/integrations.json b/app/javascript/dashboard/i18n/locale/uk/integrations.json
index 5ebd0081c..de5e8258b 100644
--- a/app/javascript/dashboard/i18n/locale/uk/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/uk/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "URL вебхука",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Налаштування",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/uk/report.json b/app/javascript/dashboard/i18n/locale/uk/report.json
index bf40caef6..6af3bdc23 100644
--- a/app/javascript/dashboard/i18n/locale/uk/report.json
+++ b/app/javascript/dashboard/i18n/locale/uk/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Останні 7 днів",
"LAST_14_DAYS": "Останні 14 днів",
"LAST_30_DAYS": "Останні 30 днів",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Останні 3 місяці",
"LAST_6_MONTHS": "Останні 6 місяців",
"LAST_YEAR": "Минулий рік",
diff --git a/app/javascript/dashboard/i18n/locale/uk/settings.json b/app/javascript/dashboard/i18n/locale/uk/settings.json
index 6d480d63b..2fcc4fd2f 100644
--- a/app/javascript/dashboard/i18n/locale/uk/settings.json
+++ b/app/javascript/dashboard/i18n/locale/uk/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Обліковий запис призупинено",
"MESSAGE": "Ваш обліковий запис призупинено. Будь ласка, зверніться до служби підтримки для отримання додаткової інформації."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Вхідні",
+ "CAPTAIN_SETTINGS": "Налаштування",
"HOME": "Головна",
"AGENTS": "Агенти",
"AGENT_BOTS": "Боти",
diff --git a/app/javascript/dashboard/i18n/locale/ur/integrations.json b/app/javascript/dashboard/i18n/locale/ur/integrations.json
index 80b245b7b..b534e6194 100644
--- a/app/javascript/dashboard/i18n/locale/ur/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ur/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Settings",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/ur/report.json b/app/javascript/dashboard/i18n/locale/ur/report.json
index 6c25d30c7..a4c1fb9b3 100644
--- a/app/javascript/dashboard/i18n/locale/ur/report.json
+++ b/app/javascript/dashboard/i18n/locale/ur/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Last 7 days",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "Last 30 days",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/ur/settings.json b/app/javascript/dashboard/i18n/locale/ur/settings.json
index dda7ab163..8b15e3009 100644
--- a/app/javascript/dashboard/i18n/locale/ur/settings.json
+++ b/app/javascript/dashboard/i18n/locale/ur/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Settings",
"HOME": "Home",
"AGENTS": "ایجنٹ",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/ur_IN/integrations.json b/app/javascript/dashboard/i18n/locale/ur_IN/integrations.json
index c5b554ee7..0566abd9a 100644
--- a/app/javascript/dashboard/i18n/locale/ur_IN/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ur_IN/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Settings",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/ur_IN/report.json b/app/javascript/dashboard/i18n/locale/ur_IN/report.json
index 22e285c19..a2ad6bd4a 100644
--- a/app/javascript/dashboard/i18n/locale/ur_IN/report.json
+++ b/app/javascript/dashboard/i18n/locale/ur_IN/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "Last 7 days",
"LAST_14_DAYS": "Last 14 days",
"LAST_30_DAYS": "Last 30 days",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "Last 3 months",
"LAST_6_MONTHS": "Last 6 months",
"LAST_YEAR": "Last year",
diff --git a/app/javascript/dashboard/i18n/locale/ur_IN/settings.json b/app/javascript/dashboard/i18n/locale/ur_IN/settings.json
index 256f77c04..aec3e852d 100644
--- a/app/javascript/dashboard/i18n/locale/ur_IN/settings.json
+++ b/app/javascript/dashboard/i18n/locale/ur_IN/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Inboxes",
+ "CAPTAIN_SETTINGS": "Settings",
"HOME": "Home",
"AGENTS": "Agents",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/vi/integrations.json b/app/javascript/dashboard/i18n/locale/vi/integrations.json
index 42ff68fda..bcfd10f38 100644
--- a/app/javascript/dashboard/i18n/locale/vi/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/vi/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook URL",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "Cài đặt",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/vi/report.json b/app/javascript/dashboard/i18n/locale/vi/report.json
index 6713bb3a9..69b10453e 100644
--- a/app/javascript/dashboard/i18n/locale/vi/report.json
+++ b/app/javascript/dashboard/i18n/locale/vi/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "7 ngày cuối",
"LAST_14_DAYS": "14 ngày cuối",
"LAST_30_DAYS": "30 ngày cuối",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "3 tháng vừa qua",
"LAST_6_MONTHS": "6 tháng vừa qua",
"LAST_YEAR": "Năm ngoái",
diff --git a/app/javascript/dashboard/i18n/locale/vi/settings.json b/app/javascript/dashboard/i18n/locale/vi/settings.json
index 1f5c43834..5d52a58c5 100644
--- a/app/javascript/dashboard/i18n/locale/vi/settings.json
+++ b/app/javascript/dashboard/i18n/locale/vi/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Tài khoản bị ngưng",
"MESSAGE": "Tài khoản của bạn bị tạm ngưng. Vui lòng liên hệ với nhóm hỗ trợ để biết thêm thông tin."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "Log out"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "Hộp thư đến",
+ "CAPTAIN_SETTINGS": "Cài đặt",
"HOME": "Trang Chủ",
"AGENTS": "Đại lý",
"AGENT_BOTS": "Bots",
diff --git a/app/javascript/dashboard/i18n/locale/zh_CN/integrations.json b/app/javascript/dashboard/i18n/locale/zh_CN/integrations.json
index ee01615e4..a37ac43a5 100644
--- a/app/javascript/dashboard/i18n/locale/zh_CN/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/zh_CN/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "对话输入关闭"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook 网址",
"PLACEHOLDER": "例如:{webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "了解更多",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "助手",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "尝试这些提示信息",
@@ -483,9 +492,7 @@
"NOT_FOUND": "无法找到助手。请重试。"
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "助手"
- },
+ "HEADER": "设置",
"BASIC_SETTINGS": {
"TITLE": "基本设置",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "删除助手",
+ "DESCRIPTION": "此操作是永久性的。删除此文档将永久删除所有生成的知识。",
+ "BUTTON_TEXT": "删除 {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "全选 ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "全选 ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "全选 ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "文档名称(可选)",
"PLACEHOLDER": "输入文档的名称"
- },
- "ASSISTANT": {
- "LABEL": "助手",
- "PLACEHOLDER": "选择助手",
- "ERROR": "助手字段是必需的"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "答案",
"PLACEHOLDER": "在此输入答案",
"ERROR": "请提供有效的答案"
- },
- "ASSISTANT": {
- "LABEL": "助手",
- "PLACEHOLDER": "选择助手",
- "ERROR": "请选择助手"
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/zh_CN/report.json b/app/javascript/dashboard/i18n/locale/zh_CN/report.json
index b6b89b17e..57c9ef3af 100644
--- a/app/javascript/dashboard/i18n/locale/zh_CN/report.json
+++ b/app/javascript/dashboard/i18n/locale/zh_CN/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "最近7天",
"LAST_14_DAYS": "最近14天",
"LAST_30_DAYS": "最近30天",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "最近3个月",
"LAST_6_MONTHS": "最近6个月",
"LAST_YEAR": "最近一年",
diff --git a/app/javascript/dashboard/i18n/locale/zh_CN/settings.json b/app/javascript/dashboard/i18n/locale/zh_CN/settings.json
index 478816f53..1a60e9538 100644
--- a/app/javascript/dashboard/i18n/locale/zh_CN/settings.json
+++ b/app/javascript/dashboard/i18n/locale/zh_CN/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "账户已暂停",
"MESSAGE": "您的账户已被暂停。请联系支持团队以获取更多信息。"
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "注销"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "文档",
"CAPTAIN_RESPONSES": "常见问题",
"CAPTAIN_TOOLS": "工具",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "试验场",
+ "CAPTAIN_INBOXES": "收件箱",
+ "CAPTAIN_SETTINGS": "设置",
"HOME": "首页",
"AGENTS": "客服代理",
"AGENT_BOTS": "机器人",
diff --git a/app/javascript/dashboard/i18n/locale/zh_TW/integrations.json b/app/javascript/dashboard/i18n/locale/zh_TW/integrations.json
index e3acd0073..2016bb406 100644
--- a/app/javascript/dashboard/i18n/locale/zh_TW/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/zh_TW/integrations.json
@@ -46,6 +46,10 @@
"CONVERSATION_TYPING_OFF": "Conversation Typing Off"
}
},
+ "NAME": {
+ "LABEL": "Webhook Name",
+ "PLACEHOLDER": "Enter the name of the webhook"
+ },
"END_POINT": {
"LABEL": "Webhook 網址",
"PLACEHOLDER": "Example: {webhookExampleURL}",
@@ -344,6 +348,11 @@
"CAPTAIN": {
"NAME": "Captain",
"HEADER_KNOW_MORE": "Know more",
+ "ASSISTANT_SWITCHER": {
+ "ASSISTANTS": "Assistants",
+ "SWITCH_ASSISTANT": "Switch between assistants",
+ "NEW_ASSISTANT": "Create Assistant"
+ },
"COPILOT": {
"TITLE": "Copilot",
"TRY_THESE_PROMPTS": "Try these prompts",
@@ -483,9 +492,7 @@
"NOT_FOUND": "Could not find the assistant. Please try again."
},
"SETTINGS": {
- "BREADCRUMB": {
- "ASSISTANT": "Assistant"
- },
+ "HEADER": "設定",
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
@@ -502,15 +509,16 @@
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
},
- "SCENARIOS": {
- "TITLE": "Scenarios",
- "DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
- },
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?"
}
}
+ },
+ "DELETE": {
+ "TITLE": "Delete Assistant",
+ "DESCRIPTION": "This action is permanent. Deleting this assistant will remove it from all connected inboxes and permanently erase all generated knowledge.",
+ "BUTTON_TEXT": "Delete {assistantName}"
}
},
"OPTIONS": {
@@ -529,9 +537,6 @@
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
- "BREADCRUMB": {
- "TITLE": "Guardrails"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -577,9 +582,6 @@
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistant’s replies—clear and friendly? Short and snappy? Detailed and formal?",
- "BREADCRUMB": {
- "TITLE": "Response Guidelines"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -625,9 +627,6 @@
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
- "BREADCRUMB": {
- "TITLE": "Scenarios"
- },
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECT_ALL": "Select all ({count})",
@@ -725,11 +724,6 @@
"NAME": {
"LABEL": "Document Name (Optional)",
"PLACEHOLDER": "Enter a name for the document"
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select the assistant",
- "ERROR": "The assistant field is required"
}
},
"DELETE": {
@@ -923,11 +917,6 @@
"LABEL": "Answer",
"PLACEHOLDER": "Enter the answer here",
"ERROR": "Please provide a valid answer."
- },
- "ASSISTANT": {
- "LABEL": "Assistant",
- "PLACEHOLDER": "Select an assistant",
- "ERROR": "Please select an assistant."
}
},
"EDIT": {
diff --git a/app/javascript/dashboard/i18n/locale/zh_TW/report.json b/app/javascript/dashboard/i18n/locale/zh_TW/report.json
index 76a86db03..3f36b9ef5 100644
--- a/app/javascript/dashboard/i18n/locale/zh_TW/report.json
+++ b/app/javascript/dashboard/i18n/locale/zh_TW/report.json
@@ -53,6 +53,8 @@
"LAST_7_DAYS": "最近7天",
"LAST_14_DAYS": "最近14天",
"LAST_30_DAYS": "最近30天",
+ "THIS_MONTH": "This month",
+ "LAST_MONTH": "Last month",
"LAST_3_MONTHS": "三個月內",
"LAST_6_MONTHS": "六個月內",
"LAST_YEAR": "去年",
diff --git a/app/javascript/dashboard/i18n/locale/zh_TW/settings.json b/app/javascript/dashboard/i18n/locale/zh_TW/settings.json
index 814517a19..1ba1d30ff 100644
--- a/app/javascript/dashboard/i18n/locale/zh_TW/settings.json
+++ b/app/javascript/dashboard/i18n/locale/zh_TW/settings.json
@@ -251,6 +251,12 @@
"ACCOUNT_SUSPENDED": {
"TITLE": "Account Suspended",
"MESSAGE": "Your account is suspended. Please reach out to the support team for more information."
+ },
+ "NO_ACCOUNTS": {
+ "TITLE": "No account found",
+ "MESSAGE_CLOUD": "You are not part of any accounts right now. If you think this is a mistake, please reach out to our support team.",
+ "MESSAGE_SELF_HOSTED": "You are not part of any accounts right now. Please reach out to your administrator.",
+ "LOGOUT": "退出登入"
}
},
"COMPONENTS": {
@@ -305,6 +311,10 @@
"CAPTAIN_DOCUMENTS": "Documents",
"CAPTAIN_RESPONSES": "FAQs",
"CAPTAIN_TOOLS": "Tools",
+ "CAPTAIN_SCENARIOS": "Scenarios",
+ "CAPTAIN_PLAYGROUND": "Playground",
+ "CAPTAIN_INBOXES": "收件匣",
+ "CAPTAIN_SETTINGS": "設定",
"HOME": "首頁",
"AGENTS": "客服",
"AGENT_BOTS": "機器人",
diff --git a/config/locales/am.yml b/config/locales/am.yml
index f1e9bf52b..59ecaf187 100644
--- a/config/locales/am.yml
+++ b/config/locales/am.yml
@@ -76,6 +76,7 @@ am:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/ar.yml b/config/locales/ar.yml
index b4998c6e4..77c3f3c21 100644
--- a/config/locales/ar.yml
+++ b/config/locales/ar.yml
@@ -76,6 +76,7 @@ ar:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/az.yml b/config/locales/az.yml
index 4ca5260f5..ecf46da3b 100644
--- a/config/locales/az.yml
+++ b/config/locales/az.yml
@@ -76,6 +76,7 @@ az:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/bg.yml b/config/locales/bg.yml
index 9a83df74a..9f806ddb8 100644
--- a/config/locales/bg.yml
+++ b/config/locales/bg.yml
@@ -76,6 +76,7 @@ bg:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/bn.yml b/config/locales/bn.yml
index 6e2cedeb1..6bea58292 100644
--- a/config/locales/bn.yml
+++ b/config/locales/bn.yml
@@ -76,6 +76,7 @@ bn:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/ca.yml b/config/locales/ca.yml
index cd0e36f29..51a3e06e4 100644
--- a/config/locales/ca.yml
+++ b/config/locales/ca.yml
@@ -76,6 +76,7 @@ ca:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/cs.yml b/config/locales/cs.yml
index 3fb647b48..9daeea48a 100644
--- a/config/locales/cs.yml
+++ b/config/locales/cs.yml
@@ -76,6 +76,7 @@ cs:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/da.yml b/config/locales/da.yml
index d7c02426f..81834a427 100644
--- a/config/locales/da.yml
+++ b/config/locales/da.yml
@@ -76,6 +76,7 @@ da:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/de.yml b/config/locales/de.yml
index c59576720..c805c47d3 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -76,6 +76,7 @@ de:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/el.yml b/config/locales/el.yml
index 22fce73b7..63c4a686d 100644
--- a/config/locales/el.yml
+++ b/config/locales/el.yml
@@ -76,6 +76,7 @@ el:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/es.yml b/config/locales/es.yml
index cfe468dee..8a035df7b 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -76,6 +76,7 @@ es:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/et.yml b/config/locales/et.yml
index dcf81c6e3..e60df2b42 100644
--- a/config/locales/et.yml
+++ b/config/locales/et.yml
@@ -76,6 +76,7 @@ et:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/fa.yml b/config/locales/fa.yml
index 536c78f47..bb9db01e9 100644
--- a/config/locales/fa.yml
+++ b/config/locales/fa.yml
@@ -76,6 +76,7 @@ fa:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/fi.yml b/config/locales/fi.yml
index 7e8c3e14b..94f68aa8d 100644
--- a/config/locales/fi.yml
+++ b/config/locales/fi.yml
@@ -76,6 +76,7 @@ fi:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 53435aafa..460e520aa 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -76,6 +76,7 @@ fr:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/he.yml b/config/locales/he.yml
index a8c729959..56e32d142 100644
--- a/config/locales/he.yml
+++ b/config/locales/he.yml
@@ -76,6 +76,7 @@ he:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/hi.yml b/config/locales/hi.yml
index 26b89c2e5..0e47a998c 100644
--- a/config/locales/hi.yml
+++ b/config/locales/hi.yml
@@ -76,6 +76,7 @@ hi:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/hr.yml b/config/locales/hr.yml
index 4b4117eed..3239824bf 100644
--- a/config/locales/hr.yml
+++ b/config/locales/hr.yml
@@ -76,6 +76,7 @@ hr:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/hu.yml b/config/locales/hu.yml
index 87c496aa0..585afcd24 100644
--- a/config/locales/hu.yml
+++ b/config/locales/hu.yml
@@ -76,6 +76,7 @@ hu:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/hy.yml b/config/locales/hy.yml
index 063db291d..8b61be9c4 100644
--- a/config/locales/hy.yml
+++ b/config/locales/hy.yml
@@ -76,6 +76,7 @@ hy:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/id.yml b/config/locales/id.yml
index 41383befc..167b860a9 100644
--- a/config/locales/id.yml
+++ b/config/locales/id.yml
@@ -76,6 +76,7 @@ id:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/is.yml b/config/locales/is.yml
index 7f671ac54..47db2a83c 100644
--- a/config/locales/is.yml
+++ b/config/locales/is.yml
@@ -76,6 +76,7 @@ is:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/it.yml b/config/locales/it.yml
index 83a00a8b5..ba6c7cf5e 100644
--- a/config/locales/it.yml
+++ b/config/locales/it.yml
@@ -76,6 +76,7 @@ it:
token_exchange_failed: 'Impossibile scambiare il codice con il token di accesso. Riprova.'
invalid_token_permissions: 'Il token di accesso non dispone dei permessi richiesti per WhatsApp.'
phone_info_fetch_failed: 'Impossibile recuperare le informazioni sul numero di telefono. Riprova.'
+ phone_number_already_exists: 'Esiste già un canale per questo numero di telefono: %{phone_number}, si prega di contattare il supporto se l''errore persiste'
reauthorization:
generic: 'Impossibile riautorizzare WhatsApp. Riprova.'
not_supported: 'La riautorizzazione non è supportata per questo tipo di canale WhatsApp.'
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index eb205d1f5..d1753cb7a 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -76,6 +76,7 @@ ja:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/ka.yml b/config/locales/ka.yml
index df7caec35..25e2370ee 100644
--- a/config/locales/ka.yml
+++ b/config/locales/ka.yml
@@ -76,6 +76,7 @@ ka:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/ko.yml b/config/locales/ko.yml
index 8200fe4cf..707332172 100644
--- a/config/locales/ko.yml
+++ b/config/locales/ko.yml
@@ -76,6 +76,7 @@ ko:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/lt.yml b/config/locales/lt.yml
index 4fca6066f..daf7b00ee 100644
--- a/config/locales/lt.yml
+++ b/config/locales/lt.yml
@@ -76,6 +76,7 @@ lt:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/lv.yml b/config/locales/lv.yml
index baac1bbfe..3fd92993b 100644
--- a/config/locales/lv.yml
+++ b/config/locales/lv.yml
@@ -76,6 +76,7 @@ lv:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/ml.yml b/config/locales/ml.yml
index ef716ae26..ee5ee8f7f 100644
--- a/config/locales/ml.yml
+++ b/config/locales/ml.yml
@@ -76,6 +76,7 @@ ml:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/ms.yml b/config/locales/ms.yml
index 8dc3b396d..460986218 100644
--- a/config/locales/ms.yml
+++ b/config/locales/ms.yml
@@ -76,6 +76,7 @@ ms:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/ne.yml b/config/locales/ne.yml
index 6a1d0cdb0..57b0ddc4c 100644
--- a/config/locales/ne.yml
+++ b/config/locales/ne.yml
@@ -76,6 +76,7 @@ ne:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/nl.yml b/config/locales/nl.yml
index 75d536a5c..73e15b0c3 100644
--- a/config/locales/nl.yml
+++ b/config/locales/nl.yml
@@ -76,6 +76,7 @@ nl:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/no.yml b/config/locales/no.yml
index e45fe8b88..41ce03ef5 100644
--- a/config/locales/no.yml
+++ b/config/locales/no.yml
@@ -76,6 +76,7 @@
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index 863bd6671..5b727d944 100644
--- a/config/locales/pl.yml
+++ b/config/locales/pl.yml
@@ -76,6 +76,7 @@ pl:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/pt.yml b/config/locales/pt.yml
index cc5f4b940..168941db0 100644
--- a/config/locales/pt.yml
+++ b/config/locales/pt.yml
@@ -76,6 +76,7 @@ pt:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/pt_BR.yml b/config/locales/pt_BR.yml
index 52a0b4226..f8f6c0428 100644
--- a/config/locales/pt_BR.yml
+++ b/config/locales/pt_BR.yml
@@ -76,6 +76,7 @@ pt_BR:
token_exchange_failed: 'Falha ao trocar o código por um token de acesso. Por favor, tente novamente.'
invalid_token_permissions: 'O token de acesso não tem as permissões necessárias para o WhatsApp.'
phone_info_fetch_failed: 'Falha ao obter a informação do número de telefone. Por favor, tente novamente.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Falha ao reautenticar o WhatsApp. Por favor, tente novamente.'
not_supported: 'Reautenticação não é suportado por este tipo de canal WhatsApp.'
diff --git a/config/locales/ro.yml b/config/locales/ro.yml
index b998feb84..b00c1689c 100644
--- a/config/locales/ro.yml
+++ b/config/locales/ro.yml
@@ -76,6 +76,7 @@ ro:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/ru.yml b/config/locales/ru.yml
index 2484b30b4..90d41e87b 100644
--- a/config/locales/ru.yml
+++ b/config/locales/ru.yml
@@ -76,6 +76,7 @@ ru:
token_exchange_failed: 'Не удалось обменять код на токена доступа. Пожалуйста, попробуйте еще раз.'
invalid_token_permissions: 'Токен доступа не имеет необходимых прав для WhatsApp.'
phone_info_fetch_failed: 'Не удалось получить информацию о номере телефона. Пожалуйста, попробуйте еще раз.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Не удалось повторно авторизовать WhatsApp. Пожалуйста, попробуйте еще раз.'
not_supported: 'Повторная авторизация не поддерживается для данного типа канала WhatsApp.'
diff --git a/config/locales/sh.yml b/config/locales/sh.yml
index 612db81a8..e918e4f58 100644
--- a/config/locales/sh.yml
+++ b/config/locales/sh.yml
@@ -76,6 +76,7 @@ sh:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/sk.yml b/config/locales/sk.yml
index 149af73cd..51c376df2 100644
--- a/config/locales/sk.yml
+++ b/config/locales/sk.yml
@@ -76,6 +76,7 @@ sk:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/sl.yml b/config/locales/sl.yml
index 40333e298..ba73fed9f 100644
--- a/config/locales/sl.yml
+++ b/config/locales/sl.yml
@@ -76,6 +76,7 @@ sl:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/sq.yml b/config/locales/sq.yml
index ac7d5e4b9..b2874d78f 100644
--- a/config/locales/sq.yml
+++ b/config/locales/sq.yml
@@ -76,6 +76,7 @@ sq:
token_exchange_failed: 'Dështoi shkëmbimi i kodit për tokenin e aksesit. Ju lutemi, provoni përsëri.'
invalid_token_permissions: 'Tokeni i aksesit nuk ka lejet e nevojshme për WhatsApp.'
phone_info_fetch_failed: 'Dështoi marrja e informacionit të numrit të telefonit. Ju lutemi, provoni përsëri.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Dështoi riautorizimi i WhatsApp-it. Ju lutemi, provoni përsëri.'
not_supported: 'Riautorizimi nuk mbështetet për këtë lloj kanali të WhatsApp-it.'
diff --git a/config/locales/sr.yml b/config/locales/sr.yml
index 685b736be..c0d384a15 100644
--- a/config/locales/sr.yml
+++ b/config/locales/sr.yml
@@ -76,6 +76,7 @@ sr-Latn:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/sv.yml b/config/locales/sv.yml
index 5c0c18b22..c12ee447d 100644
--- a/config/locales/sv.yml
+++ b/config/locales/sv.yml
@@ -76,6 +76,7 @@ sv:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/ta.yml b/config/locales/ta.yml
index 752ec6e6c..1f84cf894 100644
--- a/config/locales/ta.yml
+++ b/config/locales/ta.yml
@@ -76,6 +76,7 @@ ta:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/th.yml b/config/locales/th.yml
index 1ad957730..c6882b804 100644
--- a/config/locales/th.yml
+++ b/config/locales/th.yml
@@ -76,6 +76,7 @@ th:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/tl.yml b/config/locales/tl.yml
index 4ccbe3f16..a82593d8b 100644
--- a/config/locales/tl.yml
+++ b/config/locales/tl.yml
@@ -76,6 +76,7 @@ tl:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/tr.yml b/config/locales/tr.yml
index ca0eb3596..5cca4e559 100644
--- a/config/locales/tr.yml
+++ b/config/locales/tr.yml
@@ -76,6 +76,7 @@ tr:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Bu telefon numarası için zaten bir kanal mevcut: %{phone_number}, hata devam ederse lütfen destek ile iletişime geçin'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/uk.yml b/config/locales/uk.yml
index 543241725..b993f11cc 100644
--- a/config/locales/uk.yml
+++ b/config/locales/uk.yml
@@ -76,6 +76,7 @@ uk:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/ur.yml b/config/locales/ur.yml
index 859babbfa..3ce206c7a 100644
--- a/config/locales/ur.yml
+++ b/config/locales/ur.yml
@@ -76,6 +76,7 @@ ur:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/ur_IN.yml b/config/locales/ur_IN.yml
index 9a402fa1c..1c60bbbe2 100644
--- a/config/locales/ur_IN.yml
+++ b/config/locales/ur_IN.yml
@@ -76,6 +76,7 @@ ur:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/vi.yml b/config/locales/vi.yml
index 281b3bab4..4a58f028e 100644
--- a/config/locales/vi.yml
+++ b/config/locales/vi.yml
@@ -76,6 +76,7 @@ vi:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/zh_CN.yml b/config/locales/zh_CN.yml
index b706cdca3..86a9ca702 100644
--- a/config/locales/zh_CN.yml
+++ b/config/locales/zh_CN.yml
@@ -76,6 +76,7 @@ zh_CN:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
diff --git a/config/locales/zh_TW.yml b/config/locales/zh_TW.yml
index f35ced777..de3b45df9 100644
--- a/config/locales/zh_TW.yml
+++ b/config/locales/zh_TW.yml
@@ -76,6 +76,7 @@ zh_TW:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
+ phone_number_already_exists: 'Channel already exists for this phone number: %{phone_number}, please contact support if the error persists'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
From 6ae5e67b52bc849a0a05dade6755a09f6e9f540f Mon Sep 17 00:00:00 2001
From: Vinay Keerthi <11478411+stonecharioteer@users.noreply.github.com>
Date: Fri, 14 Nov 2025 22:42:56 +0530
Subject: [PATCH 67/80] fix: revert annotaterb migration due to persistent
annotation errors (#12881)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## Description
This PR reverts the migration from the `annotate` gem to `annotaterb`
introduced in PR #12845. The annotation errors reported in #11673
persist with both gems, and the old `annotate` gem handles the errors
more gracefully by continuing to process other models instead of
crashing.
**Testing reveals both gems fail with the same underlying issue:**
**Old annotate gem (3.2.0):**
```
Unable to annotate app/models/installation_config.rb: no implicit conversion of Hash into String
Unable to annotate app/models/installation_config.rb: no implicit conversion of nil into Array
Model files unchanged.
```
(Logs error but continues processing)
**New annotaterb gem (4.20.0):**
```
❯ bundle exec annotaterb models
ruby/3.4.4/lib/ruby/gems/3.4.0/gems/reline-0.3.6/lib/reline/terminfo.rb:2: warning: ruby/3.4.4/lib/ruby/3.4.0/fiddle.rb was loaded from the standard library, but will no longer be part of the default gems starting from Ruby 3.5.0.
You can add fiddle to your Gemfile or gemspec to silence this warning.
Also please contact the author of reline-0.3.6 to request adding fiddle into its gemspec.
Annotating models
bundler: failed to load command: annotaterb (ruby/3.4.4/bin/annotaterb)
ruby/3.4.4/lib/ruby/3.4.0/psych/parser.rb:62:in 'Psych::Parser#_native_parse': no implicit conversion of Hash into String (TypeError)
_native_parse @handler, yaml, path
^^^^^^^^^^^^^^^^^^^^
from ruby/3.4.4/lib/ruby/3.4.0/psych/parser.rb:62:in 'Psych::Parser#parse'
from ruby/3.4.4/lib/ruby/3.4.0/psych.rb:457:in 'Psych.parse_stream'
from ruby/3.4.4/lib/ruby/3.4.0/psych.rb:401:in 'Psych.parse'
from ruby/3.4.4/lib/ruby/3.4.0/psych.rb:325:in 'Psych.safe_load'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/activerecord-7.1.5.2/lib/active_record/coders/yaml_column.rb:37:in 'ActiveRecord::Coders::YAMLColumn::SafeCoder#load'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/activerecord-7.1.5.2/lib/active_record/coders/column_serializer.rb:37:in 'ActiveRecord::Coders::ColumnSerializer#load'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/activerecord-7.1.5.2/lib/active_record/type/serialized.rb:22:in 'ActiveRecord::Type::Serialized#deserialize'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/activemodel-7.1.5.2/lib/active_model/attribute.rb:175:in 'ActiveModel::Attribute::FromDatabase#type_cast'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/activemodel-7.1.5.2/lib/active_model/attribute.rb:43:in 'ActiveModel::Attribute#value'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/activemodel-7.1.5.2/lib/active_model/attribute_set.rb:37:in 'block in ActiveModel::AttributeSet#to_hash'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/activesupport-7.1.5.2/lib/active_support/core_ext/enumerable.rb:78:in 'block in Enumerable#index_with'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/activesupport-7.1.5.2/lib/active_support/core_ext/enumerable.rb:78:in 'Array#each'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/activesupport-7.1.5.2/lib/active_support/core_ext/enumerable.rb:78:in 'Enumerable#index_with'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/activemodel-7.1.5.2/lib/active_model/attribute_set.rb:37:in 'ActiveModel::AttributeSet#to_hash'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/activerecord-7.1.5.2/lib/active_record/model_schema.rb:499:in 'ActiveRecord::ModelSchema::ClassMethods#column_defaults'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/model_annotator/model_wrapper.rb:68:in 'AnnotateRb::ModelAnnotator::ModelWrapper#column_defaults'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/model_annotator/model_wrapper.rb:139:in 'block in AnnotateRb::ModelAnnotator::ModelWrapper#built_attributes'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/model_annotator/model_wrapper.rb:136:in 'Array#map'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/model_annotator/model_wrapper.rb:136:in 'AnnotateRb::ModelAnnotator::ModelWrapper#built_attributes'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/model_annotator/column_annotation/annotation_builder.rb:15:in 'AnnotateRb::ModelAnnotator::ColumnAnnotation::AnnotationBuilder#build'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/model_annotator/annotation/annotation_builder.rb:52:in 'block in AnnotateRb::ModelAnnotator::Annotation::AnnotationBuilder::Annotation#columns'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/model_annotator/annotation/annotation_builder.rb:51:in 'Array#map'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/model_annotator/annotation/annotation_builder.rb:51:in 'AnnotateRb::ModelAnnotator::Annotation::AnnotationBuilder::Annotation#columns'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/model_annotator/annotation/annotation_builder.rb:26:in 'AnnotateRb::ModelAnnotator::Annotation::AnnotationBuilder::Annotation#body'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/model_annotator/annotation/annotation_builder.rb:35:in 'AnnotateRb::ModelAnnotator::Annotation::AnnotationBuilder::Annotation#build'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/model_annotator/annotation/annotation_builder.rb:71:in 'AnnotateRb::ModelAnnotator::Annotation::AnnotationBuilder#build'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/model_annotator/project_annotator.rb:43:in 'AnnotateRb::ModelAnnotator::ProjectAnnotator#build_instructions_for_file'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/model_annotator/project_annotator.rb:17:in 'block in AnnotateRb::ModelAnnotator::ProjectAnnotator#annotate'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/model_annotator/project_annotator.rb:13:in 'Array#map'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/model_annotator/project_annotator.rb:13:in 'AnnotateRb::ModelAnnotator::ProjectAnnotator#annotate'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/model_annotator/annotator.rb:21:in 'AnnotateRb::ModelAnnotator::Annotator#do_annotations'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/model_annotator/annotator.rb:8:in 'AnnotateRb::ModelAnnotator::Annotator.do_annotations'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/commands/annotate_models.rb:17:in 'AnnotateRb::Commands::AnnotateModels#call'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/runner.rb:38:in 'AnnotateRb::Runner#run'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/lib/annotate_rb/runner.rb:11:in 'AnnotateRb::Runner.run'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/annotaterb-4.20.0/exe/annotaterb:18:in ''
from ruby/3.4.4/bin/annotaterb:25:in 'Kernel#load'
from ruby/3.4.4/bin/annotaterb:25:in ''
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/bundler-2.5.16/lib/bundler/cli/exec.rb:58:in 'Kernel.load'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/bundler-2.5.16/lib/bundler/cli/exec.rb:58:in 'Bundler::CLI::Exec#kernel_load'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/bundler-2.5.16/lib/bundler/cli/exec.rb:23:in 'Bundler::CLI::Exec#run'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/bundler-2.5.16/lib/bundler/cli.rb:455:in 'Bundler::CLI#exec'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/bundler-2.5.16/lib/bundler/vendor/thor/lib/thor/command.rb:28:in 'Bundler::Thor::Command#run'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/bundler-2.5.16/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in 'Bundler::Thor::Invocation#invoke_command'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/bundler-2.5.16/lib/bundler/vendor/thor/lib/thor.rb:527:in 'Bundler::Thor.dispatch'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/bundler-2.5.16/lib/bundler/cli.rb:35:in 'Bundler::CLI.dispatch'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/bundler-2.5.16/lib/bundler/vendor/thor/lib/thor/base.rb:584:in 'Bundler::Thor::Base::ClassMethods#start'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/bundler-2.5.16/lib/bundler/cli.rb:29:in 'Bundler::CLI.start'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/bundler-2.5.16/exe/bundle:28:in 'block in '
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/bundler-2.5.16/lib/bundler/friendly_errors.rb:117:in 'Bundler.with_friendly_errors'
from ruby/3.4.4/lib/ruby/gems/3.4.0/gems/bundler-2.5.16/exe/bundle:20:in ''
from ruby/3.4.4/bin/bundle:25:in 'Kernel#load'
from ruby/3.4.4/bin/bundle:25:in ''
```
(Crashes immediately, stops all processing)
**Root cause:** The `InstallationConfig` model uses YAML serialization
(`serialize :serialized_value, coder: YAML`) on a JSONB database column.
When annotation tools read column defaults, PostgreSQL returns JSONB as
a Hash, but YAML expects a String, causing the type error.
The migration to annotaterb doesn't solve the problem - both gems
encounter the same error. The old gem is preferable as it continues
working despite the error.
Reverts #12845
Related to #11673
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
1. Reverted commit 559d1b657
2. Ran `bundle install` to reinstall annotate gem v3.2.0
3. Ran `RAILS_ENV=development bundle exec annotate`
- Result: Logs errors for InstallationConfig but completes successfully
4. Re-applied the annotaterb changes and tested `bundle exec annotaterb
models`
- Result: Crashes with full stack trace and stops processing
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] My changes generate no new warnings
- [x] New and existing unit tests pass locally with my changes
---
*Edited to truncate environment-specific info from error dump*
---
Gemfile | 2 +-
Gemfile.lock | 8 ++++----
lib/tasks/auto_annotate_models.rake | 9 ++++-----
3 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/Gemfile b/Gemfile
index 4b9d978d4..abbd3332f 100644
--- a/Gemfile
+++ b/Gemfile
@@ -207,7 +207,7 @@ group :production do
end
group :development do
- gem 'annotaterb'
+ gem 'annotate'
gem 'bullet'
gem 'letter_opener'
gem 'scss_lint', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index fa3a5e788..99e75b33c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -128,9 +128,9 @@ GEM
selectize-rails (~> 0.6)
ai-agents (0.4.3)
ruby_llm (~> 1.3)
- annotaterb (4.20.0)
- activerecord (>= 6.0.0)
- activesupport (>= 6.0.0)
+ annotate (3.2.0)
+ activerecord (>= 3.2, < 8.0)
+ rake (>= 10.4, < 14.0)
ast (2.4.3)
attr_extras (7.1.0)
audited (5.4.1)
@@ -992,7 +992,7 @@ DEPENDENCIES
administrate-field-active_storage (>= 1.0.3)
administrate-field-belongs_to_search (>= 0.9.0)
ai-agents (>= 0.4.3)
- annotaterb
+ annotate
attr_extras
audited (~> 5.4, >= 5.4.1)
aws-sdk-s3
diff --git a/lib/tasks/auto_annotate_models.rake b/lib/tasks/auto_annotate_models.rake
index 9dcd13126..8a89739b6 100644
--- a/lib/tasks/auto_annotate_models.rake
+++ b/lib/tasks/auto_annotate_models.rake
@@ -2,14 +2,11 @@
# NOTE: are sensitive to local FS writes, and besides -- it's just not proper
# NOTE: to have a dev-mode tool do its thing in production.
if Rails.env.development?
- require 'annotate_rb'
-
- AnnotateRb::Core.load_rake_tasks
-
+ require 'annotate'
task :set_annotation_options do
# You can override any of these by setting an environment variable of the
# same name.
- AnnotateRb::Options.set_defaults(
+ Annotate.set_defaults(
'additional_file_patterns' => [],
'routes' => 'false',
'models' => 'true',
@@ -58,4 +55,6 @@ if Rails.env.development?
'with_comment' => 'true'
)
end
+
+ Annotate.load_tasks
end
From 2c4e65d68e8c36e7461948d2ee108e42c0c9f2b4 Mon Sep 17 00:00:00 2001
From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Date: Mon, 17 Nov 2025 09:58:59 +0530
Subject: [PATCH 68/80] chore: Hide assistant switcher on paywall screen
(#12875)
---
.../components-next/captain/PageLayout.vue | 20 ++++++++++++++-----
.../switcher/AssistantSwitcher.vue | 5 +++++
.../i18n/locale/en/integrations.json | 3 ++-
3 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/app/javascript/dashboard/components-next/captain/PageLayout.vue b/app/javascript/dashboard/components-next/captain/PageLayout.vue
index 19303ba01..d9fce9e0f 100644
--- a/app/javascript/dashboard/components-next/captain/PageLayout.vue
+++ b/app/javascript/dashboard/components-next/captain/PageLayout.vue
@@ -2,6 +2,7 @@
import { ref, computed } from 'vue';
import { OnClickOutside } from '@vueuse/components';
import { useRoute } from 'vue-router';
+import { useI18n } from 'vue-i18n';
import { useMapGetter } from 'dashboard/composables/store.js';
import { usePolicy } from 'dashboard/composables/usePolicy';
import Button from 'dashboard/components-next/button/Button.vue';
@@ -69,6 +70,8 @@ const props = defineProps({
const emit = defineEmits(['click', 'close', 'update:currentPage']);
+const { t } = useI18n();
+
const route = useRoute();
const { shouldShowPaywall } = usePolicy();
@@ -76,14 +79,16 @@ const showAssistantSwitcherDropdown = ref(false);
const createAssistantDialogRef = ref(null);
const assistants = useMapGetter('captainAssistants/getRecords');
+const uiFlags = useMapGetter('captainAssistants/getUIFlags');
const currentAssistantId = computed(() => route.params.assistantId);
+const isFetchingAssistants = computed(() => uiFlags.value?.fetchingList);
const activeAssistantName = computed(() => {
return (
assistants.value?.find(
assistant => assistant.id === Number(currentAssistantId.value)
- )?.name || ''
+ )?.name || t('CAPTAIN.ASSISTANT_SWITCHER.NEW_ASSISTANT')
);
});
@@ -118,15 +123,18 @@ const handleCreateAssistant = () => {
>
-
+
{{ activeAssistantName }}
-
+
@@ -135,6 +143,8 @@ const handleCreateAssistant = () => {
variant="ghost"
color="slate"
size="xs"
+ :disabled="isFetchingAssistants"
+ :is-loading="isFetchingAssistants"
class="rounded-md group-hover:bg-n-slate-3 hover:bg-n-slate-3 [&>span]:size-4"
@click="toggleAssistantSwitcher"
/>
@@ -151,7 +161,7 @@ const handleCreateAssistant = () => {
+
+
+ {{ t('CAPTAIN.ASSISTANT_SWITCHER.EMPTY_LIST') }}
+
+
diff --git a/app/javascript/dashboard/i18n/locale/en/integrations.json b/app/javascript/dashboard/i18n/locale/en/integrations.json
index f74e674d7..c08cde4d3 100644
--- a/app/javascript/dashboard/i18n/locale/en/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/en/integrations.json
@@ -348,7 +348,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
From c9823d9409b217fa045ae2bfa879eba3c6ce9d58 Mon Sep 17 00:00:00 2001
From: Tanmay Deep Sharma <32020192+tds-1@users.noreply.github.com>
Date: Mon, 17 Nov 2025 10:08:25 +0530
Subject: [PATCH 69/80] feat: Assignment service (v2) (#12320)
## Linear Link
## Description
This PR introduces a new robust auto-assignment system for conversations
in Chatwoot. The system replaces the existing round-robin assignment
with a more sophisticated service-based architecture that supports
multiple assignment strategies, rate limiting, and Enterprise features
like capacity-based assignment and balanced distribution.
## Type of change
- [ ] New feature (non-breaking change which adds functionality)
## How Has This Been Tested?
- Unit test cases
- Test conversations getting assigned on status change to open
- Test the job directly via rails console
## Checklist:
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
---
> [!NOTE]
> Adds a new service-based auto-assignment system with scheduled jobs,
rate limiting, enterprise capacity/balanced selection, and wiring via
inbox/handler; includes Redis helpers and comprehensive tests.
>
> - **Auto-assignment v2 (core services)**:
> - Add `AutoAssignment::AssignmentService` with bulk assignment,
configurable conversation priority, RR selection, and per-agent rate
limiting via `AutoAssignment::RateLimiter`.
> - Add `AutoAssignment::RoundRobinSelector` for agent selection.
> - **Jobs & scheduling**:
> - Add `AutoAssignment::AssignmentJob` (per-inbox bulk assign;
env-based limit) and `AutoAssignment::PeriodicAssignmentJob` (batch over
accounts/inboxes).
> - Schedule periodic run in `config/schedule.yml`
(`periodic_assignment_job`).
> - **Model/concerns wiring**:
> - Include `InboxAgentAvailability` in `Inbox`; add
`Inbox#auto_assignment_v2_enabled?`.
> - Update `AutoAssignmentHandler` to trigger v2 job when
`auto_assignment_v2_enabled?`, else fallback to legacy.
> - **Enterprise extensions**:
> - Add `Enterprise::InboxAgentAvailability` (capacity-aware filtering)
and `Enterprise::Concerns::Inbox` association `inbox_capacity_limits`.
> - Extend service via `Enterprise::AutoAssignment::AssignmentService`
(policy-driven config, capacity filtering, exclusion rules) and add
selectors/services: `BalancedSelector`, `CapacityService`.
> - **Infrastructure**:
> - Enhance `Redis::Alfred` with `expire`, key scan/count, and extended
ZSET helpers (`zadd`, `zcount`, `zcard`, `zrangebyscore`).
> - **Tests**:
> - Add specs for jobs, core service, rate limiter, RR selector, and
enterprise features (capacity, balanced selection, exclusions).
>
> Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
0ebe187c8aea73765b0122a44b18d6f465c2477f. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).
---------
Co-authored-by: Muhsin Keloth
Co-authored-by: Shivam Mishra
---
app/jobs/auto_assignment/assignment_job.rb | 22 ++
.../periodic_assignment_job.rb | 19 ++
.../concerns/auto_assignment_handler.rb | 8 +-
.../concerns/inbox_agent_availability.rb | 28 ++
app/models/inbox.rb | 5 +
.../auto_assignment/assignment_service.rb | 90 +++++
app/services/auto_assignment/rate_limiter.rb | 49 +++
.../auto_assignment/round_robin_selector.rb | 16 +
config/schedule.yml | 6 +
.../app/models/enterprise/concerns/inbox.rb | 1 +
.../enterprise/inbox_agent_availability.rb | 31 ++
.../auto_assignment/assignment_service.rb | 94 ++++++
.../auto_assignment/balanced_selector.rb | 26 ++
.../auto_assignment/capacity_service.rb | 25 ++
lib/redis/alfred.rb | 47 ++-
lib/redis/redis_keys.rb | 5 +
.../assignment_service_spec.rb | 185 +++++++++++
.../auto_assignment/balanced_selector_spec.rb | 88 +++++
.../auto_assignment/capacity_service_spec.rb | 119 +++++++
.../auto_assignment/assignment_job_spec.rb | 85 +++++
.../periodic_assignment_job_spec.rb | 123 +++++++
.../assignment_service_spec.rb | 310 ++++++++++++++++++
.../auto_assignment/rate_limiter_spec.rb | 167 ++++++++++
.../round_robin_selector_spec.rb | 78 +++++
24 files changed, 1622 insertions(+), 5 deletions(-)
create mode 100644 app/jobs/auto_assignment/assignment_job.rb
create mode 100644 app/jobs/auto_assignment/periodic_assignment_job.rb
create mode 100644 app/models/concerns/inbox_agent_availability.rb
create mode 100644 app/services/auto_assignment/assignment_service.rb
create mode 100644 app/services/auto_assignment/rate_limiter.rb
create mode 100644 app/services/auto_assignment/round_robin_selector.rb
create mode 100644 enterprise/app/models/enterprise/inbox_agent_availability.rb
create mode 100644 enterprise/app/services/enterprise/auto_assignment/assignment_service.rb
create mode 100644 enterprise/app/services/enterprise/auto_assignment/balanced_selector.rb
create mode 100644 enterprise/app/services/enterprise/auto_assignment/capacity_service.rb
create mode 100644 spec/enterprise/services/enterprise/auto_assignment/assignment_service_spec.rb
create mode 100644 spec/enterprise/services/enterprise/auto_assignment/balanced_selector_spec.rb
create mode 100644 spec/enterprise/services/enterprise/auto_assignment/capacity_service_spec.rb
create mode 100644 spec/jobs/auto_assignment/assignment_job_spec.rb
create mode 100644 spec/jobs/auto_assignment/periodic_assignment_job_spec.rb
create mode 100644 spec/services/auto_assignment/assignment_service_spec.rb
create mode 100644 spec/services/auto_assignment/rate_limiter_spec.rb
create mode 100644 spec/services/auto_assignment/round_robin_selector_spec.rb
diff --git a/app/jobs/auto_assignment/assignment_job.rb b/app/jobs/auto_assignment/assignment_job.rb
new file mode 100644
index 000000000..9c6760ecc
--- /dev/null
+++ b/app/jobs/auto_assignment/assignment_job.rb
@@ -0,0 +1,22 @@
+class AutoAssignment::AssignmentJob < ApplicationJob
+ queue_as :default
+
+ def perform(inbox_id:)
+ inbox = Inbox.find_by(id: inbox_id)
+ return unless inbox
+
+ service = AutoAssignment::AssignmentService.new(inbox: inbox)
+
+ assigned_count = service.perform_bulk_assignment(limit: bulk_assignment_limit)
+ Rails.logger.info "Assigned #{assigned_count} conversations for inbox #{inbox.id}"
+ rescue StandardError => e
+ Rails.logger.error "Bulk assignment failed for inbox #{inbox_id}: #{e.message}"
+ raise e if Rails.env.test?
+ end
+
+ private
+
+ def bulk_assignment_limit
+ ENV.fetch('AUTO_ASSIGNMENT_BULK_LIMIT', 100).to_i
+ end
+end
diff --git a/app/jobs/auto_assignment/periodic_assignment_job.rb b/app/jobs/auto_assignment/periodic_assignment_job.rb
new file mode 100644
index 000000000..63500507e
--- /dev/null
+++ b/app/jobs/auto_assignment/periodic_assignment_job.rb
@@ -0,0 +1,19 @@
+class AutoAssignment::PeriodicAssignmentJob < ApplicationJob
+ queue_as :scheduled_jobs
+
+ def perform
+ Account.find_in_batches do |accounts|
+ accounts.each do |account|
+ next unless account.feature_enabled?('assignment_v2')
+
+ account.inboxes.joins(:assignment_policy).find_in_batches do |inboxes|
+ inboxes.each do |inbox|
+ next unless inbox.auto_assignment_v2_enabled?
+
+ AutoAssignment::AssignmentJob.perform_later(inbox_id: inbox.id)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/models/concerns/auto_assignment_handler.rb b/app/models/concerns/auto_assignment_handler.rb
index de5fdae7d..a1198200a 100644
--- a/app/models/concerns/auto_assignment_handler.rb
+++ b/app/models/concerns/auto_assignment_handler.rb
@@ -14,7 +14,13 @@ module AutoAssignmentHandler
return unless conversation_status_changed_to_open?
return unless should_run_auto_assignment?
- ::AutoAssignment::AgentAssignmentService.new(conversation: self, allowed_agent_ids: inbox.member_ids_with_assignment_capacity).perform
+ if inbox.auto_assignment_v2_enabled?
+ # Use new assignment system
+ AutoAssignment::AssignmentJob.perform_later(inbox_id: inbox.id)
+ else
+ # Use legacy assignment system
+ AutoAssignment::AgentAssignmentService.new(conversation: self, allowed_agent_ids: inbox.member_ids_with_assignment_capacity).perform
+ end
end
def should_run_auto_assignment?
diff --git a/app/models/concerns/inbox_agent_availability.rb b/app/models/concerns/inbox_agent_availability.rb
new file mode 100644
index 000000000..289da7db9
--- /dev/null
+++ b/app/models/concerns/inbox_agent_availability.rb
@@ -0,0 +1,28 @@
+module InboxAgentAvailability
+ extend ActiveSupport::Concern
+
+ def available_agents
+ online_agent_ids = fetch_online_agent_ids
+ return inbox_members.none if online_agent_ids.empty?
+
+ inbox_members
+ .joins(:user)
+ .where(users: { id: online_agent_ids })
+ .includes(:user)
+ end
+
+ def member_ids_with_assignment_capacity
+ member_ids
+ end
+
+ private
+
+ def fetch_online_agent_ids
+ OnlineStatusTracker.get_available_users(account_id)
+ .select { |_key, value| value.eql?('online') }
+ .keys
+ .map(&:to_i)
+ end
+end
+
+InboxAgentAvailability.prepend_mod_with('InboxAgentAvailability')
diff --git a/app/models/inbox.rb b/app/models/inbox.rb
index b0f13d222..894c57bcc 100644
--- a/app/models/inbox.rb
+++ b/app/models/inbox.rb
@@ -44,6 +44,7 @@ class Inbox < ApplicationRecord
include Avatarable
include OutOfOffisable
include AccountCacheRevalidator
+ include InboxAgentAvailability
# Not allowing characters:
validates :name, presence: true
@@ -190,6 +191,10 @@ class Inbox < ApplicationRecord
members.ids
end
+ def auto_assignment_v2_enabled?
+ account.feature_enabled?('assignment_v2')
+ end
+
private
def default_name_for_blank_name
diff --git a/app/services/auto_assignment/assignment_service.rb b/app/services/auto_assignment/assignment_service.rb
new file mode 100644
index 000000000..59e7b5a7b
--- /dev/null
+++ b/app/services/auto_assignment/assignment_service.rb
@@ -0,0 +1,90 @@
+class AutoAssignment::AssignmentService
+ pattr_initialize [:inbox!]
+
+ def perform_bulk_assignment(limit: 100)
+ return 0 unless inbox.auto_assignment_v2_enabled?
+
+ assigned_count = 0
+
+ unassigned_conversations(limit).each do |conversation|
+ assigned_count += 1 if perform_for_conversation(conversation)
+ end
+
+ assigned_count
+ end
+
+ private
+
+ def perform_for_conversation(conversation)
+ return false unless assignable?(conversation)
+
+ agent = find_available_agent
+ return false unless agent
+
+ assign_conversation(conversation, agent)
+ end
+
+ def assignable?(conversation)
+ conversation.status == 'open' &&
+ conversation.assignee_id.nil?
+ end
+
+ def unassigned_conversations(limit)
+ scope = inbox.conversations.unassigned.open
+
+ scope = if assignment_config['conversation_priority'].to_s == 'longest_waiting'
+ scope.reorder(last_activity_at: :asc, created_at: :asc)
+ else
+ scope.reorder(created_at: :asc)
+ end
+
+ scope.limit(limit)
+ end
+
+ def find_available_agent
+ agents = filter_agents_by_rate_limit(inbox.available_agents)
+ return nil if agents.empty?
+
+ round_robin_selector.select_agent(agents)
+ end
+
+ def filter_agents_by_rate_limit(agents)
+ agents.select do |agent_member|
+ rate_limiter = build_rate_limiter(agent_member.user)
+ rate_limiter.within_limit?
+ end
+ end
+
+ def assign_conversation(conversation, agent)
+ conversation.update!(assignee: agent)
+
+ rate_limiter = build_rate_limiter(agent)
+ rate_limiter.track_assignment(conversation)
+
+ dispatch_assignment_event(conversation, agent)
+ true
+ end
+
+ def dispatch_assignment_event(conversation, agent)
+ Rails.configuration.dispatcher.dispatch(
+ Events::Types::ASSIGNEE_CHANGED,
+ Time.zone.now,
+ conversation: conversation,
+ user: agent
+ )
+ end
+
+ def build_rate_limiter(agent)
+ AutoAssignment::RateLimiter.new(inbox: inbox, agent: agent)
+ end
+
+ def round_robin_selector
+ @round_robin_selector ||= AutoAssignment::RoundRobinSelector.new(inbox: inbox)
+ end
+
+ def assignment_config
+ @assignment_config ||= inbox.auto_assignment_config || {}
+ end
+end
+
+AutoAssignment::AssignmentService.prepend_mod_with('AutoAssignment::AssignmentService')
diff --git a/app/services/auto_assignment/rate_limiter.rb b/app/services/auto_assignment/rate_limiter.rb
new file mode 100644
index 000000000..d22f1f9b7
--- /dev/null
+++ b/app/services/auto_assignment/rate_limiter.rb
@@ -0,0 +1,49 @@
+class AutoAssignment::RateLimiter
+ pattr_initialize [:inbox!, :agent!]
+
+ def within_limit?
+ return true unless enabled?
+
+ current_count < limit
+ end
+
+ def track_assignment(conversation)
+ return unless enabled?
+
+ assignment_key = build_assignment_key(conversation.id)
+ Redis::Alfred.set(assignment_key, conversation.id.to_s, ex: window)
+ end
+
+ def current_count
+ return 0 unless enabled?
+
+ pattern = assignment_key_pattern
+ Redis::Alfred.keys_count(pattern)
+ end
+
+ private
+
+ def enabled?
+ limit.present? && limit.positive?
+ end
+
+ def limit
+ config&.fair_distribution_limit&.to_i || Math
+ end
+
+ def window
+ config&.fair_distribution_window&.to_i || 24.hours.to_i
+ end
+
+ def config
+ @config ||= inbox.assignment_policy
+ end
+
+ def assignment_key_pattern
+ format(Redis::RedisKeys::ASSIGNMENT_KEY_PATTERN, inbox_id: inbox.id, agent_id: agent.id)
+ end
+
+ def build_assignment_key(conversation_id)
+ format(Redis::RedisKeys::ASSIGNMENT_KEY, inbox_id: inbox.id, agent_id: agent.id, conversation_id: conversation_id)
+ end
+end
diff --git a/app/services/auto_assignment/round_robin_selector.rb b/app/services/auto_assignment/round_robin_selector.rb
new file mode 100644
index 000000000..65e72090d
--- /dev/null
+++ b/app/services/auto_assignment/round_robin_selector.rb
@@ -0,0 +1,16 @@
+class AutoAssignment::RoundRobinSelector
+ pattr_initialize [:inbox!]
+
+ def select_agent(available_agents)
+ return nil if available_agents.empty?
+
+ agent_user_ids = available_agents.map(&:user_id).map(&:to_s)
+ round_robin_service.available_agent(allowed_agent_ids: agent_user_ids)
+ end
+
+ private
+
+ def round_robin_service
+ @round_robin_service ||= AutoAssignment::InboxRoundRobinService.new(inbox: inbox)
+ end
+end
diff --git a/config/schedule.yml b/config/schedule.yml
index b5b21b4ce..c039719fa 100644
--- a/config/schedule.yml
+++ b/config/schedule.yml
@@ -53,3 +53,9 @@ bulk_auto_assignment_job:
cron: '*/15 * * * *'
class: 'Inboxes::BulkAutoAssignmentJob'
queue: scheduled_jobs
+
+# executed every 30 minutes for assignment_v2
+periodic_assignment_job:
+ cron: '*/30 * * * *'
+ class: 'AutoAssignment::PeriodicAssignmentJob'
+ queue: scheduled_jobs
diff --git a/enterprise/app/models/enterprise/concerns/inbox.rb b/enterprise/app/models/enterprise/concerns/inbox.rb
index 6f450bed1..0de61db23 100644
--- a/enterprise/app/models/enterprise/concerns/inbox.rb
+++ b/enterprise/app/models/enterprise/concerns/inbox.rb
@@ -6,5 +6,6 @@ module Enterprise::Concerns::Inbox
has_one :captain_assistant,
through: :captain_inbox,
class_name: 'Captain::Assistant'
+ has_many :inbox_capacity_limits, dependent: :destroy
end
end
diff --git a/enterprise/app/models/enterprise/inbox_agent_availability.rb b/enterprise/app/models/enterprise/inbox_agent_availability.rb
new file mode 100644
index 000000000..886b55278
--- /dev/null
+++ b/enterprise/app/models/enterprise/inbox_agent_availability.rb
@@ -0,0 +1,31 @@
+module Enterprise::InboxAgentAvailability
+ extend ActiveSupport::Concern
+
+ def member_ids_with_assignment_capacity
+ return member_ids unless capacity_filtering_enabled?
+
+ # Get online agents with capacity
+ agents = available_agents
+ agents = filter_by_capacity(agents)
+ agents.map(&:user_id)
+ end
+
+ private
+
+ def filter_by_capacity(inbox_members_scope)
+ return inbox_members_scope unless capacity_filtering_enabled?
+
+ inbox_members_scope.select do |inbox_member|
+ capacity_service.agent_has_capacity?(inbox_member.user, self)
+ end
+ end
+
+ def capacity_filtering_enabled?
+ account.feature_enabled?('assignment_v2') &&
+ account.account_users.joins(:agent_capacity_policy).exists?
+ end
+
+ def capacity_service
+ @capacity_service ||= Enterprise::AutoAssignment::CapacityService.new
+ end
+end
diff --git a/enterprise/app/services/enterprise/auto_assignment/assignment_service.rb b/enterprise/app/services/enterprise/auto_assignment/assignment_service.rb
new file mode 100644
index 000000000..4f3da08ee
--- /dev/null
+++ b/enterprise/app/services/enterprise/auto_assignment/assignment_service.rb
@@ -0,0 +1,94 @@
+module Enterprise::AutoAssignment::AssignmentService
+ private
+
+ # Override assignment config to use policy if available
+ def assignment_config
+ return super unless policy
+
+ {
+ 'conversation_priority' => policy.conversation_priority,
+ 'fair_distribution_limit' => policy.fair_distribution_limit,
+ 'fair_distribution_window' => policy.fair_distribution_window,
+ 'balanced' => policy.balanced?
+ }.compact
+ end
+
+ # Extend agent finding to add capacity checks
+ def find_available_agent
+ agents = filter_agents_by_rate_limit(inbox.available_agents)
+ agents = filter_agents_by_capacity(agents) if capacity_filtering_enabled?
+ return nil if agents.empty?
+
+ selector = policy&.balanced? ? balanced_selector : round_robin_selector
+ selector.select_agent(agents)
+ end
+
+ def filter_agents_by_capacity(agents)
+ return agents unless capacity_filtering_enabled?
+
+ capacity_service = Enterprise::AutoAssignment::CapacityService.new
+ agents.select { |agent_member| capacity_service.agent_has_capacity?(agent_member.user, inbox) }
+ end
+
+ def capacity_filtering_enabled?
+ account.feature_enabled?('assignment_v2') &&
+ account.account_users.joins(:agent_capacity_policy).exists?
+ end
+
+ def round_robin_selector
+ @round_robin_selector ||= AutoAssignment::RoundRobinSelector.new(inbox: inbox)
+ end
+
+ def balanced_selector
+ @balanced_selector ||= Enterprise::AutoAssignment::BalancedSelector.new(inbox: inbox)
+ end
+
+ def policy
+ @policy ||= inbox.assignment_policy
+ end
+
+ def account
+ inbox.account
+ end
+
+ # Override to apply exclusion rules
+ def unassigned_conversations(limit)
+ scope = inbox.conversations.unassigned.open
+
+ # Apply exclusion rules from capacity policy or assignment policy
+ scope = apply_exclusion_rules(scope)
+
+ # Apply conversation priority using enum methods if policy exists
+ scope = if policy&.longest_waiting?
+ scope.reorder(last_activity_at: :asc, created_at: :asc)
+ else
+ scope.reorder(created_at: :asc)
+ end
+
+ scope.limit(limit)
+ end
+
+ def apply_exclusion_rules(scope)
+ capacity_policy = inbox.inbox_capacity_limits.first&.agent_capacity_policy
+ return scope unless capacity_policy
+
+ exclusion_rules = capacity_policy.exclusion_rules || {}
+ scope = apply_label_exclusions(scope, exclusion_rules['excluded_labels'])
+ apply_age_exclusions(scope, exclusion_rules['exclude_older_than_hours'])
+ end
+
+ def apply_label_exclusions(scope, excluded_labels)
+ return scope if excluded_labels.blank?
+
+ scope.tagged_with(excluded_labels, exclude: true, on: :labels)
+ end
+
+ def apply_age_exclusions(scope, hours_threshold)
+ return scope if hours_threshold.blank?
+
+ hours = hours_threshold.to_i
+ return scope unless hours.positive?
+
+ scope.where('conversations.created_at >= ?', hours.hours.ago)
+ end
+end
diff --git a/enterprise/app/services/enterprise/auto_assignment/balanced_selector.rb b/enterprise/app/services/enterprise/auto_assignment/balanced_selector.rb
new file mode 100644
index 000000000..57017b6bb
--- /dev/null
+++ b/enterprise/app/services/enterprise/auto_assignment/balanced_selector.rb
@@ -0,0 +1,26 @@
+class Enterprise::AutoAssignment::BalancedSelector
+ pattr_initialize [:inbox!]
+
+ def select_agent(available_agents)
+ return nil if available_agents.empty?
+
+ agent_users = available_agents.map(&:user)
+ assignment_counts = fetch_assignment_counts(agent_users)
+
+ agent_users.min_by { |user| assignment_counts[user.id] || 0 }
+ end
+
+ private
+
+ def fetch_assignment_counts(users)
+ user_ids = users.map(&:id)
+
+ counts = inbox.conversations
+ .open
+ .where(assignee_id: user_ids)
+ .group(:assignee_id)
+ .count
+
+ Hash.new(0).merge(counts)
+ end
+end
diff --git a/enterprise/app/services/enterprise/auto_assignment/capacity_service.rb b/enterprise/app/services/enterprise/auto_assignment/capacity_service.rb
new file mode 100644
index 000000000..f82da9267
--- /dev/null
+++ b/enterprise/app/services/enterprise/auto_assignment/capacity_service.rb
@@ -0,0 +1,25 @@
+class Enterprise::AutoAssignment::CapacityService
+ def agent_has_capacity?(user, inbox)
+ # Get the account_user for this specific account
+ account_user = user.account_users.find_by(account: inbox.account)
+
+ # If no account_user or no capacity policy, agent has unlimited capacity
+ return true unless account_user&.agent_capacity_policy
+
+ policy = account_user.agent_capacity_policy
+
+ # Check if there's a specific limit for this inbox
+ inbox_limit = policy.inbox_capacity_limits.find_by(inbox: inbox)
+
+ # If no specific limit for this inbox, agent has unlimited capacity for this inbox
+ return true unless inbox_limit
+
+ # Count current open conversations for this agent in this inbox
+ current_count = user.assigned_conversations
+ .where(inbox: inbox, status: :open)
+ .count
+
+ # Agent has capacity if current count is below the limit
+ current_count < inbox_limit.conversation_limit
+ end
+end
diff --git a/lib/redis/alfred.rb b/lib/redis/alfred.rb
index b3e156420..e7e04ed60 100644
--- a/lib/redis/alfred.rb
+++ b/lib/redis/alfred.rb
@@ -35,6 +35,25 @@ module Redis::Alfred
$alfred.with { |conn| conn.exists?(key) }
end
+ # set expiry on a key in seconds
+ def expire(key, seconds)
+ $alfred.with { |conn| conn.expire(key, seconds) }
+ end
+
+ # scan keys matching a pattern
+ def scan_each(match: nil, count: 100, &)
+ $alfred.with do |conn|
+ conn.scan_each(match: match, count: count, &)
+ end
+ end
+
+ # count keys matching a pattern
+ def keys_count(pattern)
+ count = 0
+ scan_each(match: pattern) { count += 1 }
+ count
+ end
+
# list operations
def llen(key)
@@ -81,8 +100,15 @@ module Redis::Alfred
# sorted set operations
# add score and value for a key
- def zadd(key, score, value)
- $alfred.with { |conn| conn.zadd(key, score, value) }
+ # Modern Redis syntax: zadd(key, [[score, member], ...])
+ def zadd(key, score, value = nil)
+ if value.nil? && score.is_a?(Array)
+ # New syntax: score is actually an array of [score, member] pairs
+ $alfred.with { |conn| conn.zadd(key, score) }
+ else
+ # Support old syntax for backward compatibility
+ $alfred.with { |conn| conn.zadd(key, [[score, value]]) }
+ end
end
# get score of a value for key
@@ -90,9 +116,22 @@ module Redis::Alfred
$alfred.with { |conn| conn.zscore(key, value) }
end
+ # count members in a sorted set with scores within the given range
+ def zcount(key, min_score, max_score)
+ $alfred.with { |conn| conn.zcount(key, min_score, max_score) }
+ end
+
+ # get the number of members in a sorted set
+ def zcard(key)
+ $alfred.with { |conn| conn.zcard(key) }
+ end
+
# get values by score
- def zrangebyscore(key, range_start, range_end)
- $alfred.with { |conn| conn.zrangebyscore(key, range_start, range_end) }
+ def zrangebyscore(key, range_start, range_end, with_scores: false, limit: nil)
+ options = {}
+ options[:with_scores] = with_scores if with_scores
+ options[:limit] = limit if limit
+ $alfred.with { |conn| conn.zrangebyscore(key, range_start, range_end, **options) }
end
# remove values by score
diff --git a/lib/redis/redis_keys.rb b/lib/redis/redis_keys.rb
index fa64d1043..f5d297e5f 100644
--- a/lib/redis/redis_keys.rb
+++ b/lib/redis/redis_keys.rb
@@ -42,4 +42,9 @@ module Redis::RedisKeys
SLACK_MESSAGE_MUTEX = 'SLACK_MESSAGE_LOCK::%s::%s'.freeze
EMAIL_MESSAGE_MUTEX = 'EMAIL_CHANNEL_LOCK::%s'.freeze
CRM_PROCESS_MUTEX = 'CRM_PROCESS_MUTEX::%s'.freeze
+
+ ## Auto Assignment Keys
+ # Track conversation assignments to agents for rate limiting
+ ASSIGNMENT_KEY = 'ASSIGNMENT::%d::AGENT::%d::CONVERSATION::%d'.freeze
+ ASSIGNMENT_KEY_PATTERN = 'ASSIGNMENT::%d::AGENT::%d::*'.freeze
end
diff --git a/spec/enterprise/services/enterprise/auto_assignment/assignment_service_spec.rb b/spec/enterprise/services/enterprise/auto_assignment/assignment_service_spec.rb
new file mode 100644
index 000000000..432f397be
--- /dev/null
+++ b/spec/enterprise/services/enterprise/auto_assignment/assignment_service_spec.rb
@@ -0,0 +1,185 @@
+require 'rails_helper'
+
+RSpec.describe Enterprise::AutoAssignment::AssignmentService, type: :service do
+ let(:account) { create(:account) }
+ let(:assignment_policy) { create(:assignment_policy, account: account, enabled: true) }
+ let(:inbox) { create(:inbox, account: account) }
+ let(:agent1) { create(:user, account: account, name: 'Agent 1') }
+ let(:agent2) { create(:user, account: account, name: 'Agent 2') }
+ let(:assignment_service) { AutoAssignment::AssignmentService.new(inbox: inbox) }
+
+ before do
+ # Create inbox members
+ create(:inbox_member, inbox: inbox, user: agent1)
+ create(:inbox_member, inbox: inbox, user: agent2)
+
+ # Link inbox to assignment policy
+ create(:inbox_assignment_policy, inbox: inbox, assignment_policy: assignment_policy)
+
+ allow(account).to receive(:feature_enabled?).and_return(false)
+ allow(account).to receive(:feature_enabled?).with('assignment_v2').and_return(true)
+
+ # Set agents as online
+ OnlineStatusTracker.update_presence(account.id, 'User', agent1.id)
+ OnlineStatusTracker.set_status(account.id, agent1.id, 'online')
+ OnlineStatusTracker.update_presence(account.id, 'User', agent2.id)
+ OnlineStatusTracker.set_status(account.id, agent2.id, 'online')
+ end
+
+ describe 'exclusion rules' do
+ let(:capacity_policy) { create(:agent_capacity_policy, account: account) }
+ let(:label1) { create(:label, account: account, title: 'high-priority') }
+ let(:label2) { create(:label, account: account, title: 'vip') }
+
+ before do
+ create(:inbox_capacity_limit, inbox: inbox, agent_capacity_policy: capacity_policy, conversation_limit: 10)
+ inbox.enable_auto_assignment = true
+ inbox.save!
+ end
+
+ context 'when excluding conversations by label' do
+ let!(:conversation_with_label) { create(:conversation, inbox: inbox, assignee: nil) }
+ let!(:conversation_without_label) { create(:conversation, inbox: inbox, assignee: nil) }
+
+ before do
+ conversation_with_label.update_labels([label1.title])
+
+ capacity_policy.update!(exclusion_rules: {
+ 'excluded_labels' => [label1.title]
+ })
+ end
+
+ it 'excludes conversations with specified labels' do
+ # First check conversations are unassigned
+ expect(conversation_with_label.assignee).to be_nil
+ expect(conversation_without_label.assignee).to be_nil
+
+ # Run bulk assignment
+ assigned_count = assignment_service.perform_bulk_assignment(limit: 10)
+
+ # Only the conversation without label should be assigned
+ expect(assigned_count).to eq(1)
+ expect(conversation_with_label.reload.assignee).to be_nil
+ expect(conversation_without_label.reload.assignee).to be_present
+ end
+
+ it 'handles bulk assignment correctly' do
+ assigned_count = assignment_service.perform_bulk_assignment(limit: 10)
+
+ # Only 1 conversation should be assigned (the one without label)
+ expect(assigned_count).to eq(1)
+ expect(conversation_with_label.reload.assignee).to be_nil
+ expect(conversation_without_label.reload.assignee).to be_present
+ end
+
+ it 'excludes conversations with multiple labels' do
+ conversation_without_label.update_labels([label2.title])
+
+ capacity_policy.update!(exclusion_rules: {
+ 'excluded_labels' => [label1.title, label2.title]
+ })
+
+ assigned_count = assignment_service.perform_bulk_assignment(limit: 10)
+
+ # Both conversations should be excluded
+ expect(assigned_count).to eq(0)
+ expect(conversation_with_label.reload.assignee).to be_nil
+ expect(conversation_without_label.reload.assignee).to be_nil
+ end
+ end
+
+ context 'when excluding conversations by age' do
+ let!(:old_conversation) { create(:conversation, inbox: inbox, assignee: nil, created_at: 25.hours.ago) }
+ let!(:recent_conversation) { create(:conversation, inbox: inbox, assignee: nil, created_at: 1.hour.ago) }
+
+ before do
+ capacity_policy.update!(exclusion_rules: {
+ 'exclude_older_than_hours' => 24
+ })
+ end
+
+ it 'excludes conversations older than specified hours' do
+ assigned_count = assignment_service.perform_bulk_assignment(limit: 10)
+
+ # Only recent conversation should be assigned
+ expect(assigned_count).to eq(1)
+ expect(old_conversation.reload.assignee).to be_nil
+ expect(recent_conversation.reload.assignee).to be_present
+ end
+
+ it 'handles different time thresholds' do
+ capacity_policy.update!(exclusion_rules: {
+ 'exclude_older_than_hours' => 2
+ })
+
+ assigned_count = assignment_service.perform_bulk_assignment(limit: 10)
+
+ # Only conversation created within 2 hours should be assigned
+ expect(assigned_count).to eq(1)
+ expect(recent_conversation.reload.assignee).to be_present
+ end
+ end
+
+ context 'when combining exclusion rules' do
+ it 'applies both exclusion rules' do
+ # Create conversations
+ old_conversation_with_label = create(:conversation, inbox: inbox, assignee: nil, created_at: 25.hours.ago)
+ old_conversation_without_label = create(:conversation, inbox: inbox, assignee: nil, created_at: 25.hours.ago)
+ recent_conversation_with_label = create(:conversation, inbox: inbox, assignee: nil, created_at: 1.hour.ago)
+ recent_conversation_without_label = create(:conversation, inbox: inbox, assignee: nil, created_at: 1.hour.ago)
+
+ # Add labels
+ old_conversation_with_label.update_labels([label1.title])
+ recent_conversation_with_label.update_labels([label1.title])
+
+ capacity_policy.update!(exclusion_rules: {
+ 'excluded_labels' => [label1.title],
+ 'exclude_older_than_hours' => 24
+ })
+
+ assigned_count = assignment_service.perform_bulk_assignment(limit: 10)
+
+ # Only recent conversation without label should be assigned
+ expect(assigned_count).to eq(1)
+ expect(old_conversation_with_label.reload.assignee).to be_nil
+ expect(old_conversation_without_label.reload.assignee).to be_nil
+ expect(recent_conversation_with_label.reload.assignee).to be_nil
+ expect(recent_conversation_without_label.reload.assignee).to be_present
+ end
+ end
+
+ context 'when exclusion rules are empty' do
+ let!(:conversation1) { create(:conversation, inbox: inbox, assignee: nil) }
+ let!(:conversation2) { create(:conversation, inbox: inbox, assignee: nil) }
+
+ before do
+ capacity_policy.update!(exclusion_rules: {})
+ end
+
+ it 'assigns all eligible conversations' do
+ assigned_count = assignment_service.perform_bulk_assignment(limit: 10)
+
+ expect(assigned_count).to eq(2)
+ expect(conversation1.reload.assignee).to be_present
+ expect(conversation2.reload.assignee).to be_present
+ end
+ end
+
+ context 'when no capacity policy exists' do
+ let!(:conversation1) { create(:conversation, inbox: inbox, assignee: nil) }
+ let!(:conversation2) { create(:conversation, inbox: inbox, assignee: nil) }
+
+ before do
+ InboxCapacityLimit.destroy_all
+ end
+
+ it 'assigns all eligible conversations without exclusions' do
+ assigned_count = assignment_service.perform_bulk_assignment(limit: 10)
+
+ expect(assigned_count).to eq(2)
+ expect(conversation1.reload.assignee).to be_present
+ expect(conversation2.reload.assignee).to be_present
+ end
+ end
+ end
+end
diff --git a/spec/enterprise/services/enterprise/auto_assignment/balanced_selector_spec.rb b/spec/enterprise/services/enterprise/auto_assignment/balanced_selector_spec.rb
new file mode 100644
index 000000000..a2340ab0e
--- /dev/null
+++ b/spec/enterprise/services/enterprise/auto_assignment/balanced_selector_spec.rb
@@ -0,0 +1,88 @@
+require 'rails_helper'
+
+RSpec.describe Enterprise::AutoAssignment::BalancedSelector do
+ let(:account) { create(:account) }
+ let(:inbox) { create(:inbox, account: account) }
+ let(:selector) { described_class.new(inbox: inbox) }
+ let(:agent1) { create(:user, account: account, role: :agent, availability: :online) }
+ let(:agent2) { create(:user, account: account, role: :agent, availability: :online) }
+ let(:agent3) { create(:user, account: account, role: :agent, availability: :online) }
+ let(:member1) { create(:inbox_member, inbox: inbox, user: agent1) }
+ let(:member2) { create(:inbox_member, inbox: inbox, user: agent2) }
+ let(:member3) { create(:inbox_member, inbox: inbox, user: agent3) }
+
+ describe '#select_agent' do
+ context 'when selecting based on workload' do
+ let(:available_agents) { [member1, member2, member3] }
+
+ it 'selects the agent with least open conversations' do
+ # Agent1 has 3 open conversations
+ 3.times { create(:conversation, inbox: inbox, assignee: agent1, status: 'open') }
+
+ # Agent2 has 1 open conversation
+ create(:conversation, inbox: inbox, assignee: agent2, status: 'open')
+
+ # Agent3 has 2 open conversations
+ 2.times { create(:conversation, inbox: inbox, assignee: agent3, status: 'open') }
+
+ selected_agent = selector.select_agent(available_agents)
+
+ # Should select agent2 as they have the least conversations
+ expect(selected_agent).to eq(agent2)
+ end
+
+ it 'considers only open conversations' do
+ # Agent1 has 1 open and 3 resolved conversations
+ create(:conversation, inbox: inbox, assignee: agent1, status: 'open')
+ 3.times { create(:conversation, inbox: inbox, assignee: agent1, status: 'resolved') }
+
+ # Agent2 has 2 open conversations
+ 2.times { create(:conversation, inbox: inbox, assignee: agent2, status: 'open') }
+
+ selected_agent = selector.select_agent([member1, member2])
+
+ # Should select agent1 as they have fewer open conversations
+ expect(selected_agent).to eq(agent1)
+ end
+
+ it 'selects any agent when agents have equal workload' do
+ # All agents have same number of conversations
+ [member1, member2, member3].each do |member|
+ create(:conversation, inbox: inbox, assignee: member.user, status: 'open')
+ end
+
+ selected_agent = selector.select_agent(available_agents)
+
+ # Should select one of the agents (when equal, min_by returns the first one it finds)
+ expect([agent1, agent2, agent3]).to include(selected_agent)
+ end
+ end
+
+ context 'when no agents are available' do
+ it 'returns nil' do
+ selected_agent = selector.select_agent([])
+ expect(selected_agent).to be_nil
+ end
+ end
+
+ context 'when one agent is available' do
+ it 'returns that agent' do
+ selected_agent = selector.select_agent([member1])
+ expect(selected_agent).to eq(agent1)
+ end
+ end
+
+ context 'with new agents (no conversations)' do
+ it 'prioritizes agents with no conversations' do
+ # Agent1 and 2 have conversations
+ create(:conversation, inbox: inbox, assignee: agent1, status: 'open')
+ create(:conversation, inbox: inbox, assignee: agent2, status: 'open')
+
+ # Agent3 is new with no conversations
+ selected_agent = selector.select_agent([member1, member2, member3])
+
+ expect(selected_agent).to eq(agent3)
+ end
+ end
+ end
+end
diff --git a/spec/enterprise/services/enterprise/auto_assignment/capacity_service_spec.rb b/spec/enterprise/services/enterprise/auto_assignment/capacity_service_spec.rb
new file mode 100644
index 000000000..98d7c2172
--- /dev/null
+++ b/spec/enterprise/services/enterprise/auto_assignment/capacity_service_spec.rb
@@ -0,0 +1,119 @@
+require 'rails_helper'
+
+RSpec.describe Enterprise::AutoAssignment::CapacityService, type: :service do
+ let(:account) { create(:account) }
+ let(:inbox) { create(:inbox, account: account, enable_auto_assignment: true) }
+
+ # Assignment policy with rate limiting
+ let(:assignment_policy) do
+ create(:assignment_policy,
+ account: account,
+ enabled: true,
+ fair_distribution_limit: 5,
+ fair_distribution_window: 3600)
+ end
+
+ # Agent capacity policy
+ let(:agent_capacity_policy) do
+ create(:agent_capacity_policy, account: account, name: 'Limited Capacity')
+ end
+
+ # Agents with different capacity settings
+ let(:agent_with_capacity) { create(:user, account: account, role: :agent, availability: :online) }
+ let(:agent_without_capacity) { create(:user, account: account, role: :agent, availability: :online) }
+ let(:agent_at_capacity) { create(:user, account: account, role: :agent, availability: :online) }
+
+ before do
+ # Create inbox assignment policy
+ create(:inbox_assignment_policy, inbox: inbox, assignment_policy: assignment_policy)
+
+ # Set inbox capacity limit
+ create(:inbox_capacity_limit,
+ agent_capacity_policy: agent_capacity_policy,
+ inbox: inbox,
+ conversation_limit: 3)
+
+ # Assign capacity policy to specific agents
+ agent_with_capacity.account_users.find_by(account: account)
+ .update!(agent_capacity_policy: agent_capacity_policy)
+
+ agent_at_capacity.account_users.find_by(account: account)
+ .update!(agent_capacity_policy: agent_capacity_policy)
+
+ # Create inbox members
+ create(:inbox_member, inbox: inbox, user: agent_with_capacity)
+ create(:inbox_member, inbox: inbox, user: agent_without_capacity)
+ create(:inbox_member, inbox: inbox, user: agent_at_capacity)
+
+ # Mock online status
+ allow(OnlineStatusTracker).to receive(:get_available_users).and_return({
+ agent_with_capacity.id.to_s => 'online',
+ agent_without_capacity.id.to_s => 'online',
+ agent_at_capacity.id.to_s => 'online'
+ })
+
+ # Enable assignment_v2 feature
+ allow(account).to receive(:feature_enabled?).with('assignment_v2').and_return(true)
+
+ # Create existing assignments for agent_at_capacity (at limit)
+ 3.times do
+ create(:conversation, inbox: inbox, assignee: agent_at_capacity, status: :open)
+ end
+ end
+
+ describe 'capacity filtering' do
+ it 'excludes agents at capacity' do
+ # Get available agents respecting capacity
+ capacity_service = described_class.new
+ online_agents = inbox.available_agents
+ filtered_agents = online_agents.select do |inbox_member|
+ capacity_service.agent_has_capacity?(inbox_member.user, inbox)
+ end
+ available_users = filtered_agents.map(&:user)
+
+ expect(available_users).to include(agent_with_capacity)
+ expect(available_users).to include(agent_without_capacity) # No capacity policy = unlimited
+ expect(available_users).not_to include(agent_at_capacity) # At capacity limit
+ end
+
+ it 'respects inbox-specific capacity limits' do
+ capacity_service = described_class.new
+
+ expect(capacity_service.agent_has_capacity?(agent_with_capacity, inbox)).to be true
+ expect(capacity_service.agent_has_capacity?(agent_without_capacity, inbox)).to be true
+ expect(capacity_service.agent_has_capacity?(agent_at_capacity, inbox)).to be false
+ end
+ end
+
+ describe 'assignment with capacity' do
+ let(:service) { AutoAssignment::AssignmentService.new(inbox: inbox) }
+
+ it 'assigns to agents with available capacity' do
+ # Create conversation before assignment
+ conversation = create(:conversation, inbox: inbox, assignee: nil, status: :open)
+
+ # Mock the selector to prefer agent_at_capacity (but should skip due to capacity)
+ selector = instance_double(AutoAssignment::RoundRobinSelector)
+ allow(AutoAssignment::RoundRobinSelector).to receive(:new).and_return(selector)
+ allow(selector).to receive(:select_agent) do |agents|
+ agents.map(&:user).find { |u| [agent_with_capacity, agent_without_capacity].include?(u) }
+ end
+
+ assigned_count = service.perform_bulk_assignment(limit: 1)
+ expect(assigned_count).to eq(1)
+ expect(conversation.reload.assignee).to be_in([agent_with_capacity, agent_without_capacity])
+ expect(conversation.reload.assignee).not_to eq(agent_at_capacity)
+ end
+
+ it 'returns false when all agents are at capacity' do
+ # Fill up remaining agents
+ 3.times { create(:conversation, inbox: inbox, assignee: agent_with_capacity, status: :open) }
+
+ # agent_without_capacity has no limit, so should still be available
+ conversation2 = create(:conversation, inbox: inbox, assignee: nil, status: :open)
+ assigned_count = service.perform_bulk_assignment(limit: 1)
+ expect(assigned_count).to eq(1)
+ expect(conversation2.reload.assignee).to eq(agent_without_capacity)
+ end
+ end
+end
diff --git a/spec/jobs/auto_assignment/assignment_job_spec.rb b/spec/jobs/auto_assignment/assignment_job_spec.rb
new file mode 100644
index 000000000..d13f9fef8
--- /dev/null
+++ b/spec/jobs/auto_assignment/assignment_job_spec.rb
@@ -0,0 +1,85 @@
+require 'rails_helper'
+
+RSpec.describe AutoAssignment::AssignmentJob, type: :job do
+ let(:account) { create(:account) }
+ let(:inbox) { create(:inbox, account: account, enable_auto_assignment: true) }
+ let(:agent) { create(:user, account: account, role: :agent, availability: :online) }
+
+ before do
+ create(:inbox_member, inbox: inbox, user: agent)
+ end
+
+ describe '#perform' do
+ context 'when inbox exists' do
+ context 'when auto assignment is enabled' do
+ it 'calls the assignment service' do
+ service = instance_double(AutoAssignment::AssignmentService)
+ allow(AutoAssignment::AssignmentService).to receive(:new).with(inbox: inbox).and_return(service)
+ expect(service).to receive(:perform_bulk_assignment).with(limit: 100).and_return(5)
+
+ described_class.new.perform(inbox_id: inbox.id)
+ end
+
+ it 'logs the assignment count' do
+ service = instance_double(AutoAssignment::AssignmentService)
+ allow(AutoAssignment::AssignmentService).to receive(:new).and_return(service)
+ allow(service).to receive(:perform_bulk_assignment).and_return(3)
+
+ expect(Rails.logger).to receive(:info).with("Assigned 3 conversations for inbox #{inbox.id}")
+
+ described_class.new.perform(inbox_id: inbox.id)
+ end
+
+ it 'uses custom bulk limit from environment' do
+ allow(ENV).to receive(:fetch).with('AUTO_ASSIGNMENT_BULK_LIMIT', 100).and_return('50')
+
+ service = instance_double(AutoAssignment::AssignmentService)
+ allow(AutoAssignment::AssignmentService).to receive(:new).with(inbox: inbox).and_return(service)
+ expect(service).to receive(:perform_bulk_assignment).with(limit: 50).and_return(2)
+
+ described_class.new.perform(inbox_id: inbox.id)
+ end
+ end
+
+ context 'when auto assignment is disabled' do
+ before { inbox.update!(enable_auto_assignment: false) }
+
+ it 'calls the service which handles the disabled state' do
+ service = instance_double(AutoAssignment::AssignmentService)
+ allow(AutoAssignment::AssignmentService).to receive(:new).with(inbox: inbox).and_return(service)
+ expect(service).to receive(:perform_bulk_assignment).with(limit: 100).and_return(0)
+
+ described_class.new.perform(inbox_id: inbox.id)
+ end
+ end
+ end
+
+ context 'when inbox does not exist' do
+ it 'returns early without processing' do
+ expect(AutoAssignment::AssignmentService).not_to receive(:new)
+
+ described_class.new.perform(inbox_id: 999_999)
+ end
+ end
+
+ context 'when an error occurs' do
+ it 'logs the error and re-raises in test environment' do
+ service = instance_double(AutoAssignment::AssignmentService)
+ allow(AutoAssignment::AssignmentService).to receive(:new).and_return(service)
+ allow(service).to receive(:perform_bulk_assignment).and_raise(StandardError, 'Something went wrong')
+
+ expect(Rails.logger).to receive(:error).with("Bulk assignment failed for inbox #{inbox.id}: Something went wrong")
+
+ expect do
+ described_class.new.perform(inbox_id: inbox.id)
+ end.to raise_error(StandardError, 'Something went wrong')
+ end
+ end
+ end
+
+ describe 'job configuration' do
+ it 'is queued in the default queue' do
+ expect(described_class.queue_name).to eq('default')
+ end
+ end
+end
diff --git a/spec/jobs/auto_assignment/periodic_assignment_job_spec.rb b/spec/jobs/auto_assignment/periodic_assignment_job_spec.rb
new file mode 100644
index 000000000..4b06decd0
--- /dev/null
+++ b/spec/jobs/auto_assignment/periodic_assignment_job_spec.rb
@@ -0,0 +1,123 @@
+require 'rails_helper'
+
+RSpec.describe AutoAssignment::PeriodicAssignmentJob, type: :job do
+ let(:account) { create(:account) }
+ let(:inbox) { create(:inbox, account: account, enable_auto_assignment: true) }
+ let(:assignment_policy) { create(:assignment_policy, account: account) }
+ let(:inbox_assignment_policy) { create(:inbox_assignment_policy, inbox: inbox, assignment_policy: assignment_policy) }
+ let(:agent) { create(:user, account: account, role: :agent) }
+
+ before do
+ create(:inbox_member, inbox: inbox, user: agent)
+ end
+
+ describe '#perform' do
+ context 'when account has assignment_v2 feature enabled' do
+ before do
+ allow(account).to receive(:feature_enabled?).with('assignment_v2').and_return(true)
+ allow(Account).to receive(:find_in_batches).and_yield([account])
+ end
+
+ context 'when inbox has auto_assignment_v2 enabled' do
+ before do
+ allow(inbox).to receive(:auto_assignment_v2_enabled?).and_return(true)
+ inbox_relation = instance_double(ActiveRecord::Relation)
+ allow(account).to receive(:inboxes).and_return(inbox_relation)
+ allow(inbox_relation).to receive(:joins).with(:assignment_policy).and_return(inbox_relation)
+ allow(inbox_relation).to receive(:find_in_batches).and_yield([inbox])
+ end
+
+ it 'queues assignment job for eligible inboxes' do
+ inbox_assignment_policy # ensure it exists
+ expect(AutoAssignment::AssignmentJob).to receive(:perform_later).with(inbox_id: inbox.id)
+
+ described_class.new.perform
+ end
+
+ it 'processes multiple accounts' do
+ inbox_assignment_policy # ensure it exists
+ account2 = create(:account)
+ inbox2 = create(:inbox, account: account2, enable_auto_assignment: true)
+ policy2 = create(:assignment_policy, account: account2)
+ create(:inbox_assignment_policy, inbox: inbox2, assignment_policy: policy2)
+
+ allow(account2).to receive(:feature_enabled?).with('assignment_v2').and_return(true)
+ allow(inbox2).to receive(:auto_assignment_v2_enabled?).and_return(true)
+
+ inbox_relation2 = instance_double(ActiveRecord::Relation)
+ allow(account2).to receive(:inboxes).and_return(inbox_relation2)
+ allow(inbox_relation2).to receive(:joins).with(:assignment_policy).and_return(inbox_relation2)
+ allow(inbox_relation2).to receive(:find_in_batches).and_yield([inbox2])
+
+ allow(Account).to receive(:find_in_batches).and_yield([account]).and_yield([account2])
+
+ expect(AutoAssignment::AssignmentJob).to receive(:perform_later).with(inbox_id: inbox.id)
+ expect(AutoAssignment::AssignmentJob).to receive(:perform_later).with(inbox_id: inbox2.id)
+
+ described_class.new.perform
+ end
+ end
+
+ context 'when inbox does not have auto_assignment_v2 enabled' do
+ before do
+ allow(inbox).to receive(:auto_assignment_v2_enabled?).and_return(false)
+ end
+
+ it 'does not queue assignment job' do
+ expect(AutoAssignment::AssignmentJob).not_to receive(:perform_later)
+
+ described_class.new.perform
+ end
+ end
+ end
+
+ context 'when account does not have assignment_v2 feature enabled' do
+ before do
+ allow(account).to receive(:feature_enabled?).with('assignment_v2').and_return(false)
+ allow(Account).to receive(:find_in_batches).and_yield([account])
+ end
+
+ it 'does not process the account' do
+ expect(AutoAssignment::AssignmentJob).not_to receive(:perform_later)
+
+ described_class.new.perform
+ end
+ end
+
+ context 'with batch processing' do
+ it 'processes accounts in batches' do
+ accounts = []
+ # Create multiple accounts
+ 5.times do |_i|
+ acc = create(:account)
+ inb = create(:inbox, account: acc, enable_auto_assignment: true)
+ policy = create(:assignment_policy, account: acc)
+ create(:inbox_assignment_policy, inbox: inb, assignment_policy: policy)
+ allow(acc).to receive(:feature_enabled?).with('assignment_v2').and_return(true)
+ allow(inb).to receive(:auto_assignment_v2_enabled?).and_return(true)
+
+ inbox_relation = instance_double(ActiveRecord::Relation)
+ allow(acc).to receive(:inboxes).and_return(inbox_relation)
+ allow(inbox_relation).to receive(:joins).with(:assignment_policy).and_return(inbox_relation)
+ allow(inbox_relation).to receive(:find_in_batches).and_yield([inb])
+
+ accounts << acc
+ end
+
+ allow(Account).to receive(:find_in_batches) do |&block|
+ accounts.each { |acc| block.call([acc]) }
+ end
+
+ expect(Account).to receive(:find_in_batches).and_call_original
+
+ described_class.new.perform
+ end
+ end
+ end
+
+ describe 'job configuration' do
+ it 'is queued in the scheduled_jobs queue' do
+ expect(described_class.queue_name).to eq('scheduled_jobs')
+ end
+ end
+end
diff --git a/spec/services/auto_assignment/assignment_service_spec.rb b/spec/services/auto_assignment/assignment_service_spec.rb
new file mode 100644
index 000000000..535277714
--- /dev/null
+++ b/spec/services/auto_assignment/assignment_service_spec.rb
@@ -0,0 +1,310 @@
+require 'rails_helper'
+
+RSpec.describe AutoAssignment::AssignmentService do
+ let(:account) { create(:account) }
+ let(:assignment_policy) { create(:assignment_policy, account: account, enabled: true) }
+ let(:inbox) { create(:inbox, account: account, enable_auto_assignment: true) }
+ let(:service) { described_class.new(inbox: inbox) }
+ let(:agent) { create(:user, account: account, role: :agent, availability: :online) }
+ let(:agent2) { create(:user, account: account, role: :agent, availability: :online) }
+ let(:conversation) { create(:conversation, inbox: inbox, assignee: nil) }
+
+ before do
+ # Enable assignment_v2 feature for the account
+ allow(account).to receive(:feature_enabled?).with('assignment_v2').and_return(true)
+ # Link inbox to assignment policy
+ create(:inbox_assignment_policy, inbox: inbox, assignment_policy: assignment_policy)
+ create(:inbox_member, inbox: inbox, user: agent)
+ end
+
+ describe '#perform_bulk_assignment' do
+ context 'when auto assignment is enabled' do
+ let(:rate_limiter) { instance_double(AutoAssignment::RateLimiter) }
+
+ before do
+ allow(OnlineStatusTracker).to receive(:get_available_users).and_return({ agent.id.to_s => 'online' })
+
+ # Mock RoundRobinSelector to return the agent
+ round_robin_selector = instance_double(AutoAssignment::RoundRobinSelector)
+ allow(AutoAssignment::RoundRobinSelector).to receive(:new).and_return(round_robin_selector)
+ allow(round_robin_selector).to receive(:select_agent).and_return(agent)
+
+ # Mock RateLimiter to allow all assignments by default
+ allow(AutoAssignment::RateLimiter).to receive(:new).and_return(rate_limiter)
+ allow(rate_limiter).to receive(:within_limit?).and_return(true)
+ allow(rate_limiter).to receive(:track_assignment)
+ end
+
+ it 'assigns conversations to available agents' do
+ # Create conversation and ensure it's unassigned
+ conv = create(:conversation, inbox: inbox, status: 'open')
+ conv.update!(assignee_id: nil)
+
+ assigned_count = service.perform_bulk_assignment(limit: 1)
+
+ expect(assigned_count).to eq(1)
+ expect(conv.reload.assignee).to eq(agent)
+ end
+
+ it 'returns 0 when no agents are online' do
+ allow(OnlineStatusTracker).to receive(:get_available_users).and_return({})
+
+ assigned_count = service.perform_bulk_assignment(limit: 1)
+
+ expect(assigned_count).to eq(0)
+ expect(conversation.reload.assignee).to be_nil
+ end
+
+ it 'respects the limit parameter' do
+ 3.times do
+ conv = create(:conversation, inbox: inbox, status: 'open')
+ conv.update!(assignee_id: nil)
+ end
+
+ assigned_count = service.perform_bulk_assignment(limit: 2)
+
+ expect(assigned_count).to eq(2)
+ expect(inbox.conversations.unassigned.count).to eq(1)
+ end
+
+ it 'only assigns open conversations' do
+ conversation # ensure it exists
+ conversation.update!(assignee_id: nil)
+ resolved_conversation = create(:conversation, inbox: inbox, status: 'resolved')
+ resolved_conversation.update!(assignee_id: nil)
+
+ service.perform_bulk_assignment(limit: 10)
+
+ expect(conversation.reload.assignee).to eq(agent)
+ expect(resolved_conversation.reload.assignee).to be_nil
+ end
+
+ it 'does not reassign already assigned conversations' do
+ conversation # ensure it exists
+ conversation.update!(assignee_id: nil)
+ assigned_conversation = create(:conversation, inbox: inbox, assignee: agent)
+ unassigned_conversation = create(:conversation, inbox: inbox, status: 'open')
+ unassigned_conversation.update!(assignee_id: nil)
+
+ assigned_count = service.perform_bulk_assignment(limit: 10)
+
+ expect(assigned_count).to eq(2) # conversation + unassigned_conversation
+ expect(assigned_conversation.reload.assignee).to eq(agent)
+ expect(unassigned_conversation.reload.assignee).to eq(agent)
+ end
+
+ it 'dispatches assignee changed event' do
+ conversation # ensure it exists
+ conversation.update!(assignee_id: nil)
+
+ # The conversation model also dispatches a conversation.updated event
+ allow(Rails.configuration.dispatcher).to receive(:dispatch)
+ expect(Rails.configuration.dispatcher).to receive(:dispatch).with(
+ Events::Types::ASSIGNEE_CHANGED,
+ anything,
+ hash_including(conversation: conversation, user: agent)
+ )
+
+ service.perform_bulk_assignment(limit: 1)
+ end
+ end
+
+ context 'when auto assignment is disabled' do
+ before { assignment_policy.update!(enabled: false) }
+
+ it 'returns 0 without processing' do
+ assigned_count = service.perform_bulk_assignment(limit: 10)
+
+ expect(assigned_count).to eq(0)
+ expect(conversation.reload.assignee).to be_nil
+ end
+ end
+
+ context 'with conversation priority' do
+ let(:rate_limiter) { instance_double(AutoAssignment::RateLimiter) }
+
+ before do
+ allow(OnlineStatusTracker).to receive(:get_available_users).and_return({ agent.id.to_s => 'online' })
+
+ # Mock RoundRobinSelector to return the agent
+ round_robin_selector = instance_double(AutoAssignment::RoundRobinSelector)
+ allow(AutoAssignment::RoundRobinSelector).to receive(:new).and_return(round_robin_selector)
+ allow(round_robin_selector).to receive(:select_agent).and_return(agent)
+
+ # Mock RateLimiter to allow all assignments by default
+ allow(AutoAssignment::RateLimiter).to receive(:new).and_return(rate_limiter)
+ allow(rate_limiter).to receive(:within_limit?).and_return(true)
+ allow(rate_limiter).to receive(:track_assignment)
+ end
+
+ context 'when priority is longest_waiting' do
+ before do
+ allow(inbox).to receive(:auto_assignment_config).and_return({ 'conversation_priority' => 'longest_waiting' })
+ end
+
+ it 'assigns conversations with oldest last_activity_at first' do
+ old_conversation = create(:conversation,
+ inbox: inbox,
+ status: 'open',
+ created_at: 2.hours.ago,
+ last_activity_at: 2.hours.ago)
+ old_conversation.update!(assignee_id: nil)
+ new_conversation = create(:conversation,
+ inbox: inbox,
+ status: 'open',
+ created_at: 1.hour.ago,
+ last_activity_at: 1.hour.ago)
+ new_conversation.update!(assignee_id: nil)
+
+ service.perform_bulk_assignment(limit: 1)
+
+ expect(old_conversation.reload.assignee).to eq(agent)
+ expect(new_conversation.reload.assignee).to be_nil
+ end
+ end
+
+ context 'when priority is default' do
+ it 'assigns conversations by created_at' do
+ old_conversation = create(:conversation, inbox: inbox, status: 'open', created_at: 2.hours.ago)
+ old_conversation.update!(assignee_id: nil)
+ new_conversation = create(:conversation, inbox: inbox, status: 'open', created_at: 1.hour.ago)
+ new_conversation.update!(assignee_id: nil)
+
+ service.perform_bulk_assignment(limit: 1)
+
+ expect(old_conversation.reload.assignee).to eq(agent)
+ expect(new_conversation.reload.assignee).to be_nil
+ end
+ end
+ end
+
+ context 'with fair distribution' do
+ before do
+ create(:inbox_member, inbox: inbox, user: agent2)
+ allow(OnlineStatusTracker).to receive(:get_available_users).and_return({
+ agent.id.to_s => 'online',
+ agent2.id.to_s => 'online'
+ })
+ end
+
+ context 'when fair distribution is enabled' do
+ before do
+ allow(inbox).to receive(:auto_assignment_config).and_return({
+ 'fair_distribution_limit' => 2,
+ 'fair_distribution_window' => 3600
+ })
+ end
+
+ it 'respects the assignment limit per agent' do
+ # Mock RoundRobinSelector to select agent2
+ round_robin_selector = instance_double(AutoAssignment::RoundRobinSelector)
+ allow(AutoAssignment::RoundRobinSelector).to receive(:new).and_return(round_robin_selector)
+ allow(round_robin_selector).to receive(:select_agent).and_return(agent2)
+
+ # Mock agent1 at limit, agent2 not at limit
+ agent1_limiter = instance_double(AutoAssignment::RateLimiter)
+ agent2_limiter = instance_double(AutoAssignment::RateLimiter)
+
+ allow(AutoAssignment::RateLimiter).to receive(:new).with(inbox: inbox, agent: agent).and_return(agent1_limiter)
+ allow(AutoAssignment::RateLimiter).to receive(:new).with(inbox: inbox, agent: agent2).and_return(agent2_limiter)
+
+ allow(agent1_limiter).to receive(:within_limit?).and_return(false)
+ allow(agent2_limiter).to receive(:within_limit?).and_return(true)
+ allow(agent2_limiter).to receive(:track_assignment)
+
+ unassigned_conversation = create(:conversation, inbox: inbox, status: 'open')
+ unassigned_conversation.update!(assignee_id: nil)
+
+ service.perform_bulk_assignment(limit: 1)
+
+ expect(unassigned_conversation.reload.assignee).to eq(agent2)
+ end
+
+ it 'tracks assignments in Redis' do
+ conversation # ensure it exists
+ conversation.update!(assignee_id: nil)
+
+ # Mock RoundRobinSelector
+ round_robin_selector = instance_double(AutoAssignment::RoundRobinSelector)
+ allow(AutoAssignment::RoundRobinSelector).to receive(:new).and_return(round_robin_selector)
+ allow(round_robin_selector).to receive(:select_agent).and_return(agent)
+
+ limiter = instance_double(AutoAssignment::RateLimiter)
+ allow(AutoAssignment::RateLimiter).to receive(:new).and_return(limiter)
+ allow(limiter).to receive(:within_limit?).and_return(true)
+ expect(limiter).to receive(:track_assignment)
+
+ service.perform_bulk_assignment(limit: 1)
+ end
+
+ it 'allows assignments after window expires' do
+ # Mock RoundRobinSelector
+ round_robin_selector = instance_double(AutoAssignment::RoundRobinSelector)
+ allow(AutoAssignment::RoundRobinSelector).to receive(:new).and_return(round_robin_selector)
+ allow(round_robin_selector).to receive(:select_agent).and_return(agent, agent2)
+
+ # Mock RateLimiter to allow all
+ limiter = instance_double(AutoAssignment::RateLimiter)
+ allow(AutoAssignment::RateLimiter).to receive(:new).and_return(limiter)
+ allow(limiter).to receive(:within_limit?).and_return(true)
+ allow(limiter).to receive(:track_assignment)
+
+ # Simulate time passing for rate limit window
+ freeze_time do
+ 2.times do
+ conversation_new = create(:conversation, inbox: inbox, status: 'open')
+ conversation_new.update!(assignee_id: nil)
+ service.perform_bulk_assignment(limit: 1)
+ expect(conversation_new.reload.assignee).not_to be_nil
+ end
+ end
+
+ # Move forward past the window
+ travel_to(2.hours.from_now) do
+ new_conversation = create(:conversation, inbox: inbox, status: 'open')
+ new_conversation.update!(assignee_id: nil)
+ service.perform_bulk_assignment(limit: 1)
+ expect(new_conversation.reload.assignee).not_to be_nil
+ end
+ end
+ end
+
+ context 'when fair distribution is disabled' do
+ it 'assigns without rate limiting' do
+ 5.times do
+ conv = create(:conversation, inbox: inbox, status: 'open')
+ conv.update!(assignee_id: nil)
+ end
+
+ # Mock RoundRobinSelector
+ round_robin_selector = instance_double(AutoAssignment::RoundRobinSelector)
+ allow(AutoAssignment::RoundRobinSelector).to receive(:new).and_return(round_robin_selector)
+ allow(round_robin_selector).to receive(:select_agent).and_return(agent)
+
+ # Mock RateLimiter to allow all
+ limiter = instance_double(AutoAssignment::RateLimiter)
+ allow(AutoAssignment::RateLimiter).to receive(:new).and_return(limiter)
+ allow(limiter).to receive(:within_limit?).and_return(true)
+ allow(limiter).to receive(:track_assignment)
+
+ assigned_count = service.perform_bulk_assignment(limit: 5)
+ expect(assigned_count).to eq(5)
+ end
+ end
+
+ context 'with round robin assignment' do
+ it 'distributes conversations evenly among agents' do
+ conversations = Array.new(4) { create(:conversation, inbox: inbox, assignee: nil) }
+
+ service.perform_bulk_assignment(limit: 4)
+
+ agent1_count = conversations.count { |c| c.reload.assignee == agent }
+ agent2_count = conversations.count { |c| c.reload.assignee == agent2 }
+
+ # Should be distributed evenly (2 each) or close to even (3 and 1)
+ expect([agent1_count, agent2_count].sort).to eq([2, 2]).or(eq([1, 3]))
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/auto_assignment/rate_limiter_spec.rb b/spec/services/auto_assignment/rate_limiter_spec.rb
new file mode 100644
index 000000000..48a5367e3
--- /dev/null
+++ b/spec/services/auto_assignment/rate_limiter_spec.rb
@@ -0,0 +1,167 @@
+require 'rails_helper'
+
+RSpec.describe AutoAssignment::RateLimiter do
+ # Stub Math methods for testing when assignment_policy is nil
+ # rubocop:disable RSpec/BeforeAfterAll, RSpec/InstanceVariable
+ before(:all) do
+ @math_had_positive = Math.respond_to?(:positive?)
+ Math.define_singleton_method(:positive?) { false } unless @math_had_positive
+ end
+
+ after(:all) do
+ Math.singleton_class.send(:remove_method, :positive?) unless @math_had_positive
+ end
+ # rubocop:enable RSpec/BeforeAfterAll, RSpec/InstanceVariable
+
+ let(:account) { create(:account) }
+ let(:inbox) { create(:inbox, account: account) }
+ let(:agent) { create(:user, account: account, role: :agent) }
+ let(:conversation) { create(:conversation, inbox: inbox) }
+ let(:rate_limiter) { described_class.new(inbox: inbox, agent: agent) }
+
+ describe '#within_limit?' do
+ context 'when rate limiting is not enabled' do
+ before do
+ allow(inbox).to receive(:assignment_policy).and_return(nil)
+ end
+
+ it 'returns true' do
+ expect(rate_limiter.within_limit?).to be true
+ end
+ end
+
+ context 'when rate limiting is enabled' do
+ let(:assignment_policy) do
+ instance_double(AssignmentPolicy,
+ fair_distribution_limit: 5,
+ fair_distribution_window: 3600)
+ end
+
+ before do
+ allow(inbox).to receive(:assignment_policy).and_return(assignment_policy)
+ end
+
+ it 'returns true when under the limit' do
+ allow(rate_limiter).to receive(:current_count).and_return(3)
+ expect(rate_limiter.within_limit?).to be true
+ end
+
+ it 'returns false when at or over the limit' do
+ allow(rate_limiter).to receive(:current_count).and_return(5)
+ expect(rate_limiter.within_limit?).to be false
+ end
+ end
+ end
+
+ describe '#track_assignment' do
+ context 'when rate limiting is not enabled' do
+ before do
+ allow(inbox).to receive(:assignment_policy).and_return(nil)
+ end
+
+ it 'does not track the assignment' do
+ expect(Redis::Alfred).not_to receive(:set)
+ rate_limiter.track_assignment(conversation)
+ end
+ end
+
+ context 'when rate limiting is enabled' do
+ let(:assignment_policy) do
+ instance_double(AssignmentPolicy,
+ fair_distribution_limit: 5,
+ fair_distribution_window: 3600)
+ end
+
+ before do
+ allow(inbox).to receive(:assignment_policy).and_return(assignment_policy)
+ end
+
+ it 'creates a Redis key with correct expiry' do
+ expected_key = format(Redis::RedisKeys::ASSIGNMENT_KEY, inbox_id: inbox.id, agent_id: agent.id, conversation_id: conversation.id)
+ expect(Redis::Alfred).to receive(:set).with(
+ expected_key,
+ conversation.id.to_s,
+ ex: 3600
+ )
+ rate_limiter.track_assignment(conversation)
+ end
+ end
+ end
+
+ describe '#current_count' do
+ context 'when rate limiting is not enabled' do
+ before do
+ allow(inbox).to receive(:assignment_policy).and_return(nil)
+ end
+
+ it 'returns 0' do
+ expect(rate_limiter.current_count).to eq(0)
+ end
+ end
+
+ context 'when rate limiting is enabled' do
+ let(:assignment_policy) do
+ instance_double(AssignmentPolicy,
+ fair_distribution_limit: 5,
+ fair_distribution_window: 3600)
+ end
+
+ before do
+ allow(inbox).to receive(:assignment_policy).and_return(assignment_policy)
+ end
+
+ it 'counts matching Redis keys' do
+ pattern = format(Redis::RedisKeys::ASSIGNMENT_KEY_PATTERN, inbox_id: inbox.id, agent_id: agent.id)
+ allow(Redis::Alfred).to receive(:keys_count).with(pattern).and_return(3)
+
+ expect(rate_limiter.current_count).to eq(3)
+ end
+ end
+ end
+
+ describe 'configuration' do
+ context 'with custom window' do
+ let(:assignment_policy) do
+ instance_double(AssignmentPolicy,
+ fair_distribution_limit: 10,
+ fair_distribution_window: 7200)
+ end
+
+ before do
+ allow(inbox).to receive(:assignment_policy).and_return(assignment_policy)
+ end
+
+ it 'uses the custom window value' do
+ expected_key = format(Redis::RedisKeys::ASSIGNMENT_KEY, inbox_id: inbox.id, agent_id: agent.id, conversation_id: conversation.id)
+ expect(Redis::Alfred).to receive(:set).with(
+ expected_key,
+ conversation.id.to_s,
+ ex: 7200
+ )
+ rate_limiter.track_assignment(conversation)
+ end
+ end
+
+ context 'without custom window' do
+ let(:assignment_policy) do
+ instance_double(AssignmentPolicy,
+ fair_distribution_limit: 10,
+ fair_distribution_window: nil)
+ end
+
+ before do
+ allow(inbox).to receive(:assignment_policy).and_return(assignment_policy)
+ end
+
+ it 'uses the default window value of 24 hours' do
+ expected_key = format(Redis::RedisKeys::ASSIGNMENT_KEY, inbox_id: inbox.id, agent_id: agent.id, conversation_id: conversation.id)
+ expect(Redis::Alfred).to receive(:set).with(
+ expected_key,
+ conversation.id.to_s,
+ ex: 86_400
+ )
+ rate_limiter.track_assignment(conversation)
+ end
+ end
+ end
+end
diff --git a/spec/services/auto_assignment/round_robin_selector_spec.rb b/spec/services/auto_assignment/round_robin_selector_spec.rb
new file mode 100644
index 000000000..05c1dcd73
--- /dev/null
+++ b/spec/services/auto_assignment/round_robin_selector_spec.rb
@@ -0,0 +1,78 @@
+require 'rails_helper'
+
+RSpec.describe AutoAssignment::RoundRobinSelector do
+ let(:account) { create(:account) }
+ let(:inbox) { create(:inbox, account: account) }
+ let(:selector) { described_class.new(inbox: inbox) }
+ let(:agent1) { create(:user, account: account, role: :agent, availability: :online) }
+ let(:agent2) { create(:user, account: account, role: :agent, availability: :online) }
+ let(:agent3) { create(:user, account: account, role: :agent, availability: :online) }
+
+ let(:round_robin_service) { instance_double(AutoAssignment::InboxRoundRobinService) }
+
+ let(:member1) do
+ allow(AutoAssignment::InboxRoundRobinService).to receive(:new).and_return(round_robin_service)
+ allow(round_robin_service).to receive(:add_agent_to_queue)
+ create(:inbox_member, inbox: inbox, user: agent1)
+ end
+
+ let(:member2) do
+ allow(AutoAssignment::InboxRoundRobinService).to receive(:new).and_return(round_robin_service)
+ allow(round_robin_service).to receive(:add_agent_to_queue)
+ create(:inbox_member, inbox: inbox, user: agent2)
+ end
+
+ let(:member3) do
+ allow(AutoAssignment::InboxRoundRobinService).to receive(:new).and_return(round_robin_service)
+ allow(round_robin_service).to receive(:add_agent_to_queue)
+ create(:inbox_member, inbox: inbox, user: agent3)
+ end
+
+ before do
+ # Mock the round robin service to avoid Redis calls
+ allow(AutoAssignment::InboxRoundRobinService).to receive(:new).and_return(round_robin_service)
+ allow(round_robin_service).to receive(:add_agent_to_queue)
+ allow(round_robin_service).to receive(:reset_queue)
+ allow(round_robin_service).to receive(:validate_queue?).and_return(true)
+ end
+
+ describe '#select_agent' do
+ context 'when agents are available' do
+ let(:available_agents) { [member1, member2, member3] }
+
+ it 'returns an agent from the available list' do
+ allow(round_robin_service).to receive(:available_agent).and_return(agent1)
+
+ selected_agent = selector.select_agent(available_agents)
+
+ expect(selected_agent).not_to be_nil
+ expect([agent1, agent2, agent3]).to include(selected_agent)
+ end
+
+ it 'uses round robin service for selection' do
+ expect(round_robin_service).to receive(:available_agent).with(
+ allowed_agent_ids: [agent1.id.to_s, agent2.id.to_s, agent3.id.to_s]
+ ).and_return(agent1)
+
+ selected_agent = selector.select_agent(available_agents)
+ expect(selected_agent).to eq(agent1)
+ end
+ end
+
+ context 'when no agents are available' do
+ it 'returns nil' do
+ selected_agent = selector.select_agent([])
+ expect(selected_agent).to be_nil
+ end
+ end
+
+ context 'when one agent is available' do
+ it 'returns that agent' do
+ allow(round_robin_service).to receive(:available_agent).and_return(agent1)
+
+ selected_agent = selector.select_agent([member1])
+ expect(selected_agent).to eq(agent1)
+ end
+ end
+ end
+end
From 93374f4327c5bad15179de8841c0bf427c302a2d Mon Sep 17 00:00:00 2001
From: Vinay Keerthi <11478411+stonecharioteer@users.noreply.github.com>
Date: Mon, 17 Nov 2025 16:09:36 +0530
Subject: [PATCH 70/80] fix: Change contact_inboxes.source_id to text column
(#12882)
## Description
Fixes CW-5961 where IMAP email processing failed with
`ActiveRecord::RecordInvalid: Validation failed: Source is too long
(maximum is 255 characters)` error.
This changes the `contact_inboxes.source_id` column from `string` (255
character limit) to `text` (unlimited) to accommodate long email message
IDs that were causing validation failures.
Fixes CW-5961
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
- Added spec test validating `source_id` values longer than 255
characters (300 chars)
- All existing `contact_inbox_spec.rb` tests pass (7 examples, 0
failures)
- Migration applied successfully with reversible up/down methods
- Verified `source_id` column type changed to `text` with `null: false`
constraint preserved
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
---
app/models/contact_inbox.rb | 2 +-
app/models/conversation.rb | 1 +
.../20251114173609_change_source_id_to_text.rb | 9 +++++++++
db/schema.rb | 6 +++---
spec/models/contact_inbox_spec.rb | 12 ++++++++++++
5 files changed, 26 insertions(+), 4 deletions(-)
create mode 100644 db/migrate/20251114173609_change_source_id_to_text.rb
diff --git a/app/models/contact_inbox.rb b/app/models/contact_inbox.rb
index 6d034880e..893ab87f3 100644
--- a/app/models/contact_inbox.rb
+++ b/app/models/contact_inbox.rb
@@ -9,7 +9,7 @@
# updated_at :datetime not null
# contact_id :bigint
# inbox_id :bigint
-# source_id :string not null
+# source_id :text not null
#
# Indexes
#
diff --git a/app/models/conversation.rb b/app/models/conversation.rb
index eb97a22e8..ca8a3258e 100644
--- a/app/models/conversation.rb
+++ b/app/models/conversation.rb
@@ -40,6 +40,7 @@
# index_conversations_on_contact_inbox_id (contact_inbox_id)
# index_conversations_on_first_reply_created_at (first_reply_created_at)
# index_conversations_on_id_and_account_id (account_id,id)
+# index_conversations_on_identifier_and_account_id (identifier,account_id)
# index_conversations_on_inbox_id (inbox_id)
# index_conversations_on_priority (priority)
# index_conversations_on_status_and_account_id (status,account_id)
diff --git a/db/migrate/20251114173609_change_source_id_to_text.rb b/db/migrate/20251114173609_change_source_id_to_text.rb
new file mode 100644
index 000000000..c6a41131f
--- /dev/null
+++ b/db/migrate/20251114173609_change_source_id_to_text.rb
@@ -0,0 +1,9 @@
+class ChangeSourceIdToText < ActiveRecord::Migration[7.1]
+ def up
+ change_column :contact_inboxes, :source_id, :text, null: false
+ end
+
+ def down
+ change_column :contact_inboxes, :source_id, :string, null: false
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 0aeea5cc9..7b893ecd2 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.1].define(version: 2025_10_22_152158) do
+ActiveRecord::Schema[7.1].define(version: 2025_11_14_173609) do
# These extensions should be enabled to support this database
enable_extension "pg_stat_statements"
enable_extension "pg_trgm"
@@ -585,7 +585,7 @@ ActiveRecord::Schema[7.1].define(version: 2025_10_22_152158) do
create_table "contact_inboxes", force: :cascade do |t|
t.bigint "contact_id"
t.bigint "inbox_id"
- t.string "source_id", null: false
+ t.text "source_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "hmac_verified", default: false
@@ -676,7 +676,7 @@ ActiveRecord::Schema[7.1].define(version: 2025_10_22_152158) do
t.index ["contact_id"], name: "index_conversations_on_contact_id"
t.index ["contact_inbox_id"], name: "index_conversations_on_contact_inbox_id"
t.index ["first_reply_created_at"], name: "index_conversations_on_first_reply_created_at"
- t.index ["identifier", "account_id"], name: "index_conversations_on_identifier_and_account_id"
+ t.index ["identifier", "account_id"], name: "index_conversations_on_identifier_and_account_id"
t.index ["inbox_id"], name: "index_conversations_on_inbox_id"
t.index ["priority"], name: "index_conversations_on_priority"
t.index ["status", "account_id"], name: "index_conversations_on_status_and_account_id"
diff --git a/spec/models/contact_inbox_spec.rb b/spec/models/contact_inbox_spec.rb
index 23d4b7bc7..c0a2faf9e 100644
--- a/spec/models/contact_inbox_spec.rb
+++ b/spec/models/contact_inbox_spec.rb
@@ -40,6 +40,18 @@ RSpec.describe ContactInbox do
describe 'validations' do
context 'when source_id' do
+ it 'allows source_id longer than 255 characters for channels without format restrictions' do
+ long_source_id = 'a' * 300
+ email_inbox = create(:inbox, channel: create(:channel_email))
+ contact = create(:contact, account: email_inbox.account)
+ contact_inbox = build(:contact_inbox, contact: contact, inbox: email_inbox, source_id: long_source_id)
+
+ expect(contact_inbox.valid?).to be(true)
+ expect { contact_inbox.save! }.not_to raise_error
+ expect(contact_inbox.reload.source_id).to eq(long_source_id)
+ expect(contact_inbox.source_id.length).to eq(300)
+ end
+
it 'validates whatsapp channel source_id' do
whatsapp_inbox = create(:channel_whatsapp, sync_templates: false, validate_provider_config: false).inbox
contact = create(:contact)
From bf806f0c284b5b407b0e180da335fb16f7829853 Mon Sep 17 00:00:00 2001
From: Sojan Jose
Date: Mon, 17 Nov 2025 14:03:08 -0800
Subject: [PATCH 71/80] feat: allow configuring attachment upload limit
(#12835)
## Summary
- add a configurable MAXIMUM_FILE_UPLOAD_SIZE installation setting and
surface it through super admin and global config payloads
- apply the configurable limit to attachment validations and shared
upload helpers on dashboard and widget
- introduce a reusable helper with unit tests for parsing the limit and
extend attachment specs for configurability
------
[Codex
Task](https://chatgpt.com/codex/tasks/task_e_6912644786b08326bc8dee9401af6d0a)
---------
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: iamsivin
---
.../api/v1/widget/configs_controller.rb | 8 +++-
app/controllers/dashboard_controller.rb | 45 +++++++++++--------
.../super_admin/app_configs_controller.rb | 5 ++-
app/controllers/widgets_controller.rb | 9 +++-
.../composables/spec/useFileUpload.spec.js | 14 ++++--
.../dashboard/composables/useFileUpload.js | 30 ++++++++++---
.../dashboard/mixins/fileUploadMixin.js | 31 ++++++++++---
.../mixins/specs/fileUploadMixin.spec.js | 3 ++
app/javascript/shared/constants/messages.js | 3 --
app/javascript/shared/helpers/FileHelper.js | 12 +++++
.../shared/helpers/specs/FileHelper.spec.js | 26 +++++++++++
app/javascript/shared/store/globalConfig.js | 3 ++
.../widget/components/ChatAttachment.vue | 16 ++++---
app/models/attachment.rb | 5 ++-
config/installation_config.yml | 5 +++
spec/models/attachment_spec.rb | 35 +++++++++++++++
16 files changed, 204 insertions(+), 46 deletions(-)
diff --git a/app/controllers/api/v1/widget/configs_controller.rb b/app/controllers/api/v1/widget/configs_controller.rb
index ecbddd905..458d0486c 100644
--- a/app/controllers/api/v1/widget/configs_controller.rb
+++ b/app/controllers/api/v1/widget/configs_controller.rb
@@ -9,7 +9,13 @@ class Api::V1::Widget::ConfigsController < Api::V1::Widget::BaseController
private
def set_global_config
- @global_config = GlobalConfig.get('LOGO_THUMBNAIL', 'BRAND_NAME', 'WIDGET_BRAND_URL', 'INSTALLATION_NAME')
+ @global_config = GlobalConfig.get(
+ 'LOGO_THUMBNAIL',
+ 'BRAND_NAME',
+ 'WIDGET_BRAND_URL',
+ 'MAXIMUM_FILE_UPLOAD_SIZE',
+ 'INSTALLATION_NAME'
+ )
end
def set_contact
diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb
index d81b4c9da..57e8af0c2 100644
--- a/app/controllers/dashboard_controller.rb
+++ b/app/controllers/dashboard_controller.rb
@@ -1,6 +1,31 @@
class DashboardController < ActionController::Base
include SwitchLocale
+ GLOBAL_CONFIG_KEYS = %w[
+ LOGO
+ LOGO_DARK
+ LOGO_THUMBNAIL
+ INSTALLATION_NAME
+ WIDGET_BRAND_URL
+ TERMS_URL
+ BRAND_URL
+ BRAND_NAME
+ PRIVACY_URL
+ DISPLAY_MANIFEST
+ CREATE_NEW_ACCOUNT_FROM_DASHBOARD
+ CHATWOOT_INBOX_TOKEN
+ API_CHANNEL_NAME
+ API_CHANNEL_THUMBNAIL
+ ANALYTICS_TOKEN
+ DIRECT_UPLOADS_ENABLED
+ MAXIMUM_FILE_UPLOAD_SIZE
+ HCAPTCHA_SITE_KEY
+ LOGOUT_REDIRECT_LINK
+ DISABLE_USER_PROFILE_UPDATE
+ DEPLOYMENT_ENV
+ INSTALLATION_PRICING_PLAN
+ ].freeze
+
before_action :set_application_pack
before_action :set_global_config
before_action :set_dashboard_scripts
@@ -19,25 +44,7 @@ class DashboardController < ActionController::Base
end
def set_global_config
- @global_config = GlobalConfig.get(
- 'LOGO', 'LOGO_DARK', 'LOGO_THUMBNAIL',
- 'INSTALLATION_NAME',
- 'WIDGET_BRAND_URL', 'TERMS_URL',
- 'BRAND_URL', 'BRAND_NAME',
- 'PRIVACY_URL',
- 'DISPLAY_MANIFEST',
- 'CREATE_NEW_ACCOUNT_FROM_DASHBOARD',
- 'CHATWOOT_INBOX_TOKEN',
- 'API_CHANNEL_NAME',
- 'API_CHANNEL_THUMBNAIL',
- 'ANALYTICS_TOKEN',
- 'DIRECT_UPLOADS_ENABLED',
- 'HCAPTCHA_SITE_KEY',
- 'LOGOUT_REDIRECT_LINK',
- 'DISABLE_USER_PROFILE_UPDATE',
- 'DEPLOYMENT_ENV',
- 'INSTALLATION_PRICING_PLAN'
- ).merge(app_config)
+ @global_config = GlobalConfig.get(*GLOBAL_CONFIG_KEYS).merge(app_config)
end
def set_dashboard_scripts
diff --git a/app/controllers/super_admin/app_configs_controller.rb b/app/controllers/super_admin/app_configs_controller.rb
index 5cf158b98..483c300bd 100644
--- a/app/controllers/super_admin/app_configs_controller.rb
+++ b/app/controllers/super_admin/app_configs_controller.rb
@@ -45,7 +45,10 @@ class SuperAdmin::AppConfigsController < SuperAdmin::ApplicationController
'google' => %w[GOOGLE_OAUTH_CLIENT_ID GOOGLE_OAUTH_CLIENT_SECRET GOOGLE_OAUTH_REDIRECT_URI]
}
- @allowed_configs = mapping.fetch(@config, %w[ENABLE_ACCOUNT_SIGNUP FIREBASE_PROJECT_ID FIREBASE_CREDENTIALS])
+ @allowed_configs = mapping.fetch(
+ @config,
+ %w[ENABLE_ACCOUNT_SIGNUP FIREBASE_PROJECT_ID FIREBASE_CREDENTIALS MAXIMUM_FILE_UPLOAD_SIZE]
+ )
end
end
diff --git a/app/controllers/widgets_controller.rb b/app/controllers/widgets_controller.rb
index 9a6a376f7..7f45ce636 100644
--- a/app/controllers/widgets_controller.rb
+++ b/app/controllers/widgets_controller.rb
@@ -14,7 +14,14 @@ class WidgetsController < ActionController::Base
private
def set_global_config
- @global_config = GlobalConfig.get('LOGO_THUMBNAIL', 'BRAND_NAME', 'WIDGET_BRAND_URL', 'DIRECT_UPLOADS_ENABLED', 'INSTALLATION_NAME')
+ @global_config = GlobalConfig.get(
+ 'LOGO_THUMBNAIL',
+ 'BRAND_NAME',
+ 'WIDGET_BRAND_URL',
+ 'DIRECT_UPLOADS_ENABLED',
+ 'MAXIMUM_FILE_UPLOAD_SIZE',
+ 'INSTALLATION_NAME'
+ )
end
def set_web_widget
diff --git a/app/javascript/dashboard/composables/spec/useFileUpload.spec.js b/app/javascript/dashboard/composables/spec/useFileUpload.spec.js
index 968a1b057..993eae2cc 100644
--- a/app/javascript/dashboard/composables/spec/useFileUpload.spec.js
+++ b/app/javascript/dashboard/composables/spec/useFileUpload.spec.js
@@ -12,7 +12,11 @@ vi.mock('dashboard/composables', () => ({
}));
vi.mock('vue-i18n');
vi.mock('activestorage');
-vi.mock('shared/helpers/FileHelper');
+vi.mock('shared/helpers/FileHelper', () => ({
+ checkFileSizeLimit: vi.fn(),
+ resolveMaximumFileUploadSize: vi.fn(value => Number(value) || 40),
+ DEFAULT_MAXIMUM_FILE_UPLOAD_SIZE: 40,
+}));
vi.mock('@chatwoot/utils');
describe('useFileUpload', () => {
@@ -36,7 +40,9 @@ describe('useFileUpload', () => {
getCurrentAccountId: { value: '123' },
getCurrentUser: { value: { access_token: 'test-token' } },
getSelectedChat: { value: { id: '456' } },
- 'globalConfig/get': { value: { directUploadsEnabled: true } },
+ 'globalConfig/get': {
+ value: { directUploadsEnabled: true, maximumFileUploadSize: 40 },
+ },
};
return getterMap[getter];
});
@@ -86,7 +92,9 @@ describe('useFileUpload', () => {
getCurrentAccountId: { value: '123' },
getCurrentUser: { value: { access_token: 'test-token' } },
getSelectedChat: { value: { id: '456' } },
- 'globalConfig/get': { value: { directUploadsEnabled: false } },
+ 'globalConfig/get': {
+ value: { directUploadsEnabled: false, maximumFileUploadSize: 40 },
+ },
};
return getterMap[getter];
});
diff --git a/app/javascript/dashboard/composables/useFileUpload.js b/app/javascript/dashboard/composables/useFileUpload.js
index c0105d321..a0c7e3297 100644
--- a/app/javascript/dashboard/composables/useFileUpload.js
+++ b/app/javascript/dashboard/composables/useFileUpload.js
@@ -4,7 +4,11 @@ import { useI18n } from 'vue-i18n';
import { DirectUpload } from 'activestorage';
import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
import { getMaxUploadSizeByChannel } from '@chatwoot/utils';
-import { MAXIMUM_FILE_UPLOAD_SIZE } from 'shared/constants/messages';
+import {
+ DEFAULT_MAXIMUM_FILE_UPLOAD_SIZE,
+ resolveMaximumFileUploadSize,
+} from 'shared/helpers/FileHelper';
+import { INBOX_TYPES } from 'dashboard/helper/inbox';
/**
* Composable for handling file uploads in conversations
@@ -21,18 +25,34 @@ export const useFileUpload = ({ inbox, attachFile, isPrivateNote = false }) => {
const currentChat = useMapGetter('getSelectedChat');
const globalConfig = useMapGetter('globalConfig/get');
+ const installationLimit = resolveMaximumFileUploadSize(
+ globalConfig.value?.maximumFileUploadSize
+ );
+
// helper: compute max upload size for a given file's mime
const maxSizeFor = mime => {
- // Use default file size limit for private notes
+ // Use default/installation limit for private notes
if (isPrivateNote) {
- return MAXIMUM_FILE_UPLOAD_SIZE;
+ return installationLimit;
}
- return getMaxUploadSizeByChannel({
- channelType: inbox?.channel_type,
+ const channelType = inbox?.channel_type;
+
+ if (!channelType || channelType === INBOX_TYPES.WEB) {
+ return installationLimit;
+ }
+
+ const channelLimit = getMaxUploadSizeByChannel({
+ channelType,
medium: inbox?.medium, // e.g. 'sms' | 'whatsapp' | etc.
mime, // e.g. 'image/png'
});
+
+ if (channelLimit === DEFAULT_MAXIMUM_FILE_UPLOAD_SIZE) {
+ return installationLimit;
+ }
+
+ return Math.min(channelLimit, installationLimit);
};
const alertOverLimit = maxSizeMB =>
diff --git a/app/javascript/dashboard/mixins/fileUploadMixin.js b/app/javascript/dashboard/mixins/fileUploadMixin.js
index 5313be812..965846401 100644
--- a/app/javascript/dashboard/mixins/fileUploadMixin.js
+++ b/app/javascript/dashboard/mixins/fileUploadMixin.js
@@ -3,27 +3,48 @@ import { useAlert } from 'dashboard/composables';
import { checkFileSizeLimit } from 'shared/helpers/FileHelper';
import { getMaxUploadSizeByChannel } from '@chatwoot/utils';
import { DirectUpload } from 'activestorage';
-import { MAXIMUM_FILE_UPLOAD_SIZE } from 'shared/constants/messages';
+import {
+ DEFAULT_MAXIMUM_FILE_UPLOAD_SIZE,
+ resolveMaximumFileUploadSize,
+} from 'shared/helpers/FileHelper';
+import { INBOX_TYPES } from 'dashboard/helper/inbox';
export default {
computed: {
...mapGetters({
accountId: 'getCurrentAccountId',
}),
+ installationLimit() {
+ return resolveMaximumFileUploadSize(
+ this.globalConfig.maximumFileUploadSize
+ );
+ },
},
methods: {
maxSizeFor(mime) {
- // Use default file size limit for private notes
+ // Use default/installation limit for private notes
if (this.isOnPrivateNote) {
- return MAXIMUM_FILE_UPLOAD_SIZE;
+ return this.installationLimit;
}
- return getMaxUploadSizeByChannel({
- channelType: this.inbox?.channel_type,
+ const channelType = this.inbox?.channel_type;
+
+ if (!channelType || channelType === INBOX_TYPES.WEB) {
+ return this.installationLimit;
+ }
+
+ const channelLimit = getMaxUploadSizeByChannel({
+ channelType,
medium: this.inbox?.medium, // e.g. 'sms' | 'whatsapp'
mime, // e.g. 'image/png'
});
+
+ if (channelLimit === DEFAULT_MAXIMUM_FILE_UPLOAD_SIZE) {
+ return this.installationLimit;
+ }
+
+ return Math.min(channelLimit, this.installationLimit);
},
alertOverLimit(maxSizeMB) {
useAlert(
diff --git a/app/javascript/dashboard/mixins/specs/fileUploadMixin.spec.js b/app/javascript/dashboard/mixins/specs/fileUploadMixin.spec.js
index a873b1859..273e89e97 100644
--- a/app/javascript/dashboard/mixins/specs/fileUploadMixin.spec.js
+++ b/app/javascript/dashboard/mixins/specs/fileUploadMixin.spec.js
@@ -6,6 +6,8 @@ import { reactive } from 'vue';
vi.mock('shared/helpers/FileHelper', () => ({
checkFileSizeLimit: vi.fn(),
+ resolveMaximumFileUploadSize: vi.fn(value => Number(value) || 40),
+ DEFAULT_MAXIMUM_FILE_UPLOAD_SIZE: 40,
}));
vi.mock('activestorage', () => ({
@@ -27,6 +29,7 @@ describe('FileUploadMixin', () => {
beforeEach(() => {
mockGlobalConfig = reactive({
directUploadsEnabled: true,
+ maximumFileUploadSize: 40,
});
mockCurrentChat = reactive({
diff --git a/app/javascript/shared/constants/messages.js b/app/javascript/shared/constants/messages.js
index 47c1e8651..8e9d06beb 100644
--- a/app/javascript/shared/constants/messages.js
+++ b/app/javascript/shared/constants/messages.js
@@ -34,9 +34,6 @@ export const CONVERSATION_PRIORITY_ORDER = {
low: 1,
};
-// Size in mega bytes
-export const MAXIMUM_FILE_UPLOAD_SIZE = 40;
-
export const ALLOWED_FILE_TYPES =
'image/*,' +
'audio/*,' +
diff --git a/app/javascript/shared/helpers/FileHelper.js b/app/javascript/shared/helpers/FileHelper.js
index d0d9daaaa..3866fb6b4 100644
--- a/app/javascript/shared/helpers/FileHelper.js
+++ b/app/javascript/shared/helpers/FileHelper.js
@@ -1,3 +1,5 @@
+export const DEFAULT_MAXIMUM_FILE_UPLOAD_SIZE = 40;
+
export const formatBytes = (bytes, decimals = 2) => {
if (bytes === 0) return '0 Bytes';
@@ -19,3 +21,13 @@ export const checkFileSizeLimit = (file, maximumUploadLimit) => {
const fileSizeInMB = fileSizeInMegaBytes(fileSize);
return fileSizeInMB <= maximumUploadLimit;
};
+
+export const resolveMaximumFileUploadSize = value => {
+ const parsedValue = Number(value);
+
+ if (!Number.isFinite(parsedValue) || parsedValue <= 0) {
+ return DEFAULT_MAXIMUM_FILE_UPLOAD_SIZE;
+ }
+
+ return parsedValue;
+};
diff --git a/app/javascript/shared/helpers/specs/FileHelper.spec.js b/app/javascript/shared/helpers/specs/FileHelper.spec.js
index 750eab52c..e8abe506a 100644
--- a/app/javascript/shared/helpers/specs/FileHelper.spec.js
+++ b/app/javascript/shared/helpers/specs/FileHelper.spec.js
@@ -1,7 +1,9 @@
import {
+ DEFAULT_MAXIMUM_FILE_UPLOAD_SIZE,
formatBytes,
fileSizeInMegaBytes,
checkFileSizeLimit,
+ resolveMaximumFileUploadSize,
} from '../FileHelper';
describe('#File Helpers', () => {
@@ -19,6 +21,7 @@ describe('#File Helpers', () => {
expect(formatBytes(10000000)).toBe('9.54 MB');
});
});
+
describe('fileSizeInMegaBytes', () => {
it('should return zero if 0 is passed', () => {
expect(fileSizeInMegaBytes(0)).toBe(0);
@@ -27,6 +30,7 @@ describe('#File Helpers', () => {
expect(fileSizeInMegaBytes(20000000)).toBeCloseTo(19.07, 2);
});
});
+
describe('checkFileSizeLimit', () => {
it('should return false if file with size 62208194 and file size limit 40 are passed', () => {
expect(checkFileSizeLimit({ file: { size: 62208194 } }, 40)).toBe(false);
@@ -35,4 +39,26 @@ describe('#File Helpers', () => {
expect(checkFileSizeLimit({ file: { size: 199154 } }, 40)).toBe(true);
});
});
+
+ describe('resolveMaximumFileUploadSize', () => {
+ it('should return default when value is undefined', () => {
+ expect(resolveMaximumFileUploadSize(undefined)).toBe(
+ DEFAULT_MAXIMUM_FILE_UPLOAD_SIZE
+ );
+ });
+
+ it('should return default when value is not a positive number', () => {
+ expect(resolveMaximumFileUploadSize('not-a-number')).toBe(
+ DEFAULT_MAXIMUM_FILE_UPLOAD_SIZE
+ );
+ expect(resolveMaximumFileUploadSize(-5)).toBe(
+ DEFAULT_MAXIMUM_FILE_UPLOAD_SIZE
+ );
+ });
+
+ it('should parse numeric strings and numbers', () => {
+ expect(resolveMaximumFileUploadSize('50')).toBe(50);
+ expect(resolveMaximumFileUploadSize(75)).toBe(75);
+ });
+ });
});
diff --git a/app/javascript/shared/store/globalConfig.js b/app/javascript/shared/store/globalConfig.js
index 8abeba123..6b4c9a5ee 100644
--- a/app/javascript/shared/store/globalConfig.js
+++ b/app/javascript/shared/store/globalConfig.js
@@ -1,4 +1,5 @@
import { parseBoolean } from '@chatwoot/utils';
+import { resolveMaximumFileUploadSize } from 'shared/helpers/FileHelper';
const {
API_CHANNEL_NAME: apiChannelName,
@@ -11,6 +12,7 @@ const {
DIRECT_UPLOADS_ENABLED: directUploadsEnabled,
DISPLAY_MANIFEST: displayManifest,
GIT_SHA: gitSha,
+ MAXIMUM_FILE_UPLOAD_SIZE: maximumFileUploadSize,
HCAPTCHA_SITE_KEY: hCaptchaSiteKey,
INSTALLATION_NAME: installationName,
LOGO_THUMBNAIL: logoThumbnail,
@@ -37,6 +39,7 @@ const state = {
disableUserProfileUpdate: parseBoolean(disableUserProfileUpdate),
displayManifest,
gitSha,
+ maximumFileUploadSize: resolveMaximumFileUploadSize(maximumFileUploadSize),
hCaptchaSiteKey,
installationName,
logo,
diff --git a/app/javascript/widget/components/ChatAttachment.vue b/app/javascript/widget/components/ChatAttachment.vue
index 64a20bcc7..169749527 100755
--- a/app/javascript/widget/components/ChatAttachment.vue
+++ b/app/javascript/widget/components/ChatAttachment.vue
@@ -1,11 +1,11 @@
@@ -36,6 +46,9 @@ const showPaywall = computed(() => shouldShowPaywall('saml'));
+
+ {{ $t('SECURITY_SETTINGS.SAML_DISABLED_MESSAGE') }}
+
diff --git a/app/javascript/v3/views/auth/signup/components/Signup/Form.vue b/app/javascript/v3/views/auth/signup/components/Signup/Form.vue
index 6a4497948..cb7345ef1 100644
--- a/app/javascript/v3/views/auth/signup/components/Signup/Form.vue
+++ b/app/javascript/v3/views/auth/signup/components/Signup/Form.vue
@@ -99,8 +99,14 @@ export default {
}
return '';
},
+ allowedLoginMethods() {
+ return window.chatwootConfig.allowedLoginMethods || ['email'];
+ },
showGoogleOAuth() {
- return Boolean(window.chatwootConfig.googleOAuthClientId);
+ return (
+ this.allowedLoginMethods.includes('google_oauth') &&
+ Boolean(window.chatwootConfig.googleOAuthClientId)
+ );
},
isFormValid() {
return !this.v$.$invalid && this.hasAValidCaptcha;
@@ -296,7 +302,7 @@ export default {
{ name == 'ENABLE_SAML_SSO_LOGIN' }
# TODO: Get rid of default scope
# https://stackoverflow.com/a/1834250/939299
@@ -54,4 +55,11 @@ class InstallationConfig < ApplicationRecord
def clear_cache
GlobalConfig.clear_cache
end
+
+ def saml_sso_users_check
+ return unless value == false || value == 'false'
+ return unless User.exists?(provider: 'saml')
+
+ errors.add(:base, 'Cannot disable SAML SSO login while users are using SAML authentication')
+ end
end
diff --git a/app/views/layouts/vueapp.html.erb b/app/views/layouts/vueapp.html.erb
index 4d71a547d..3c21850ca 100644
--- a/app/views/layouts/vueapp.html.erb
+++ b/app/views/layouts/vueapp.html.erb
@@ -38,6 +38,7 @@
instagramAppId: '<%= @global_config['INSTAGRAM_APP_ID'] %>',
googleOAuthClientId: '<%= ENV.fetch('GOOGLE_OAUTH_CLIENT_ID', nil) %>',
googleOAuthCallbackUrl: '<%= ENV.fetch('GOOGLE_OAUTH_CALLBACK_URL', nil) %>',
+ allowedLoginMethods: <%= @global_config['ALLOWED_LOGIN_METHODS'].to_json.html_safe %>,
fbApiVersion: '<%= @global_config['FACEBOOK_API_VERSION'] %>',
whatsappAppId: '<%= @global_config['WHATSAPP_APP_ID'] %>',
whatsappConfigurationId: '<%= @global_config['WHATSAPP_CONFIGURATION_ID'] %>',
diff --git a/config/installation_config.yml b/config/installation_config.yml
index 9b84ddc2b..eff38ab3d 100644
--- a/config/installation_config.yml
+++ b/config/installation_config.yml
@@ -438,8 +438,23 @@
value:
locked: false
description: 'The redirect URI configured in your Google OAuth app'
+- name: ENABLE_GOOGLE_OAUTH_LOGIN
+ display_title: 'Enable Google OAuth login'
+ value: true
+ locked: false
+ description: 'Show Google OAuth as a login option when credentials are configured'
+ type: boolean
## ------ End of Configs added for Google OAuth ------ ##
+## ------ Configs added for SAML SSO ------ ##
+- name: ENABLE_SAML_SSO_LOGIN
+ display_title: 'Enable SAML SSO login'
+ value: true
+ locked: false
+ description: 'Show SAML SSO as a login option. Cannot be disabled if any users are using SAML authentication.'
+ type: boolean
+## ------ End of Configs added for SAML SSO ------ ##
+
## ------ Configs added for Cloudflare ------ ##
- name: CLOUDFLARE_API_KEY
display_title: 'Cloudflare API Key'
diff --git a/config/locales/en.yml b/config/locales/en.yml
index d0f256146..c03fb2ba6 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -64,6 +64,7 @@ en:
not_found: Assignment policy not found
saml:
feature_not_enabled: SAML feature not enabled for this account
+ sso_not_enabled: SAML SSO is not enabled for this installation
data_import:
data_type:
invalid: Invalid data type
diff --git a/enterprise/app/controllers/api/v1/accounts/saml_settings_controller.rb b/enterprise/app/controllers/api/v1/accounts/saml_settings_controller.rb
index 9f00138cb..e70804073 100644
--- a/enterprise/app/controllers/api/v1/accounts/saml_settings_controller.rb
+++ b/enterprise/app/controllers/api/v1/accounts/saml_settings_controller.rb
@@ -1,4 +1,5 @@
class Api::V1::Accounts::SamlSettingsController < Api::V1::Accounts::BaseController
+ before_action :check_saml_sso_enabled
before_action :check_saml_feature_enabled
before_action :check_authorization
before_action :set_saml_settings
@@ -53,4 +54,10 @@ class Api::V1::Accounts::SamlSettingsController < Api::V1::Accounts::BaseControl
render json: { error: I18n.t('errors.saml.feature_not_enabled') }, status: :forbidden
end
+
+ def check_saml_sso_enabled
+ return if GlobalConfigService.load('ENABLE_SAML_SSO_LOGIN', 'true').to_s == 'true'
+
+ render json: { error: I18n.t('errors.saml.sso_not_enabled') }, status: :forbidden
+ end
end
diff --git a/enterprise/app/controllers/api/v1/auth_controller.rb b/enterprise/app/controllers/api/v1/auth_controller.rb
index b0d8e1366..c25af3cc1 100644
--- a/enterprise/app/controllers/api/v1/auth_controller.rb
+++ b/enterprise/app/controllers/api/v1/auth_controller.rb
@@ -3,6 +3,11 @@ class Api::V1::AuthController < Api::BaseController
before_action :find_user_and_account, only: [:saml_login]
def saml_login
+ unless saml_sso_enabled?
+ render json: { error: 'SAML SSO login is not enabled' }, status: :forbidden
+ return
+ end
+
return if @account.nil?
relay_state = params[:target] || 'web'
@@ -69,4 +74,8 @@ class Api::V1::AuthController < Api::BaseController
"#{frontend_url}/app/login/sso#{query_fragment}"
end
+
+ def saml_sso_enabled?
+ GlobalConfigService.load('ENABLE_SAML_SSO_LOGIN', 'true').to_s == 'true'
+ end
end
diff --git a/enterprise/app/controllers/enterprise/super_admin/app_configs_controller.rb b/enterprise/app/controllers/enterprise/super_admin/app_configs_controller.rb
index 934462b93..efaa139a9 100644
--- a/enterprise/app/controllers/enterprise/super_admin/app_configs_controller.rb
+++ b/enterprise/app/controllers/enterprise/super_admin/app_configs_controller.rb
@@ -11,6 +11,8 @@ module Enterprise::SuperAdmin::AppConfigsController
@allowed_configs = internal_config_options
when 'captain'
@allowed_configs = captain_config_options
+ when 'saml'
+ @allowed_configs = saml_config_options
else
super
end
@@ -46,4 +48,8 @@ module Enterprise::SuperAdmin::AppConfigsController
CAPTAIN_FIRECRAWL_API_KEY
]
end
+
+ def saml_config_options
+ %w[ENABLE_SAML_SSO_LOGIN]
+ end
end
From 7acf3c8817ee2d56a70151396694a3eb8db3d3c0 Mon Sep 17 00:00:00 2001
From: Chatwoot Bot <92152627+chatwoot-bot@users.noreply.github.com>
Date: Mon, 17 Nov 2025 22:02:54 -0800
Subject: [PATCH 74/80] chore: Update translations (#12876)
---
.../i18n/locale/am/integrations.json | 3 +-
.../i18n/locale/ar/integrations.json | 3 +-
.../i18n/locale/az/integrations.json | 3 +-
.../i18n/locale/bg/integrations.json | 3 +-
.../i18n/locale/bn/integrations.json | 3 +-
.../i18n/locale/ca/integrations.json | 3 +-
.../i18n/locale/cs/integrations.json | 3 +-
.../i18n/locale/da/integrations.json | 3 +-
.../i18n/locale/de/integrations.json | 3 +-
.../i18n/locale/el/integrations.json | 3 +-
.../i18n/locale/es/integrations.json | 3 +-
.../i18n/locale/et/integrations.json | 3 +-
.../i18n/locale/fa/integrations.json | 3 +-
.../i18n/locale/fi/integrations.json | 3 +-
.../i18n/locale/fr/integrations.json | 3 +-
.../dashboard/i18n/locale/he/contact.json | 48 +++++++-------
.../i18n/locale/he/conversation.json | 64 +++++++++----------
.../i18n/locale/he/generalSettings.json | 38 +++++------
.../i18n/locale/he/integrations.json | 3 +-
.../i18n/locale/hi/integrations.json | 3 +-
.../i18n/locale/hr/integrations.json | 3 +-
.../i18n/locale/hu/integrations.json | 3 +-
.../i18n/locale/hy/integrations.json | 3 +-
.../i18n/locale/id/integrations.json | 3 +-
.../i18n/locale/is/integrations.json | 3 +-
.../dashboard/i18n/locale/it/auditLogs.json | 2 +-
.../i18n/locale/it/integrations.json | 5 +-
.../i18n/locale/ja/integrations.json | 3 +-
.../i18n/locale/ka/integrations.json | 3 +-
.../i18n/locale/ko/integrations.json | 3 +-
.../i18n/locale/lt/integrations.json | 3 +-
.../i18n/locale/lv/integrations.json | 3 +-
.../i18n/locale/ml/integrations.json | 3 +-
.../i18n/locale/ms/integrations.json | 3 +-
.../i18n/locale/ne/integrations.json | 3 +-
.../i18n/locale/nl/integrations.json | 3 +-
.../i18n/locale/no/integrations.json | 3 +-
.../i18n/locale/pl/integrations.json | 3 +-
.../i18n/locale/pt/integrations.json | 3 +-
.../i18n/locale/pt_BR/integrations.json | 3 +-
.../i18n/locale/ro/integrations.json | 3 +-
.../i18n/locale/ru/integrations.json | 3 +-
.../i18n/locale/sh/integrations.json | 3 +-
.../i18n/locale/sk/integrations.json | 3 +-
.../i18n/locale/sl/integrations.json | 3 +-
.../i18n/locale/sq/integrations.json | 3 +-
.../i18n/locale/sr/integrations.json | 3 +-
.../i18n/locale/sv/integrations.json | 3 +-
.../i18n/locale/ta/integrations.json | 3 +-
.../i18n/locale/th/integrations.json | 3 +-
.../i18n/locale/tl/integrations.json | 3 +-
.../i18n/locale/tr/integrations.json | 3 +-
.../i18n/locale/uk/integrations.json | 3 +-
.../i18n/locale/ur/integrations.json | 3 +-
.../i18n/locale/ur_IN/integrations.json | 3 +-
.../i18n/locale/vi/integrations.json | 3 +-
.../i18n/locale/zh_CN/integrations.json | 3 +-
.../i18n/locale/zh_TW/integrations.json | 3 +-
58 files changed, 185 insertions(+), 131 deletions(-)
diff --git a/app/javascript/dashboard/i18n/locale/am/integrations.json b/app/javascript/dashboard/i18n/locale/am/integrations.json
index 9500e2fbc..ef3e94e42 100644
--- a/app/javascript/dashboard/i18n/locale/am/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/am/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/ar/integrations.json b/app/javascript/dashboard/i18n/locale/ar/integrations.json
index 2145f7701..9b9f957d8 100644
--- a/app/javascript/dashboard/i18n/locale/ar/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ar/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/az/integrations.json b/app/javascript/dashboard/i18n/locale/az/integrations.json
index 9500e2fbc..ef3e94e42 100644
--- a/app/javascript/dashboard/i18n/locale/az/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/az/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/bg/integrations.json b/app/javascript/dashboard/i18n/locale/bg/integrations.json
index 8c503eac6..ae4e76c2e 100644
--- a/app/javascript/dashboard/i18n/locale/bg/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/bg/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/bn/integrations.json b/app/javascript/dashboard/i18n/locale/bn/integrations.json
index 9500e2fbc..ef3e94e42 100644
--- a/app/javascript/dashboard/i18n/locale/bn/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/bn/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/ca/integrations.json b/app/javascript/dashboard/i18n/locale/ca/integrations.json
index f24fb0115..f754e0530 100644
--- a/app/javascript/dashboard/i18n/locale/ca/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ca/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/cs/integrations.json b/app/javascript/dashboard/i18n/locale/cs/integrations.json
index df6e1f936..88f86abd7 100644
--- a/app/javascript/dashboard/i18n/locale/cs/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/cs/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/da/integrations.json b/app/javascript/dashboard/i18n/locale/da/integrations.json
index bee4e7081..b27b5f270 100644
--- a/app/javascript/dashboard/i18n/locale/da/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/da/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/de/integrations.json b/app/javascript/dashboard/i18n/locale/de/integrations.json
index bf4d70074..c9f751b30 100644
--- a/app/javascript/dashboard/i18n/locale/de/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/de/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/el/integrations.json b/app/javascript/dashboard/i18n/locale/el/integrations.json
index 67ca0056e..be530ce09 100644
--- a/app/javascript/dashboard/i18n/locale/el/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/el/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/es/integrations.json b/app/javascript/dashboard/i18n/locale/es/integrations.json
index d8306bd80..342cab2be 100644
--- a/app/javascript/dashboard/i18n/locale/es/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/es/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/et/integrations.json b/app/javascript/dashboard/i18n/locale/et/integrations.json
index 9500e2fbc..ef3e94e42 100644
--- a/app/javascript/dashboard/i18n/locale/et/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/et/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/fa/integrations.json b/app/javascript/dashboard/i18n/locale/fa/integrations.json
index e635d491f..31538b5b7 100644
--- a/app/javascript/dashboard/i18n/locale/fa/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/fa/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/fi/integrations.json b/app/javascript/dashboard/i18n/locale/fi/integrations.json
index f17f88ecd..3b25a48b0 100644
--- a/app/javascript/dashboard/i18n/locale/fi/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/fi/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/fr/integrations.json b/app/javascript/dashboard/i18n/locale/fr/integrations.json
index 5a9e549a4..b3ec7a784 100644
--- a/app/javascript/dashboard/i18n/locale/fr/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/fr/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/he/contact.json b/app/javascript/dashboard/i18n/locale/he/contact.json
index 908c60a9b..4997ff841 100644
--- a/app/javascript/dashboard/i18n/locale/he/contact.json
+++ b/app/javascript/dashboard/i18n/locale/he/contact.json
@@ -17,10 +17,10 @@
"IP_ADDRESS": "כתובת IP",
"CREATED_AT_LABEL": "נוצר",
"NEW_MESSAGE": "הודעה חדשה",
- "CALL": "Call",
- "CALL_UNDER_DEVELOPMENT": "Calling is under development",
+ "CALL": "שיחה",
+ "CALL_UNDER_DEVELOPMENT": "שיחות עדיין בפיתוח",
"VOICE_INBOX_PICKER": {
- "TITLE": "Choose a voice inbox"
+ "TITLE": "בחר תא דואר עבור שיחות"
},
"CONVERSATIONS": {
"NO_RECORDS_FOUND": "לא קיימות שיחות קודמות המשויכות לאיש קשר זה.",
@@ -290,7 +290,7 @@
"HEADER": {
"TITLE": "איש קשר",
"SEARCH_TITLE": "Search contacts",
- "ACTIVE_TITLE": "Active contacts",
+ "ACTIVE_TITLE": "אנשי קשר פעילים",
"SEARCH_PLACEHOLDER": "Search...",
"MESSAGE_BUTTON": "הודעה",
"SEND_MESSAGE": "שלח הודעה",
@@ -465,8 +465,8 @@
}
},
"DELETE_CONTACT": {
- "MESSAGE": "This action is permanent and irreversible.",
- "BUTTON": "Delete now"
+ "MESSAGE": "הפעולה הזו קבועה ובלתי ניתנת לחזרה.",
+ "BUTTON": "מחק עכשיו"
}
},
"DETAILS": {
@@ -476,7 +476,7 @@
"DELETE_CONTACT": "מחק איש קשר",
"DELETE_DIALOG": {
"TITLE": "אשר מחיקה",
- "DESCRIPTION": "Are you sure you want to delete this contact?",
+ "DESCRIPTION": "אתה בטוח שאתה רוצה למחוק את איש הקשר הזה?",
"CONFIRM": "כן, מחק",
"API": {
"SUCCESS_MESSAGE": "איש הקשר נמחק בהצלחה",
@@ -554,12 +554,12 @@
"WROTE": "נכתב",
"YOU": "You",
"SAVE": "Save note",
- "ADD_NOTE": "Add contact note",
+ "ADD_NOTE": "הוסף הערה לאיש הקשר",
"EXPAND": "Expand",
- "COLLAPSE": "Collapse",
- "NO_NOTES": "No notes, you can add notes from the contact details page.",
+ "COLLAPSE": "צמצום",
+ "NO_NOTES": "אין הערות, אתה יכול להוסיף הערה מהעמוד של איש הקשר.",
"EMPTY_STATE": "There are no notes associated to this contact. You can add a note by typing in the box above.",
- "CONVERSATION_EMPTY_STATE": "There are no notes yet. Use the Add note button to create one."
+ "CONVERSATION_EMPTY_STATE": "אין הערות כרגע. השתמש בכפתור להוספת הערה."
}
},
"EMPTY_STATE": {
@@ -568,27 +568,27 @@
"BUTTON_LABEL": "Add contact",
"SEARCH_EMPTY_STATE_TITLE": "אין אנשי קשר שתואמים לחיפוש שלך 🔍",
"LIST_EMPTY_STATE_TITLE": "No contacts available in this view 📋",
- "ACTIVE_EMPTY_STATE_TITLE": "No contacts are active at the moment 🌙"
+ "ACTIVE_EMPTY_STATE_TITLE": "אין אנשי קשר פעילים 🌙"
}
},
"CONTACTS_BULK_ACTIONS": {
"ASSIGN_LABELS": "הקצה תוויות",
"ASSIGN_LABELS_SUCCESS": "תוויות שוייכו בהצלחה.",
- "ASSIGN_LABELS_FAILED": "Failed to assign labels",
- "DESCRIPTION": "Select the labels you want to add to the selected contacts.",
- "NO_LABELS_FOUND": "No labels available yet.",
+ "ASSIGN_LABELS_FAILED": "שיוך תווית נכשל",
+ "DESCRIPTION": "בחר תווית שאתה רוצה והוסף אותה לאיש קשר.",
+ "NO_LABELS_FOUND": "אין תוויות כרגע.",
"SELECTED_COUNT": "{count} selected",
- "CLEAR_SELECTION": "Clear selection",
- "SELECT_ALL": "Select all ({count})",
+ "CLEAR_SELECTION": "נקה בחירה",
+ "SELECT_ALL": "בחר הכל ({count})",
"DELETE_CONTACTS": "מחק",
- "DELETE_SUCCESS": "Contacts deleted successfully.",
- "DELETE_FAILED": "Failed to delete contacts.",
+ "DELETE_SUCCESS": "איש הקשר נמחק בהצלחה.",
+ "DELETE_FAILED": "מחיקת איש קשר נכשלה.",
"DELETE_DIALOG": {
- "TITLE": "Delete selected contacts",
- "SINGULAR_TITLE": "Delete selected contact",
- "DESCRIPTION": "This will permanently delete {count} selected contacts. This action cannot be undone.",
- "SINGULAR_DESCRIPTION": "This will permanently delete the selected contact. This action cannot be undone.",
- "CONFIRM_MULTIPLE": "Delete contacts",
+ "TITLE": "מחק אנשי קשר שנבחרו",
+ "SINGULAR_TITLE": "מחק איש קשר שנבחר",
+ "DESCRIPTION": "פעולה זו תמחק לצמיתות {count} אנשי קשר שנבחרו. לא ניתן לשחזר פעולה זו.",
+ "SINGULAR_DESCRIPTION": "פעולה זו תמחק לצמיתות אנשי קשר שנבחרו. לא ניתן לשחזר פעולה זו.",
+ "CONFIRM_MULTIPLE": "מחק אנשי קשר",
"CONFIRM_SINGLE": "מחק איש קשר"
}
},
diff --git a/app/javascript/dashboard/i18n/locale/he/conversation.json b/app/javascript/dashboard/i18n/locale/he/conversation.json
index 680924236..a26cea68d 100644
--- a/app/javascript/dashboard/i18n/locale/he/conversation.json
+++ b/app/javascript/dashboard/i18n/locale/he/conversation.json
@@ -32,17 +32,17 @@
"LOADING_CONVERSATIONS": "טוען שיחות",
"CANNOT_REPLY": "לא ניתן להשיב עקב",
"24_HOURS_WINDOW": "הגבלת חלון הודעות של 24 שעות",
- "API_HOURS_WINDOW": "You can only reply to this conversation within {hours} hours",
+ "API_HOURS_WINDOW": "ניתן להשיב לשיחה זו רק תוך {hours} שעות",
"NOT_ASSIGNED_TO_YOU": "השיחה לא שייכת לך, האם תרצה לשייך אותה אליך?",
"ASSIGN_TO_ME": "שייך לעצמך",
- "BOT_HANDOFF_MESSAGE": "You are responding to a conversation which is currently handled by an assistant or a bot.",
- "BOT_HANDOFF_ACTION": "Mark open and assign to you",
- "BOT_HANDOFF_REOPEN_ACTION": "Mark conversation open",
- "BOT_HANDOFF_SUCCESS": "Conversation has been handed over to you",
- "BOT_HANDOFF_ERROR": "Failed to take over the conversation. Please try again.",
+ "BOT_HANDOFF_MESSAGE": "אתה מגיב לשיחה שמטופלת כרגע על ידי עוזר או בוט.",
+ "BOT_HANDOFF_ACTION": "סמן כפתוח והקצה לך",
+ "BOT_HANDOFF_REOPEN_ACTION": "סמן שיחה כפתוחה",
+ "BOT_HANDOFF_SUCCESS": "השיחה הועברה אליך",
+ "BOT_HANDOFF_ERROR": "נכשל בניסיון להשתלט על השיחה. אנא נסה שוב.",
"TWILIO_WHATSAPP_CAN_REPLY": "אתה יכול להשיב לשיחה זו רק באמצעות הודעת תבנית בשל",
"TWILIO_WHATSAPP_24_HOURS_WINDOW": "הגבלת חלון הודעות של 24 שעות",
- "OLD_INSTAGRAM_INBOX_REPLY_BANNER": "This Instagram account was migrated to the new Instagram channel inbox. All new messages will show up there. You won’t be able to send messages from this conversation anymore.",
+ "OLD_INSTAGRAM_INBOX_REPLY_BANNER": "חשבון אינסטגרם זה הועבר לתיבת הדואר החדשה של ערוץ אינסטגרם. כל ההודעות החדשות יופיעו שם. לא תוכל לשלוח הודעות משיחה זו יותר.",
"REPLYING_TO": "אתה משיב ל:",
"REMOVE_SELECTION": "הסר בחירה",
"DOWNLOAD": "הורד",
@@ -72,21 +72,21 @@
"HIDE_LABELS": "הסתר תוויות"
},
"VOICE_CALL": {
- "INCOMING_CALL": "Incoming call",
- "OUTGOING_CALL": "Outgoing call",
- "CALL_IN_PROGRESS": "Call in progress",
- "NO_ANSWER": "No answer",
- "MISSED_CALL": "Missed call",
- "CALL_ENDED": "Call ended",
- "NOT_ANSWERED_YET": "Not answered yet",
- "THEY_ANSWERED": "They answered",
- "YOU_ANSWERED": "You answered"
+ "INCOMING_CALL": "שיחה נכנסת",
+ "OUTGOING_CALL": "שיחה יוצאת",
+ "CALL_IN_PROGRESS": "שיחה מתקיימת",
+ "NO_ANSWER": "אין מענה",
+ "MISSED_CALL": "שיחה שלא נענתה",
+ "CALL_ENDED": "השיחה הסתיימה",
+ "NOT_ANSWERED_YET": "לא ענה כרגע",
+ "THEY_ANSWERED": "ענה",
+ "YOU_ANSWERED": "אתה ענית"
},
"HEADER": {
"RESOLVE_ACTION": "פתרון",
"REOPEN_ACTION": "פתח מחדש",
"OPEN_ACTION": "פתח",
- "MORE_ACTIONS": "More actions",
+ "MORE_ACTIONS": "עוד פעולות",
"OPEN": "עוד",
"CLOSE": "סגור",
"DETAILS": "פרטים",
@@ -139,8 +139,8 @@
}
},
"DELETE_CONVERSATION": {
- "TITLE": "Delete conversation #{conversationId}",
- "DESCRIPTION": "Are you sure you want to delete this conversation?",
+ "TITLE": "מחק שיחה #{conversationId}",
+ "DESCRIPTION": "אתה בטוח שאתה רוצה למחוק את השיחה הזו?",
"CONFIRM": "מחק"
},
"CARD_CONTEXT_MENU": {
@@ -159,10 +159,10 @@
"ASSIGN_LABEL": "ההקצה תווית",
"AGENTS_LOADING": "טוען סוכנים...",
"ASSIGN_TEAM": "שייך צוות",
- "DELETE": "Delete conversation",
- "OPEN_IN_NEW_TAB": "Open in new tab",
- "COPY_LINK": "Copy conversation link",
- "COPY_LINK_SUCCESS": "Conversation link copied to clipboard",
+ "DELETE": "מחק שיחה",
+ "OPEN_IN_NEW_TAB": "פתח בכרטיסיה חדשה",
+ "COPY_LINK": "העתק קישור לשיחה",
+ "COPY_LINK_SUCCESS": "קישור לשיחה הועתק ללוח הגזירים",
"API": {
"AGENT_ASSIGNMENT": {
"SUCCESFUL": "מזהה שיחה {conversationId} קושר ל {agentName}",
@@ -229,11 +229,11 @@
}
},
"QUOTED_REPLY": {
- "ENABLE_TOOLTIP": "Include quoted email thread",
- "DISABLE_TOOLTIP": "Don't include quoted email thread",
- "REMOVE_PREVIEW": "Remove quoted email thread",
- "COLLAPSE": "Collapse preview",
- "EXPAND": "Expand preview"
+ "ENABLE_TOOLTIP": "כלול שרשור אימייל מצוטט",
+ "DISABLE_TOOLTIP": "אל תכלול שרשור אימייל מצוטט",
+ "REMOVE_PREVIEW": "הסר שרשור אימייל מצוטט",
+ "COLLAPSE": "כווץ תצוגה מקדימה",
+ "EXPAND": "הרחב תצוגה מקדימה"
}
},
"VISIBLE_TO_AGENTS": "פתקים פרטיים: רק אתה והצוות שלך יכולים לראות",
@@ -244,8 +244,8 @@
"ASSIGN_LABEL_SUCCESFUL": "סמן משימה כבוצעה בהצלחה",
"ASSIGN_LABEL_FAILED": "סמן משימה כנכשלה",
"CHANGE_TEAM": "שיחת קבוצה השתנתה",
- "SUCCESS_DELETE_CONVERSATION": "Conversation deleted successfully",
- "FAIL_DELETE_CONVERSATION": "Couldn't delete conversation! Try again",
+ "SUCCESS_DELETE_CONVERSATION": "השיחה נמחקה בהצלחה",
+ "FAIL_DELETE_CONVERSATION": "לא ניתן למחוק את השיחה! נסה שוב",
"FILE_SIZE_LIMIT": "הקובץ גדול מ{MAXIMUM_SUPPORTED_FILE_UPLOAD_SIZE}MB מגבלת העלאה",
"MESSAGE_ERROR": "לא ניתן לשלוח הודעה, אנא נסה שוב מאוחר יותר",
"SENT_BY": "נשלח על ידי:",
@@ -334,11 +334,11 @@
"CONVERSATION_ACTIONS": "פעולות בשיחה",
"CONVERSATION_LABELS": "תוויות שיחה",
"CONVERSATION_INFO": "מידע על שיחה",
- "CONTACT_NOTES": "Contact Notes",
+ "CONTACT_NOTES": "הערות איש קשר",
"CONTACT_ATTRIBUTES": "תכונות יצירת קשר",
"PREVIOUS_CONVERSATION": "שיחות קודמות",
"MACROS": "מאקרו",
- "LINEAR_ISSUES": "Linked Linear Issues",
+ "LINEAR_ISSUES": "בעיות ליניאריות מקושרות",
"SHOPIFY_ORDERS": "Shopify Orders"
},
"SHOPIFY": {
diff --git a/app/javascript/dashboard/i18n/locale/he/generalSettings.json b/app/javascript/dashboard/i18n/locale/he/generalSettings.json
index 57bf89e3b..69aaef39c 100644
--- a/app/javascript/dashboard/i18n/locale/he/generalSettings.json
+++ b/app/javascript/dashboard/i18n/locale/he/generalSettings.json
@@ -1,7 +1,7 @@
{
"GENERAL_SETTINGS": {
"LIMIT_MESSAGES": {
- "CONVERSATION": "You have exceeded the conversation limit. Hacker plan allows only 500 conversations.",
+ "CONVERSATION": "חרגת מהמגבלה של השיחות. תוכנית Hacker מאפשרת רק 500 שיחות.",
"INBOXES": "You have exceeded the inbox limit. Hacker plan only supports website live-chat. Additional inboxes like email, WhatsApp etc. require a paid plan.",
"AGENTS": "You have exceeded the agent limit. Your plan only allows {allowedAgents} agents.",
"NON_ADMIN": "Please contact your administrator to upgrade the plan and continue using all features."
@@ -16,22 +16,22 @@
},
"ACCOUNT_DELETE_SECTION": {
"TITLE": "Delete your Account",
- "NOTE": "Once you delete your account, all your data will be deleted.",
- "BUTTON_TEXT": "Delete Your Account",
+ "NOTE": "לאחר מחיקת החשבון, כל הנתונים שלך יימחקו.",
+ "BUTTON_TEXT": "מחק את חשבונך",
"CONFIRM": {
- "TITLE": "Delete Account",
- "MESSAGE": "Deleting your Account is irreversible. Enter your account name below to confirm you want to permanently delete it.",
+ "TITLE": "מחק חשבון",
+ "MESSAGE": "מחיקת החשבון איננה הפיכה. הזן את שם החשבון מטה כדי לאשר שאתה רוצה למחוק אותו.",
"BUTTON_TEXT": "מחק",
"DISMISS": "ביטול",
"PLACE_HOLDER": "אנא הקלד {accountName} כדי לאשר"
},
- "SUCCESS": "Account marked for deletion",
- "FAILURE": "Could not delete account, try again!",
+ "SUCCESS": "חשבון סומן למחיקה",
+ "FAILURE": "לא הצלחתי למחוק את החשבון, נסה שוב!",
"SCHEDULED_DELETION": {
- "TITLE": "Account Scheduled for Deletion",
- "MESSAGE_MANUAL": "This account is scheduled for deletion on {deletionDate}. This was requested by an administrator. You can cancel the deletion before this date.",
- "MESSAGE_INACTIVITY": ".",
- "CLEAR_BUTTON": "Cancel Scheduled Deletion"
+ "TITLE": "החשבון תוזמן למחיקה",
+ "MESSAGE_MANUAL": "חשבון זה מתוכנן למחיקה בתאריך {deletionDate}. הבקשה הוגשה על ידי מנהל. ניתן לבטל את המחיקה לפני תאריך זה.",
+ "MESSAGE_INACTIVITY": "החשבון הזה תוסמן למחיקה ב{deletionDate} בגלל שהחשבון לא היה בשימוש. אתה יכול לבטל זאת לפני התאריך.",
+ "CLEAR_BUTTON": "בטל מחיקה מתוכננת"
}
},
"FORM": {
@@ -45,10 +45,10 @@
"NOTE": "מזהה זה נדרש אם אתה בונה אינטגרציה מבוססת API"
},
"AUTO_RESOLVE": {
- "TITLE": "Auto-resolve conversations",
- "NOTE": "This configuration would allow you to automatically resolve the conversation after a certain period of inactivity.",
+ "TITLE": "פתרון אוטומטי של שיחות",
+ "NOTE": "תצורה זו מאפשרת לך לפתור אוטומטית את השיחה לאחר תקופת אי פעילות מסוימת.",
"DURATION": {
- "LABEL": "Inactivity duration",
+ "LABEL": "תקופת זמן של אי פעילות שלאחריה השיחה נפתרת אוטומטית",
"HELP": "Time period of inactivity after which conversation is auto-resolved",
"PLACEHOLDER": "30",
"ERROR": "Auto resolve duration should be between 10 minutes and 999 days",
@@ -58,11 +58,11 @@
}
},
"MESSAGE": {
- "LABEL": "Custom auto-resolution message",
- "PLACEHOLDER": "Conversation was marked resolved by system due to 15 days of inactivity",
- "HELP": "Message sent to the customer after conversation is auto-resolved"
+ "LABEL": "הודעת פתרון אוטומטית מותאמת אישית",
+ "PLACEHOLDER": "השיחה סומנה כפתורה על ידי המערכת עקב 15 ימים של אי פעילות",
+ "HELP": "הודעה שנשלחת ללקוח לאחר שהשיחה נפתרת אוטומטית"
},
- "PREFERENCES": "Preferences",
+ "PREFERENCES": "העדפות",
"LABEL": {
"LABEL": "Add label after auto-resolution",
"PLACEHOLDER": "Select a label"
@@ -115,7 +115,7 @@
},
"UPDATE_BUTTON": "עדכן",
"MESSAGE_LABEL": "Custom resolution message",
- "MESSAGE_PLACEHOLDER": "Conversation was marked resolved by system due to 15 days of inactivity",
+ "MESSAGE_PLACEHOLDER": "השיחה סומנה כפתורה על ידי המערכת עקב 15 ימים של אי פעילות",
"MESSAGE_HELP": "This message is sent to the customer when a conversation is automatically resolved by the system due to inactivity."
},
"FEATURES": {
diff --git a/app/javascript/dashboard/i18n/locale/he/integrations.json b/app/javascript/dashboard/i18n/locale/he/integrations.json
index 843c6360b..781295303 100644
--- a/app/javascript/dashboard/i18n/locale/he/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/he/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "טייס משנה",
diff --git a/app/javascript/dashboard/i18n/locale/hi/integrations.json b/app/javascript/dashboard/i18n/locale/hi/integrations.json
index c39ce064c..c4d915418 100644
--- a/app/javascript/dashboard/i18n/locale/hi/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/hi/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/hr/integrations.json b/app/javascript/dashboard/i18n/locale/hr/integrations.json
index 472e5fd69..44b906008 100644
--- a/app/javascript/dashboard/i18n/locale/hr/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/hr/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/hu/integrations.json b/app/javascript/dashboard/i18n/locale/hu/integrations.json
index a6a0654fb..80552228b 100644
--- a/app/javascript/dashboard/i18n/locale/hu/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/hu/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/hy/integrations.json b/app/javascript/dashboard/i18n/locale/hy/integrations.json
index 0566abd9a..983953180 100644
--- a/app/javascript/dashboard/i18n/locale/hy/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/hy/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/id/integrations.json b/app/javascript/dashboard/i18n/locale/id/integrations.json
index ce14316bb..965e4f351 100644
--- a/app/javascript/dashboard/i18n/locale/id/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/id/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/is/integrations.json b/app/javascript/dashboard/i18n/locale/is/integrations.json
index 100ab01e9..aa164a4fc 100644
--- a/app/javascript/dashboard/i18n/locale/is/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/is/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/it/auditLogs.json b/app/javascript/dashboard/i18n/locale/it/auditLogs.json
index 51e6d9bf4..730365a0e 100644
--- a/app/javascript/dashboard/i18n/locale/it/auditLogs.json
+++ b/app/javascript/dashboard/i18n/locale/it/auditLogs.json
@@ -50,7 +50,7 @@
"SIGN_OUT": "{agentName} si è disconnesso"
},
"TEAM": {
- "ADD": "{agentName} created a new team (#{id})",
+ "ADD": "{agentName} ha creato un nuovo team (#{id})",
"EDIT": "{agentName} ha aggiornato un team (#{id})",
"DELETE": "{agentName} ha eliminato un team (#{id})"
},
diff --git a/app/javascript/dashboard/i18n/locale/it/integrations.json b/app/javascript/dashboard/i18n/locale/it/integrations.json
index 804385262..c93f6905e 100644
--- a/app/javascript/dashboard/i18n/locale/it/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/it/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistenti",
"SWITCH_ASSISTANT": "Cambia assistenti",
- "NEW_ASSISTANT": "Crea Assistente"
+ "NEW_ASSISTANT": "Crea Assistente",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
@@ -422,7 +423,7 @@
"NO_ASSISTANTS_AVAILABLE": "Non ci sono assistenti disponibili nel tuo account.",
"ADD_NEW": "Crea un nuovo assistente",
"DELETE": {
- "TITLE": "Are you sure to delete the assistant?",
+ "TITLE": "Sei sicuro di voler eliminare l'assistente?",
"DESCRIPTION": "Questa azione è permanente. L'eliminazione di questo assistente la rimuoverà da tutte le inbox connesse e cancellerà definitivamente tutte le knowledge generate.",
"CONFIRM": "Sì, elimina",
"SUCCESS_MESSAGE": "L'assistente è stato eliminato con successo",
diff --git a/app/javascript/dashboard/i18n/locale/ja/integrations.json b/app/javascript/dashboard/i18n/locale/ja/integrations.json
index eb11e38ee..f83d0f848 100644
--- a/app/javascript/dashboard/i18n/locale/ja/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ja/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "アシスタント",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "コパイロット",
diff --git a/app/javascript/dashboard/i18n/locale/ka/integrations.json b/app/javascript/dashboard/i18n/locale/ka/integrations.json
index 0566abd9a..983953180 100644
--- a/app/javascript/dashboard/i18n/locale/ka/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ka/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/ko/integrations.json b/app/javascript/dashboard/i18n/locale/ko/integrations.json
index 8bc57201a..16add473d 100644
--- a/app/javascript/dashboard/i18n/locale/ko/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ko/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/lt/integrations.json b/app/javascript/dashboard/i18n/locale/lt/integrations.json
index 266d5c56f..466e83cce 100644
--- a/app/javascript/dashboard/i18n/locale/lt/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/lt/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/lv/integrations.json b/app/javascript/dashboard/i18n/locale/lv/integrations.json
index 7ffcdc6cf..f45afff1c 100644
--- a/app/javascript/dashboard/i18n/locale/lv/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/lv/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Asistenti",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Kopilots",
diff --git a/app/javascript/dashboard/i18n/locale/ml/integrations.json b/app/javascript/dashboard/i18n/locale/ml/integrations.json
index 35c3b24b9..a9024de8f 100644
--- a/app/javascript/dashboard/i18n/locale/ml/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ml/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/ms/integrations.json b/app/javascript/dashboard/i18n/locale/ms/integrations.json
index e530f8fb9..50cb231ba 100644
--- a/app/javascript/dashboard/i18n/locale/ms/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ms/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/ne/integrations.json b/app/javascript/dashboard/i18n/locale/ne/integrations.json
index d6c7739e6..c0ea2dbff 100644
--- a/app/javascript/dashboard/i18n/locale/ne/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ne/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/nl/integrations.json b/app/javascript/dashboard/i18n/locale/nl/integrations.json
index 57dedc0c9..648875252 100644
--- a/app/javascript/dashboard/i18n/locale/nl/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/nl/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/no/integrations.json b/app/javascript/dashboard/i18n/locale/no/integrations.json
index d162c8412..0266ca280 100644
--- a/app/javascript/dashboard/i18n/locale/no/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/no/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/pl/integrations.json b/app/javascript/dashboard/i18n/locale/pl/integrations.json
index 741f7fc9c..d5fe93b75 100644
--- a/app/javascript/dashboard/i18n/locale/pl/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/pl/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/pt/integrations.json b/app/javascript/dashboard/i18n/locale/pt/integrations.json
index 4d485528e..59aea1d3b 100644
--- a/app/javascript/dashboard/i18n/locale/pt/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/pt/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/pt_BR/integrations.json b/app/javascript/dashboard/i18n/locale/pt_BR/integrations.json
index b9311d051..6abfffa12 100644
--- a/app/javascript/dashboard/i18n/locale/pt_BR/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/pt_BR/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistentes",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copiloto",
diff --git a/app/javascript/dashboard/i18n/locale/ro/integrations.json b/app/javascript/dashboard/i18n/locale/ro/integrations.json
index 8ec2f80f3..cb5ffc802 100644
--- a/app/javascript/dashboard/i18n/locale/ro/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ro/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/ru/integrations.json b/app/javascript/dashboard/i18n/locale/ru/integrations.json
index eaa271564..d27942627 100644
--- a/app/javascript/dashboard/i18n/locale/ru/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ru/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Ассистенты",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/sh/integrations.json b/app/javascript/dashboard/i18n/locale/sh/integrations.json
index 0566abd9a..983953180 100644
--- a/app/javascript/dashboard/i18n/locale/sh/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/sh/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/sk/integrations.json b/app/javascript/dashboard/i18n/locale/sk/integrations.json
index 963814952..df29ccdbc 100644
--- a/app/javascript/dashboard/i18n/locale/sk/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/sk/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/sl/integrations.json b/app/javascript/dashboard/i18n/locale/sl/integrations.json
index 91018d11f..ea4c1822a 100644
--- a/app/javascript/dashboard/i18n/locale/sl/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/sl/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/sq/integrations.json b/app/javascript/dashboard/i18n/locale/sq/integrations.json
index 6305a2c82..ae72f4974 100644
--- a/app/javascript/dashboard/i18n/locale/sq/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/sq/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/sr/integrations.json b/app/javascript/dashboard/i18n/locale/sr/integrations.json
index b1f2a0c04..82e116cff 100644
--- a/app/javascript/dashboard/i18n/locale/sr/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/sr/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/sv/integrations.json b/app/javascript/dashboard/i18n/locale/sv/integrations.json
index eb206fa68..af76bd0f1 100644
--- a/app/javascript/dashboard/i18n/locale/sv/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/sv/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/ta/integrations.json b/app/javascript/dashboard/i18n/locale/ta/integrations.json
index b71f3824e..2c5a40fbb 100644
--- a/app/javascript/dashboard/i18n/locale/ta/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ta/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/th/integrations.json b/app/javascript/dashboard/i18n/locale/th/integrations.json
index 7c30cbb08..84b5c19e2 100644
--- a/app/javascript/dashboard/i18n/locale/th/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/th/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/tl/integrations.json b/app/javascript/dashboard/i18n/locale/tl/integrations.json
index 9500e2fbc..ef3e94e42 100644
--- a/app/javascript/dashboard/i18n/locale/tl/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/tl/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/tr/integrations.json b/app/javascript/dashboard/i18n/locale/tr/integrations.json
index 1e4118d0f..d6abfc310 100644
--- a/app/javascript/dashboard/i18n/locale/tr/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/tr/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "Asistan bulunamadı, başlamak için bir tane oluşturun"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/uk/integrations.json b/app/javascript/dashboard/i18n/locale/uk/integrations.json
index de5e8258b..dcca01734 100644
--- a/app/javascript/dashboard/i18n/locale/uk/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/uk/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/ur/integrations.json b/app/javascript/dashboard/i18n/locale/ur/integrations.json
index b534e6194..ba9130a1d 100644
--- a/app/javascript/dashboard/i18n/locale/ur/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ur/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/ur_IN/integrations.json b/app/javascript/dashboard/i18n/locale/ur_IN/integrations.json
index 0566abd9a..983953180 100644
--- a/app/javascript/dashboard/i18n/locale/ur_IN/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/ur_IN/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/vi/integrations.json b/app/javascript/dashboard/i18n/locale/vi/integrations.json
index bcfd10f38..2caf8e3ee 100644
--- a/app/javascript/dashboard/i18n/locale/vi/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/vi/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/zh_CN/integrations.json b/app/javascript/dashboard/i18n/locale/zh_CN/integrations.json
index a37ac43a5..ca4a76367 100644
--- a/app/javascript/dashboard/i18n/locale/zh_CN/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/zh_CN/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "助手",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
diff --git a/app/javascript/dashboard/i18n/locale/zh_TW/integrations.json b/app/javascript/dashboard/i18n/locale/zh_TW/integrations.json
index 2016bb406..feb3146ed 100644
--- a/app/javascript/dashboard/i18n/locale/zh_TW/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/zh_TW/integrations.json
@@ -351,7 +351,8 @@
"ASSISTANT_SWITCHER": {
"ASSISTANTS": "Assistants",
"SWITCH_ASSISTANT": "Switch between assistants",
- "NEW_ASSISTANT": "Create Assistant"
+ "NEW_ASSISTANT": "Create Assistant",
+ "EMPTY_LIST": "No assistants found, please create one to get started"
},
"COPILOT": {
"TITLE": "Copilot",
From 58ca82c720fdcc0ea6c349596ec40e702049b003 Mon Sep 17 00:00:00 2001
From: Vinay Keerthi <11478411+stonecharioteer@users.noreply.github.com>
Date: Tue, 18 Nov 2025 14:28:56 +0530
Subject: [PATCH 75/80] feat: Backend - Companies API endpoint with pagination
and search (#12840)
## Description
Adds API endpoint to list companies with pagination, search, and
sorting.
Fixes
https://linear.app/chatwoot/issue/CW-5930/add-backend-routes-to-get-companies-result
Parent issue:
https://linear.app/chatwoot/issue/CW-5928/add-companies-tab-to-dashboard
## Type of change
- [x] New feature (non-breaking change which adds functionality)
## How Has This Been Tested?
Added comprehensive specs to
`spec/enterprise/controllers/api/v1/accounts/companies_controller_spec.rb`:
- Pagination (25 per page, multiple pages)
- Search by name and domain (case-insensitive)
- Counter cache for contacts_count
- Account scoping
- Authorization
To reproduce:
```bash
bundle exec rspec spec/enterprise/controllers/api/v1/accounts/companies_controller_spec.rb
bundle exec rubocop enterprise/app/controllers/api/v1/accounts/companies_controller.rb
```
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
---------
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Co-authored-by: iamsivin
Co-authored-by: Shivam Mishra
Co-authored-by: Sojan Jose
---
.../backfill_companies_contacts_count_job.rb | 13 ++
config/locales/en.yml | 2 +
config/routes.rb | 6 +-
...1094402_add_contacts_count_to_companies.rb | 5 +
db/schema.rb | 1 +
.../api/v1/accounts/companies_controller.rb | 36 +++-
enterprise/app/models/company.rb | 18 +-
.../app/models/enterprise/concerns/contact.rb | 2 +-
enterprise/app/policies/company_policy.rb | 4 +
.../contacts/company_association_service.rb | 13 +-
.../accounts/companies/_company.json.jbuilder | 1 +
.../v1/accounts/companies/index.json.jbuilder | 5 +
.../accounts/companies/search.json.jbuilder | 10 ++
.../v1/accounts/companies_controller_spec.rb | 163 ++++++++++++++++++
.../company_association_service_spec.rb | 19 ++
15 files changed, 282 insertions(+), 16 deletions(-)
create mode 100644 app/jobs/migration/backfill_companies_contacts_count_job.rb
create mode 100644 db/migrate/20251111094402_add_contacts_count_to_companies.rb
create mode 100644 enterprise/app/views/api/v1/accounts/companies/search.json.jbuilder
diff --git a/app/jobs/migration/backfill_companies_contacts_count_job.rb b/app/jobs/migration/backfill_companies_contacts_count_job.rb
new file mode 100644
index 000000000..2cae9eeee
--- /dev/null
+++ b/app/jobs/migration/backfill_companies_contacts_count_job.rb
@@ -0,0 +1,13 @@
+class Migration::BackfillCompaniesContactsCountJob < ApplicationJob
+ queue_as :async_database_migration
+
+ def perform
+ return unless ChatwootApp.enterprise?
+
+ Company.find_in_batches(batch_size: 100) do |company_batch|
+ company_batch.each do |company|
+ Company.reset_counters(company.id, :contacts)
+ end
+ end
+ end
+end
diff --git a/config/locales/en.yml b/config/locales/en.yml
index c03fb2ba6..a624861e3 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -80,6 +80,8 @@ en:
companies:
domain:
invalid: must be a valid domain name
+ search:
+ query_missing: Specify search string with parameter q
categories:
locale:
unique: should be unique in the category and portal
diff --git a/config/routes.rb b/config/routes.rb
index 9c6866e1d..ea0228085 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -154,7 +154,11 @@ Rails.application.routes.draw do
end
end
- resources :companies, only: [:index, :show, :create, :update, :destroy]
+ resources :companies, only: [:index, :show, :create, :update, :destroy] do
+ collection do
+ get :search
+ end
+ end
resources :contacts, only: [:index, :show, :update, :create, :destroy] do
collection do
get :active
diff --git a/db/migrate/20251111094402_add_contacts_count_to_companies.rb b/db/migrate/20251111094402_add_contacts_count_to_companies.rb
new file mode 100644
index 000000000..2bd1ac5dc
--- /dev/null
+++ b/db/migrate/20251111094402_add_contacts_count_to_companies.rb
@@ -0,0 +1,5 @@
+class AddContactsCountToCompanies < ActiveRecord::Migration[7.1]
+ def change
+ add_column :companies, :contacts_count, :integer, default: 0, null: false
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 7b893ecd2..8a6e6676c 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -577,6 +577,7 @@ ActiveRecord::Schema[7.1].define(version: 2025_11_14_173609) do
t.bigint "account_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
+ t.integer "contacts_count"
t.index ["account_id", "domain"], name: "index_companies_on_account_and_domain", unique: true, where: "(domain IS NOT NULL)"
t.index ["account_id"], name: "index_companies_on_account_id"
t.index ["name", "account_id"], name: "index_companies_on_name_and_account_id"
diff --git a/enterprise/app/controllers/api/v1/accounts/companies_controller.rb b/enterprise/app/controllers/api/v1/accounts/companies_controller.rb
index a33e4c6b2..86216b03c 100644
--- a/enterprise/app/controllers/api/v1/accounts/companies_controller.rb
+++ b/enterprise/app/controllers/api/v1/accounts/companies_controller.rb
@@ -1,9 +1,29 @@
class Api::V1::Accounts::CompaniesController < Api::V1::Accounts::EnterpriseAccountsController
+ include Sift
+ sort_on :name, type: :string
+ sort_on :domain, type: :string
+ sort_on :created_at, type: :datetime
+
+ RESULTS_PER_PAGE = 25
+
before_action :check_authorization
+ before_action :set_current_page, only: [:index, :search]
before_action :fetch_company, only: [:show, :update, :destroy]
def index
- @companies = Current.account.companies.ordered_by_name
+ @companies = fetch_companies(resolved_companies)
+ @companies_count = @companies.total_count
+ end
+
+ def search
+ if params[:q].blank?
+ return render json: { error: I18n.t('errors.companies.search.query_missing') },
+ status: :unprocessable_entity
+ end
+
+ companies = resolved_companies.search_by_name_or_domain(params[:q])
+ @companies = fetch_companies(companies)
+ @companies_count = @companies.total_count
end
def show; end
@@ -24,6 +44,20 @@ class Api::V1::Accounts::CompaniesController < Api::V1::Accounts::EnterpriseAcco
private
+ def resolved_companies
+ @resolved_companies ||= Current.account.companies
+ end
+
+ def set_current_page
+ @current_page = params[:page] || 1
+ end
+
+ def fetch_companies(companies)
+ filtrate(companies)
+ .page(@current_page)
+ .per(RESULTS_PER_PAGE)
+ end
+
def check_authorization
raise Pundit::NotAuthorizedError unless ChatwootApp.enterprise?
diff --git a/enterprise/app/models/company.rb b/enterprise/app/models/company.rb
index fde6cb122..9fa18b8ad 100644
--- a/enterprise/app/models/company.rb
+++ b/enterprise/app/models/company.rb
@@ -2,13 +2,14 @@
#
# Table name: companies
#
-# id :bigint not null, primary key
-# description :text
-# domain :string
-# name :string not null
-# created_at :datetime not null
-# updated_at :datetime not null
-# account_id :bigint not null
+# id :bigint not null, primary key
+# contacts_count :integer
+# description :text
+# domain :string
+# name :string not null
+# created_at :datetime not null
+# updated_at :datetime not null
+# account_id :bigint not null
#
# Indexes
#
@@ -31,4 +32,7 @@ class Company < ApplicationRecord
has_many :contacts, dependent: :nullify
scope :ordered_by_name, -> { order(:name) }
+ scope :search_by_name_or_domain, lambda { |query|
+ where('name ILIKE :search OR domain ILIKE :search', search: "%#{query.strip}%")
+ }
end
diff --git a/enterprise/app/models/enterprise/concerns/contact.rb b/enterprise/app/models/enterprise/concerns/contact.rb
index 09885a947..daca6c431 100644
--- a/enterprise/app/models/enterprise/concerns/contact.rb
+++ b/enterprise/app/models/enterprise/concerns/contact.rb
@@ -1,7 +1,7 @@
module Enterprise::Concerns::Contact
extend ActiveSupport::Concern
included do
- belongs_to :company, optional: true
+ belongs_to :company, optional: true, counter_cache: true
after_commit :associate_company_from_email,
on: [:create, :update],
diff --git a/enterprise/app/policies/company_policy.rb b/enterprise/app/policies/company_policy.rb
index 1c252967c..756edfc32 100644
--- a/enterprise/app/policies/company_policy.rb
+++ b/enterprise/app/policies/company_policy.rb
@@ -3,6 +3,10 @@ class CompanyPolicy < ApplicationPolicy
true
end
+ def search?
+ true
+ end
+
def show?
true
end
diff --git a/enterprise/app/services/contacts/company_association_service.rb b/enterprise/app/services/contacts/company_association_service.rb
index f2e2ffdd2..cb56f5309 100644
--- a/enterprise/app/services/contacts/company_association_service.rb
+++ b/enterprise/app/services/contacts/company_association_service.rb
@@ -3,12 +3,13 @@ class Contacts::CompanyAssociationService
return nil if skip_association?(contact)
company = find_or_create_company(contact)
- # rubocop:disable Rails/SkipsModelValidations
- # Intentionally using update_column here to:
- # 1. Avoid triggering callbacks
- # 2. Improve performance (We're only setting company_id, no need for validation)
- contact.update_column(:company_id, company.id) if company
- # rubocop:enable Rails/SkipsModelValidations
+ if company
+ # rubocop:disable Rails/SkipsModelValidations
+ # Using update_column and increment_counter to avoid triggering callbacks while maintaining counter cache
+ contact.update_column(:company_id, company.id)
+ Company.increment_counter(:contacts_count, company.id)
+ # rubocop:enable Rails/SkipsModelValidations
+ end
company
end
diff --git a/enterprise/app/views/api/v1/accounts/companies/_company.json.jbuilder b/enterprise/app/views/api/v1/accounts/companies/_company.json.jbuilder
index 71c4d3b9b..8b8772507 100644
--- a/enterprise/app/views/api/v1/accounts/companies/_company.json.jbuilder
+++ b/enterprise/app/views/api/v1/accounts/companies/_company.json.jbuilder
@@ -1,5 +1,6 @@
json.id company.id
json.name company.name
+json.contacts_count company.contacts_count
json.domain company.domain
json.description company.description
json.avatar_url company.avatar_url
diff --git a/enterprise/app/views/api/v1/accounts/companies/index.json.jbuilder b/enterprise/app/views/api/v1/accounts/companies/index.json.jbuilder
index e68bd8543..ef9c67723 100644
--- a/enterprise/app/views/api/v1/accounts/companies/index.json.jbuilder
+++ b/enterprise/app/views/api/v1/accounts/companies/index.json.jbuilder
@@ -1,3 +1,8 @@
+json.meta do
+ json.total_count @companies_count
+ json.page @current_page
+end
+
json.payload do
json.array! @companies do |company|
json.partial! 'company', company: company
diff --git a/enterprise/app/views/api/v1/accounts/companies/search.json.jbuilder b/enterprise/app/views/api/v1/accounts/companies/search.json.jbuilder
new file mode 100644
index 000000000..ef9c67723
--- /dev/null
+++ b/enterprise/app/views/api/v1/accounts/companies/search.json.jbuilder
@@ -0,0 +1,10 @@
+json.meta do
+ json.total_count @companies_count
+ json.page @current_page
+end
+
+json.payload do
+ json.array! @companies do |company|
+ json.partial! 'company', company: company
+ end
+end
diff --git a/spec/enterprise/controllers/api/v1/accounts/companies_controller_spec.rb b/spec/enterprise/controllers/api/v1/accounts/companies_controller_spec.rb
index f62991ad1..f5d82310a 100644
--- a/spec/enterprise/controllers/api/v1/accounts/companies_controller_spec.rb
+++ b/spec/enterprise/controllers/api/v1/accounts/companies_controller_spec.rb
@@ -25,10 +25,150 @@ RSpec.describe 'Companies API', type: :request do
expect(response_body['payload'].size).to eq(2)
expect(response_body['payload'].map { |c| c['name'] }).to contain_exactly(company1.name, company2.name)
end
+
+ it 'returns companies with pagination' do
+ create_list(:company, 30, account: account)
+
+ get "/api/v1/accounts/#{account.id}/companies",
+ params: { page: 1 },
+ headers: admin.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ response_body = response.parsed_body
+ expect(response_body['payload'].size).to eq(25)
+ expect(response_body['meta']['total_count']).to eq(32)
+ expect(response_body['meta']['page']).to eq(1)
+ end
+
+ it 'returns second page of companies' do
+ create_list(:company, 30, account: account)
+ get "/api/v1/accounts/#{account.id}/companies",
+ params: { page: 2 },
+ headers: admin.create_new_auth_token,
+ as: :json
+ expect(response).to have_http_status(:success)
+ response_body = response.parsed_body
+ expect(response_body['payload'].size).to eq(7)
+ expect(response_body['meta']['total_count']).to eq(32)
+ expect(response_body['meta']['page']).to eq(2)
+ end
+
+ it 'returns companies with contacts_count' do
+ company_with_contacts = create(:company, name: 'Company With Contacts', account: account)
+ create_list(:contact, 5, company: company_with_contacts, account: account)
+
+ get "/api/v1/accounts/#{account.id}/companies",
+ headers: admin.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ response_body = response.parsed_body
+ company_data = response_body['payload'].find { |c| c['id'] == company_with_contacts.id }
+ expect(company_data['contacts_count']).to eq(5)
+ end
+
+ it 'does not return companies from other accounts' do
+ other_account = create(:account)
+ create(:company, name: 'Other Account Company', account: other_account)
+ create(:company, name: 'My Company', account: account)
+ get "/api/v1/accounts/#{account.id}/companies",
+ headers: admin.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ response_body = response.parsed_body
+ expect(response_body['payload'].size).to eq(3)
+ expect(response_body['payload'].map { |c| c['name'] }).not_to include('Other Account Company')
+ end
+ end
+ end
+
+ describe 'GET /api/v1/accounts/{account.id}/companies/search' do
+ context 'when it is an unauthenticated user' do
+ it 'returns unauthorized' do
+ get "/api/v1/accounts/#{account.id}/companies/search"
+ expect(response).to have_http_status(:unauthorized)
+ end
+ end
+
+ context 'when it is an authenticated user' do
+ let(:admin) { create(:user, account: account, role: :administrator) }
+
+ it 'returns error when q parameter is missing' do
+ get "/api/v1/accounts/#{account.id}/companies/search",
+ headers: admin.create_new_auth_token,
+ as: :json
+ expect(response).to have_http_status(:unprocessable_entity)
+ expect(response.parsed_body['error']).to eq('Specify search string with parameter q')
+ end
+
+ it 'searches companies by name' do
+ create(:company, name: 'Acme Corp', domain: 'acme.com', account: account)
+ create(:company, name: 'Tech Solutions', domain: 'tech.com', account: account)
+ create(:company, name: 'Global Inc', domain: 'global.com', account: account)
+
+ get "/api/v1/accounts/#{account.id}/companies/search",
+ params: { q: 'tech' },
+ headers: admin.create_new_auth_token,
+ as: :json
+ expect(response).to have_http_status(:success)
+ response_body = response.parsed_body
+ expect(response_body['payload'].size).to eq(1)
+ expect(response_body['payload'].first['name']).to eq('Tech Solutions')
+ end
+
+ it 'searches companies by domain' do
+ create(:company, name: 'Acme Corp', domain: 'acme.com', account: account)
+ create(:company, name: 'Tech Solutions', domain: 'tech.com', account: account)
+ create(:company, name: 'Global Inc', domain: 'global.com', account: account)
+
+ get "/api/v1/accounts/#{account.id}/companies/search",
+ params: { q: 'acme.com' },
+ headers: admin.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ response_body = response.parsed_body
+ expect(response_body['payload'].size).to eq(1)
+ expect(response_body['payload'].first['domain']).to eq('acme.com')
+ end
+
+ it 'search is case insensitive' do
+ create(:company, name: 'Acme Corp', domain: 'acme.com', account: account)
+ get "/api/v1/accounts/#{account.id}/companies/search",
+ params: { q: 'ACME' },
+ headers: admin.create_new_auth_token,
+ as: :json
+ expect(response).to have_http_status(:success)
+ response_body = response.parsed_body
+
+ expect(response_body['payload'].size).to eq(1)
+ end
+
+ it 'returns empty array when no companies match search' do
+ create(:company, name: 'Acme Corp', domain: 'acme.com', account: account)
+ get "/api/v1/accounts/#{account.id}/companies/search",
+ params: { q: 'nonexistent' },
+ headers: admin.create_new_auth_token,
+ as: :json
+ expect(response).to have_http_status(:success)
+ response_body = response.parsed_body
+ expect(response_body['payload'].size).to eq(0)
+ expect(response_body['meta']['total_count']).to eq(0)
+ end
end
end
describe 'GET /api/v1/accounts/{account.id}/companies/{id}' do
+ context 'when it is an unauthenticated user' do
+ it 'returns unauthorized' do
+ company = create(:company, account: account)
+ get "/api/v1/accounts/#{account.id}/companies/#{company.id}"
+ expect(response).to have_http_status(:unauthorized)
+ end
+ end
+
context 'when it is an authenticated user' do
let(:admin) { create(:user, account: account, role: :administrator) }
let(:company) { create(:company, account: account) }
@@ -46,6 +186,13 @@ RSpec.describe 'Companies API', type: :request do
end
describe 'POST /api/v1/accounts/{account.id}/companies' do
+ context 'when it is an unauthenticated user' do
+ it 'returns unauthorized' do
+ post "/api/v1/accounts/#{account.id}/companies"
+ expect(response).to have_http_status(:unauthorized)
+ end
+ end
+
context 'when it is an authenticated user' do
let(:admin) { create(:user, account: account, role: :administrator) }
let(:valid_params) do
@@ -85,6 +232,14 @@ RSpec.describe 'Companies API', type: :request do
end
describe 'PATCH /api/v1/accounts/{account.id}/companies/{id}' do
+ context 'when it is an unauthenticated user' do
+ it 'returns unauthorized' do
+ company = create(:company, account: account)
+ patch "/api/v1/accounts/#{account.id}/companies/#{company.id}"
+ expect(response).to have_http_status(:unauthorized)
+ end
+ end
+
context 'when it is an authenticated user' do
let(:admin) { create(:user, account: account, role: :administrator) }
let(:company) { create(:company, account: account) }
@@ -111,6 +266,14 @@ RSpec.describe 'Companies API', type: :request do
end
describe 'DELETE /api/v1/accounts/{account.id}/companies/{id}' do
+ context 'when it is an unauthenticated user' do
+ it 'returns unauthorized' do
+ company = create(:company, account: account)
+ delete "/api/v1/accounts/#{account.id}/companies/#{company.id}"
+ expect(response).to have_http_status(:unauthorized)
+ end
+ end
+
context 'when it is an authenticated administrator' do
let(:admin) { create(:user, account: account, role: :administrator) }
let(:company) { create(:company, account: account) }
diff --git a/spec/enterprise/services/contacts/company_association_service_spec.rb b/spec/enterprise/services/contacts/company_association_service_spec.rb
index ea9363bad..78ee739c8 100644
--- a/spec/enterprise/services/contacts/company_association_service_spec.rb
+++ b/spec/enterprise/services/contacts/company_association_service_spec.rb
@@ -45,6 +45,25 @@ RSpec.describe Contacts::CompanyAssociationService, type: :service do
contact.reload
expect(contact.company).to eq(existing_company)
end
+
+ it 'increments company contacts_count when associating contact' do
+ # Create contact without email to avoid auto-association
+ contact = create(:contact, email: nil, account: account)
+ # Manually set email to bypass callbacks
+ # rubocop:disable Rails/SkipsModelValidations
+ contact.update_column(:email, 'jane@techcorp.com')
+ # rubocop:enable Rails/SkipsModelValidations
+
+ valid_email_address = instance_double(ValidEmail2::Address, valid?: true, disposable_domain?: false)
+ allow(ValidEmail2::Address).to receive(:new).with('jane@techcorp.com').and_return(valid_email_address)
+ allow(EmailProviderInfo).to receive(:call).with('jane@techcorp.com').and_return(nil)
+
+ service.associate_company_from_email(contact)
+
+ contact.reload
+ expect(contact.company).to be_present
+ expect(contact.company.contacts_count).to eq(1)
+ end
end
context 'when contact already has a company' do
From e33f28dc33383a83f35eb78137a17e0dfdbe0bd6 Mon Sep 17 00:00:00 2001
From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Date: Tue, 18 Nov 2025 15:29:15 +0530
Subject: [PATCH 76/80] feat: Companies page (#12842)
# Pull Request Template
## Description
This PR introduces a new Companies section in the Chatwoot dashboard. It
lists all companies associated with the account and includes features
such as **search**, **sorting**, and **pagination** to enable easier
navigation and efficient management.
Fixes
https://linear.app/chatwoot/issue/CW-5928/add-companies-tab-to-dashboard
## Type of change
- [x] New feature (non-breaking change which adds functionality)
## How Has This Been Tested?
### Screenshot
## Checklist:
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
---------
Co-authored-by: Vinay Keerthi <11478411+stonecharioteer@users.noreply.github.com>
Co-authored-by: Shivam Mishra
---
app/javascript/dashboard/api/companies.js | 37 +++++
.../dashboard/api/specs/companies.spec.js | 142 +++++++++++++++++
.../Companies/CompaniesCard/CompaniesCard.vue | 95 +++++++++++
.../CompaniesHeader/CompanyHeader.vue | 55 +++++++
.../components/CompanySortMenu.vue | 116 ++++++++++++++
.../Companies/CompaniesListLayout.vue | 50 ++++++
.../components-next/sidebar/Sidebar.vue | 17 ++
app/javascript/dashboard/featureFlags.js | 1 +
.../dashboard/i18n/locale/en/companies.json | 32 ++++
.../dashboard/i18n/locale/en/index.js | 2 +
.../dashboard/i18n/locale/en/settings.json | 2 +
.../companies/pages/CompaniesIndex.vue | 150 ++++++++++++++++++
.../routes/dashboard/companies/routes.js | 26 +++
.../routes/dashboard/dashboard.routes.js | 2 +
app/javascript/dashboard/store/index.js | 2 +
.../dashboard/store/modules/companies.js | 29 ++++
config/features.yml | 5 +
17 files changed, 763 insertions(+)
create mode 100644 app/javascript/dashboard/api/companies.js
create mode 100644 app/javascript/dashboard/api/specs/companies.spec.js
create mode 100644 app/javascript/dashboard/components-next/Companies/CompaniesCard/CompaniesCard.vue
create mode 100644 app/javascript/dashboard/components-next/Companies/CompaniesHeader/CompanyHeader.vue
create mode 100644 app/javascript/dashboard/components-next/Companies/CompaniesHeader/components/CompanySortMenu.vue
create mode 100644 app/javascript/dashboard/components-next/Companies/CompaniesListLayout.vue
create mode 100644 app/javascript/dashboard/i18n/locale/en/companies.json
create mode 100644 app/javascript/dashboard/routes/dashboard/companies/pages/CompaniesIndex.vue
create mode 100644 app/javascript/dashboard/routes/dashboard/companies/routes.js
create mode 100644 app/javascript/dashboard/store/modules/companies.js
diff --git a/app/javascript/dashboard/api/companies.js b/app/javascript/dashboard/api/companies.js
new file mode 100644
index 000000000..090b530c4
--- /dev/null
+++ b/app/javascript/dashboard/api/companies.js
@@ -0,0 +1,37 @@
+/* global axios */
+import ApiClient from './ApiClient';
+
+export const buildCompanyParams = (page, sort) => {
+ let params = `page=${page}`;
+ if (sort) {
+ params = `${params}&sort=${sort}`;
+ }
+ return params;
+};
+
+export const buildSearchParams = (query, page, sort) => {
+ let params = `q=${encodeURIComponent(query)}&page=${page}`;
+ if (sort) {
+ params = `${params}&sort=${sort}`;
+ }
+ return params;
+};
+
+class CompanyAPI extends ApiClient {
+ constructor() {
+ super('companies', { accountScoped: true });
+ }
+
+ get(params = {}) {
+ const { page = 1, sort = 'name' } = params;
+ const requestURL = `${this.url}?${buildCompanyParams(page, sort)}`;
+ return axios.get(requestURL);
+ }
+
+ search(query = '', page = 1, sort = 'name') {
+ const requestURL = `${this.url}/search?${buildSearchParams(query, page, sort)}`;
+ return axios.get(requestURL);
+ }
+}
+
+export default new CompanyAPI();
diff --git a/app/javascript/dashboard/api/specs/companies.spec.js b/app/javascript/dashboard/api/specs/companies.spec.js
new file mode 100644
index 000000000..82fdc1c97
--- /dev/null
+++ b/app/javascript/dashboard/api/specs/companies.spec.js
@@ -0,0 +1,142 @@
+import companyAPI, {
+ buildCompanyParams,
+ buildSearchParams,
+} from '../companies';
+import ApiClient from '../ApiClient';
+
+describe('#CompanyAPI', () => {
+ it('creates correct instance', () => {
+ expect(companyAPI).toBeInstanceOf(ApiClient);
+ expect(companyAPI).toHaveProperty('get');
+ expect(companyAPI).toHaveProperty('show');
+ expect(companyAPI).toHaveProperty('create');
+ expect(companyAPI).toHaveProperty('update');
+ expect(companyAPI).toHaveProperty('delete');
+ expect(companyAPI).toHaveProperty('search');
+ });
+
+ describe('API calls', () => {
+ const originalAxios = window.axios;
+ const axiosMock = {
+ post: vi.fn(() => Promise.resolve()),
+ get: vi.fn(() => Promise.resolve()),
+ patch: vi.fn(() => Promise.resolve()),
+ delete: vi.fn(() => Promise.resolve()),
+ };
+
+ beforeEach(() => {
+ window.axios = axiosMock;
+ });
+
+ afterEach(() => {
+ window.axios = originalAxios;
+ });
+
+ it('#get with default params', () => {
+ companyAPI.get({});
+ expect(axiosMock.get).toHaveBeenCalledWith(
+ '/api/v1/companies?page=1&sort=name'
+ );
+ });
+
+ it('#get with page and sort params', () => {
+ companyAPI.get({ page: 2, sort: 'domain' });
+ expect(axiosMock.get).toHaveBeenCalledWith(
+ '/api/v1/companies?page=2&sort=domain'
+ );
+ });
+
+ it('#get with descending sort', () => {
+ companyAPI.get({ page: 1, sort: '-created_at' });
+ expect(axiosMock.get).toHaveBeenCalledWith(
+ '/api/v1/companies?page=1&sort=-created_at'
+ );
+ });
+
+ it('#search with query', () => {
+ companyAPI.search('acme', 1, 'name');
+ expect(axiosMock.get).toHaveBeenCalledWith(
+ '/api/v1/companies/search?q=acme&page=1&sort=name'
+ );
+ });
+
+ it('#search with special characters in query', () => {
+ companyAPI.search('acme & co', 2, 'domain');
+ expect(axiosMock.get).toHaveBeenCalledWith(
+ '/api/v1/companies/search?q=acme%20%26%20co&page=2&sort=domain'
+ );
+ });
+
+ it('#search with descending sort', () => {
+ companyAPI.search('test', 1, '-created_at');
+ expect(axiosMock.get).toHaveBeenCalledWith(
+ '/api/v1/companies/search?q=test&page=1&sort=-created_at'
+ );
+ });
+
+ it('#search with empty query', () => {
+ companyAPI.search('', 1, 'name');
+ expect(axiosMock.get).toHaveBeenCalledWith(
+ '/api/v1/companies/search?q=&page=1&sort=name'
+ );
+ });
+ });
+});
+
+describe('#buildCompanyParams', () => {
+ it('returns correct string with page only', () => {
+ expect(buildCompanyParams(1)).toBe('page=1');
+ });
+
+ it('returns correct string with page and sort', () => {
+ expect(buildCompanyParams(1, 'name')).toBe('page=1&sort=name');
+ });
+
+ it('returns correct string with different page', () => {
+ expect(buildCompanyParams(3, 'domain')).toBe('page=3&sort=domain');
+ });
+
+ it('returns correct string with descending sort', () => {
+ expect(buildCompanyParams(1, '-created_at')).toBe(
+ 'page=1&sort=-created_at'
+ );
+ });
+
+ it('returns correct string without sort parameter', () => {
+ expect(buildCompanyParams(2, '')).toBe('page=2');
+ });
+});
+
+describe('#buildSearchParams', () => {
+ it('returns correct string with all parameters', () => {
+ expect(buildSearchParams('acme', 1, 'name')).toBe(
+ 'q=acme&page=1&sort=name'
+ );
+ });
+
+ it('returns correct string with special characters', () => {
+ expect(buildSearchParams('acme & co', 2, 'domain')).toBe(
+ 'q=acme%20%26%20co&page=2&sort=domain'
+ );
+ });
+
+ it('returns correct string with empty query', () => {
+ expect(buildSearchParams('', 1, 'name')).toBe('q=&page=1&sort=name');
+ });
+
+ it('returns correct string without sort parameter', () => {
+ expect(buildSearchParams('test', 1, '')).toBe('q=test&page=1');
+ });
+
+ it('returns correct string with descending sort', () => {
+ expect(buildSearchParams('company', 3, '-created_at')).toBe(
+ 'q=company&page=3&sort=-created_at'
+ );
+ });
+
+ it('encodes special characters correctly', () => {
+ expect(buildSearchParams('test@example.com', 1, 'name')).toBe(
+ 'q=test%40example.com&page=1&sort=name'
+ );
+ });
+});
diff --git a/app/javascript/dashboard/components-next/Companies/CompaniesCard/CompaniesCard.vue b/app/javascript/dashboard/components-next/Companies/CompaniesCard/CompaniesCard.vue
new file mode 100644
index 000000000..d5f191733
--- /dev/null
+++ b/app/javascript/dashboard/components-next/Companies/CompaniesCard/CompaniesCard.vue
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+ {{ displayName }}
+
+
+
+ {{ domain }}
+
+
+
+
+
+
+ {{ domain }}
+
+
+ {{ description }}
+
+
+
+
+ {{ t('COMPANIES.CONTACTS_COUNT', { count: contactsCount }) }}
+
+
+
+ {{ formattedUpdatedAt }}
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/components-next/Companies/CompaniesHeader/CompanyHeader.vue b/app/javascript/dashboard/components-next/Companies/CompaniesHeader/CompanyHeader.vue
new file mode 100644
index 000000000..f0dc4255f
--- /dev/null
+++ b/app/javascript/dashboard/components-next/Companies/CompaniesHeader/CompanyHeader.vue
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+ {{ headerTitle }}
+
+
+
+
+
diff --git a/app/javascript/dashboard/components-next/Companies/CompaniesHeader/components/CompanySortMenu.vue b/app/javascript/dashboard/components-next/Companies/CompaniesHeader/components/CompanySortMenu.vue
new file mode 100644
index 000000000..768123b9f
--- /dev/null
+++ b/app/javascript/dashboard/components-next/Companies/CompaniesHeader/components/CompanySortMenu.vue
@@ -0,0 +1,116 @@
+
+
+
+
+
+
+
+
+ {{ t('COMPANIES.SORT_BY.LABEL') }}
+
+
+
+
+
+ {{ t('COMPANIES.ORDER.LABEL') }}
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/components-next/Companies/CompaniesListLayout.vue b/app/javascript/dashboard/components-next/Companies/CompaniesListLayout.vue
new file mode 100644
index 000000000..430a2b835
--- /dev/null
+++ b/app/javascript/dashboard/components-next/Companies/CompaniesListLayout.vue
@@ -0,0 +1,50 @@
+
+
+
+
+
diff --git a/app/javascript/dashboard/components-next/sidebar/Sidebar.vue b/app/javascript/dashboard/components-next/sidebar/Sidebar.vue
index f5725d2e1..cd4309e6e 100644
--- a/app/javascript/dashboard/components-next/sidebar/Sidebar.vue
+++ b/app/javascript/dashboard/components-next/sidebar/Sidebar.vue
@@ -351,6 +351,23 @@ const menuItems = computed(() => {
},
],
},
+ {
+ name: 'Companies',
+ label: t('SIDEBAR.COMPANIES'),
+ icon: 'i-lucide-building-2',
+ children: [
+ {
+ name: 'All Companies',
+ label: t('SIDEBAR.ALL_COMPANIES'),
+ to: accountScopedRoute(
+ 'companies_dashboard_index',
+ {},
+ { page: 1, search: undefined }
+ ),
+ activeOn: ['companies_dashboard_index'],
+ },
+ ],
+ },
{
name: 'Reports',
label: t('SIDEBAR.REPORTS'),
diff --git a/app/javascript/dashboard/featureFlags.js b/app/javascript/dashboard/featureFlags.js
index 87227e74b..0508826d6 100644
--- a/app/javascript/dashboard/featureFlags.js
+++ b/app/javascript/dashboard/featureFlags.js
@@ -41,6 +41,7 @@ export const FEATURE_FLAGS = {
CAPTAIN_V2: 'captain_integration_v2',
SAML: 'saml',
QUOTED_EMAIL_REPLY: 'quoted_email_reply',
+ COMPANIES: 'companies',
};
export const PREMIUM_FEATURES = [
diff --git a/app/javascript/dashboard/i18n/locale/en/companies.json b/app/javascript/dashboard/i18n/locale/en/companies.json
new file mode 100644
index 000000000..2c491fa7d
--- /dev/null
+++ b/app/javascript/dashboard/i18n/locale/en/companies.json
@@ -0,0 +1,32 @@
+{
+ "COMPANIES": {
+ "HEADER": "Companies",
+ "SORT_BY": {
+ "LABEL": "Sort by",
+ "OPTIONS": {
+ "NAME": "Name",
+ "DOMAIN": "Domain",
+ "CREATED_AT": "Created at"
+ }
+ },
+ "ORDER": {
+ "LABEL": "Order",
+ "OPTIONS": {
+ "ASCENDING": "Ascending",
+ "DESCENDING": "Descending"
+ }
+ },
+ "SEARCH_PLACEHOLDER": "Search companies...",
+ "LOADING": "Loading companies...",
+ "UNNAMED": "Unnamed Company",
+ "CONTACTS_COUNT": "{count} contacts",
+ "EMPTY_STATE": {
+ "TITLE": "No companies found"
+ }
+ },
+ "COMPANIES_LAYOUT": {
+ "PAGINATION_FOOTER": {
+ "SHOWING": "Showing {startItem} - {endItem} of {totalItems} companies"
+ }
+ }
+}
diff --git a/app/javascript/dashboard/i18n/locale/en/index.js b/app/javascript/dashboard/i18n/locale/en/index.js
index e93dcd88e..17121fc61 100644
--- a/app/javascript/dashboard/i18n/locale/en/index.js
+++ b/app/javascript/dashboard/i18n/locale/en/index.js
@@ -8,6 +8,7 @@ import bulkActions from './bulkActions.json';
import campaign from './campaign.json';
import cannedMgmt from './cannedMgmt.json';
import chatlist from './chatlist.json';
+import companies from './companies.json';
import components from './components.json';
import contact from './contact.json';
import contactFilters from './contactFilters.json';
@@ -49,6 +50,7 @@ export default {
...campaign,
...cannedMgmt,
...chatlist,
+ ...companies,
...components,
...contact,
...contactFilters,
diff --git a/app/javascript/dashboard/i18n/locale/en/settings.json b/app/javascript/dashboard/i18n/locale/en/settings.json
index 4553572cb..b53bfed7b 100644
--- a/app/javascript/dashboard/i18n/locale/en/settings.json
+++ b/app/javascript/dashboard/i18n/locale/en/settings.json
@@ -306,6 +306,8 @@
"SETTINGS": "Settings",
"CONTACTS": "Contacts",
"ACTIVE": "Active",
+ "COMPANIES": "Companies",
+ "ALL_COMPANIES": "All Companies",
"CAPTAIN": "Captain",
"CAPTAIN_ASSISTANTS": "Assistants",
"CAPTAIN_DOCUMENTS": "Documents",
diff --git a/app/javascript/dashboard/routes/dashboard/companies/pages/CompaniesIndex.vue b/app/javascript/dashboard/routes/dashboard/companies/pages/CompaniesIndex.vue
new file mode 100644
index 000000000..3e86c97f4
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/companies/pages/CompaniesIndex.vue
@@ -0,0 +1,150 @@
+
+
+
+
+
+ {{
+ t('COMPANIES.LOADING')
+ }}
+
+
+ {{
+ t('COMPANIES.EMPTY_STATE.TITLE')
+ }}
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/companies/routes.js b/app/javascript/dashboard/routes/dashboard/companies/routes.js
new file mode 100644
index 000000000..69cbba762
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/companies/routes.js
@@ -0,0 +1,26 @@
+import { frontendURL } from '../../../helper/URLHelper';
+import CompaniesIndex from './pages/CompaniesIndex.vue';
+import { FEATURE_FLAGS } from '../../../featureFlags';
+import { INSTALLATION_TYPES } from 'dashboard/constants/installationTypes';
+
+const commonMeta = {
+ featureFlag: FEATURE_FLAGS.COMPANIES,
+ permissions: ['administrator', 'agent'],
+ installationTypes: [INSTALLATION_TYPES.CLOUD, INSTALLATION_TYPES.ENTERPRISE],
+};
+
+export const routes = [
+ {
+ path: frontendURL('accounts/:accountId/companies'),
+ component: CompaniesIndex,
+ meta: commonMeta,
+ children: [
+ {
+ path: '',
+ name: 'companies_dashboard_index',
+ component: CompaniesIndex,
+ meta: commonMeta,
+ },
+ ],
+ },
+];
diff --git a/app/javascript/dashboard/routes/dashboard/dashboard.routes.js b/app/javascript/dashboard/routes/dashboard/dashboard.routes.js
index 5d27d6e49..1882923bd 100644
--- a/app/javascript/dashboard/routes/dashboard/dashboard.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/dashboard.routes.js
@@ -2,6 +2,7 @@ import settings from './settings/settings.routes';
import conversation from './conversation/conversation.routes';
import { routes as searchRoutes } from '../../modules/search/search.routes';
import { routes as contactRoutes } from './contacts/routes';
+import { routes as companyRoutes } from './companies/routes';
import { routes as notificationRoutes } from './notifications/routes';
import { routes as inboxRoutes } from './inbox/routes';
import { frontendURL } from '../../helper/URLHelper';
@@ -23,6 +24,7 @@ export default {
...conversation.routes,
...settings.routes,
...contactRoutes,
+ ...companyRoutes,
...searchRoutes,
...notificationRoutes,
...helpcenterRoutes.routes,
diff --git a/app/javascript/dashboard/store/index.js b/app/javascript/dashboard/store/index.js
index d56958eb5..705ce1c2e 100755
--- a/app/javascript/dashboard/store/index.js
+++ b/app/javascript/dashboard/store/index.js
@@ -14,6 +14,7 @@ import bulkActions from './modules/bulkActions';
import campaigns from './modules/campaigns';
import cannedResponse from './modules/cannedResponse';
import categories from './modules/helpCenterCategories';
+import companies from './modules/companies';
import contactConversations from './modules/contactConversations';
import contactLabels from './modules/contactLabels';
import contactNotes from './modules/contactNotes';
@@ -77,6 +78,7 @@ export default createStore({
campaigns,
cannedResponse,
categories,
+ companies,
contactConversations,
contactLabels,
contactNotes,
diff --git a/app/javascript/dashboard/store/modules/companies.js b/app/javascript/dashboard/store/modules/companies.js
new file mode 100644
index 000000000..116ed7e15
--- /dev/null
+++ b/app/javascript/dashboard/store/modules/companies.js
@@ -0,0 +1,29 @@
+import CompanyAPI from 'dashboard/api/companies';
+import { createStore } from 'dashboard/store/captain/storeFactory';
+import camelcaseKeys from 'camelcase-keys';
+
+export default createStore({
+ name: 'Company',
+ API: CompanyAPI,
+ getters: {
+ getCompaniesList: state => {
+ return camelcaseKeys(state.records, { deep: true });
+ },
+ },
+ actions: mutationTypes => ({
+ search: async ({ commit }, { search, page, sort }) => {
+ commit(mutationTypes.SET_UI_FLAG, { fetchingList: true });
+ try {
+ const {
+ data: { payload, meta },
+ } = await CompanyAPI.search(search, page, sort);
+ commit(mutationTypes.SET, payload);
+ commit(mutationTypes.SET_META, meta);
+ } catch (error) {
+ // Error
+ } finally {
+ commit(mutationTypes.SET_UI_FLAG, { fetchingList: false });
+ }
+ },
+ }),
+});
diff --git a/config/features.yml b/config/features.yml
index e1f3b20d9..0813c1c0f 100644
--- a/config/features.yml
+++ b/config/features.yml
@@ -223,3 +223,8 @@
- name: quoted_email_reply
display_name: Quoted Email Reply
enabled: false
+- name: companies
+ display_name: Companies
+ enabled: false
+ premium: true
+ chatwoot_internal: true
From 6c07f62cfc40dc7062c9fc883d0de20ee35e842f Mon Sep 17 00:00:00 2001
From: Sojan Jose
Date: Tue, 18 Nov 2025 02:03:08 -0800
Subject: [PATCH 77/80] feat: Add Amazon SES inbound email support (#12893)
## Summary
- add AWS ActionMailbox SES gems
- document SES as incoming email provider
- note SES option in configuration
## Testing
- `bundle exec rubocop config/initializers/mailer.rb
config/environments/production.rb Gemfile`
------
[Codex
Task](https://chatgpt.com/codex/tasks/task_e_68bbb7d482288326b8f04bb795af0322)
---------
Co-authored-by: Pranav
Co-authored-by: Vinay Keerthi <11478411+stonecharioteer@users.noreply.github.com>
---
.env.example | 5 +++++
Gemfile | 3 +++
Gemfile.lock | 14 +++++++++++---
config/initializers/mailer.rb | 4 ++++
4 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/.env.example b/.env.example
index 3ff349ffc..9031fc08a 100644
--- a/.env.example
+++ b/.env.example
@@ -105,6 +105,7 @@ MAILER_INBOUND_EMAIL_DOMAIN=
# mandrill for Mandrill
# postmark for Postmark
# sendgrid for Sendgrid
+# ses for Amazon SES
RAILS_INBOUND_EMAIL_SERVICE=
# Use one of the following based on the email ingress service
# Ref: https://edgeguides.rubyonrails.org/action_mailbox_basics.html
@@ -114,6 +115,10 @@ RAILS_INBOUND_EMAIL_PASSWORD=
MAILGUN_INGRESS_SIGNING_KEY=
MANDRILL_INGRESS_API_KEY=
+# SNS topic ARN for ActionMailbox (format: arn:aws:sns:region:account-id:topic-name)
+# Configure only if the rails_inbound_email_service = ses
+ACTION_MAILBOX_SES_SNS_TOPIC=
+
# Creating Your Inbound Webhook Instructions for Postmark and Sendgrid:
# Inbound webhook URL format:
# https://actionmailbox:[YOUR_RAILS_INBOUND_EMAIL_PASSWORD]@[YOUR_CHATWOOT_DOMAIN.COM]/rails/action_mailbox/[RAILS_INBOUND_EMAIL_SERVICE]/inbound_emails
diff --git a/Gemfile b/Gemfile
index abbd3332f..31ecf5b3c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -55,6 +55,9 @@ gem 'azure-storage-blob', git: 'https://github.com/chatwoot/azure-storage-ruby',
gem 'google-cloud-storage', '>= 1.48.0', require: false
gem 'image_processing'
+##-- for actionmailbox --##
+gem 'aws-actionmailbox-ses', '~> 0'
+
##-- gems for database --#
gem 'groupdate'
gem 'pg'
diff --git a/Gemfile.lock b/Gemfile.lock
index 99e75b33c..6af8c0e7c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -136,9 +136,13 @@ GEM
audited (5.4.1)
activerecord (>= 5.0, < 7.7)
activesupport (>= 5.0, < 7.7)
+ aws-actionmailbox-ses (0.1.0)
+ actionmailbox (>= 7.1.0)
+ aws-sdk-s3 (~> 1, >= 1.123.0)
+ aws-sdk-sns (~> 1, >= 1.61.0)
aws-eventstream (1.2.0)
aws-partitions (1.760.0)
- aws-sdk-core (3.171.1)
+ aws-sdk-core (3.188.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
@@ -146,10 +150,13 @@ GEM
aws-sdk-kms (1.64.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.122.0)
- aws-sdk-core (~> 3, >= 3.165.0)
+ aws-sdk-s3 (1.126.0)
+ aws-sdk-core (~> 3, >= 3.174.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
+ aws-sdk-sns (1.70.0)
+ aws-sdk-core (~> 3, >= 3.188.0)
+ aws-sigv4 (~> 1.1)
aws-sigv4 (1.5.2)
aws-eventstream (~> 1, >= 1.0.2)
barnes (0.0.9)
@@ -995,6 +1002,7 @@ DEPENDENCIES
annotate
attr_extras
audited (~> 5.4, >= 5.4.1)
+ aws-actionmailbox-ses (~> 0)
aws-sdk-s3
azure-storage-blob!
barnes
diff --git a/config/initializers/mailer.rb b/config/initializers/mailer.rb
index a0e5d7b73..3d585d8b6 100644
--- a/config/initializers/mailer.rb
+++ b/config/initializers/mailer.rb
@@ -46,5 +46,9 @@ Rails.application.configure do
# :mandrill for Mandrill
# :postmark for Postmark
# :sendgrid for Sendgrid
+ # :ses for Amazon SES
config.action_mailbox.ingress = ENV.fetch('RAILS_INBOUND_EMAIL_SERVICE', 'relay').to_sym
+
+ # Amazon SES ActionMailbox configuration
+ config.action_mailbox.ses.subscribed_topic = ENV['ACTION_MAILBOX_SES_SNS_TOPIC'] if ENV['ACTION_MAILBOX_SES_SNS_TOPIC'].present?
end
From 70c183ea6e069302c1fa0cc85456beb75486b7c7 Mon Sep 17 00:00:00 2001
From: Vishnu Narayanan
Date: Wed, 19 Nov 2025 07:35:12 +0530
Subject: [PATCH 78/80] feat: hide email forwarding address if
INBOUND_EMAIL_DOMAIN is not configured (#12768)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
#### Summary
- Improved email inbox setup flow to handle cases where inbound email
forwarding is not configured on the installation
- Added conditional display of email forwarding address based on
MAILER_INBOUND_EMAIL_DOMAIN environment variable availability
- Enhanced user messaging to guide users toward configuring SMTP/IMAP
settings when forwarding is unavailable
#### Changes
**Backend (app/views/api/v1/models/_inbox.json.jbuilder)**
- Added forwarding_enabled boolean flag to inbox API response based on
MAILER_INBOUND_EMAIL_DOMAIN presence
- Made forward_to_email conditional - only included when forwarding is
enabled
**Frontend - Inbox Creation Flow**
- Created new EmailInboxFinish.vue component to handle email inbox setup
completion
- Shows different messages based on whether forwarding is enabled:
- With forwarding: displays forwarding address and encourages SMTP/IMAP
configuration
- Without forwarding: warns that SMTP/IMAP configuration is required for
emails to be processed
- Added link to configuration page for easy access to SMTP/IMAP settings
Fixes
https://linear.app/chatwoot/issue/CW-5881/hide-forwaring-email-section-if-inbound-email-domain-is-not-configured
## Type of change
- [x] New feature (non-breaking change which adds functionality)
## How Has This Been Tested?
- Tested locally
## Checklist:
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules
---------
Co-authored-by: Pranav
---
.../dashboard/i18n/locale/en/inboxMgmt.json | 7 ++-
.../dashboard/settings/inbox/FinishSetup.vue | 16 ++----
.../emailChannels/EmailInboxFinish.vue | 55 +++++++++++++++++++
.../inbox/settingsPage/ConfigurationPage.vue | 22 +++++++-
app/views/api/v1/models/_inbox.json.jbuilder | 3 +-
5 files changed, 89 insertions(+), 14 deletions(-)
create mode 100644 app/javascript/dashboard/routes/dashboard/settings/inbox/channels/emailChannels/EmailInboxFinish.vue
diff --git a/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json
index 87fe57564..a4092289e 100644
--- a/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json
+++ b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json
@@ -381,7 +381,11 @@
"API": {
"ERROR_MESSAGE": "We were not able to save the email channel"
},
- "FINISH_MESSAGE": "Start forwarding your emails to the following email address."
+ "FINISH_MESSAGE": "Your email inbox has been created successfully! You can start forwarding your emails to the address below, or configure SMTP and IMAP credentials to send and receive emails directly.",
+ "FINISH_MESSAGE_NO_FORWARDING": "Your email inbox has been created successfully! You need to configure SMTP and IMAP credentials to send and receive emails. Without these settings, no emails will be processed.",
+ "FORWARDING_ADDRESS_LABEL": "Forward emails to this address:",
+ "CONFIGURE_SMTP_IMAP_LINK": "Click here",
+ "CONFIGURE_SMTP_IMAP_TEXT": " to configure IMAP and SMTP settings"
},
"LINE_CHANNEL": {
"TITLE": "LINE Channel",
@@ -707,6 +711,7 @@
"INBOX_IDENTIFIER_SUB_TEXT": "Use the `inbox_identifier` token shown here to authentication your API clients.",
"FORWARD_EMAIL_TITLE": "Forward to Email",
"FORWARD_EMAIL_SUB_TEXT": "Start forwarding your emails to the following email address.",
+ "FORWARD_EMAIL_NOT_CONFIGURED": "Forwarding emails to your inbox is currently disabled on this installation. To use this feature, it must be enabled by your administrator. Please get in touch with them to proceed.",
"ALLOW_MESSAGES_AFTER_RESOLVED": "Allow messages after conversation resolved",
"ALLOW_MESSAGES_AFTER_RESOLVED_SUB_TEXT": "Allow the end-users to send messages even after the conversation is resolved.",
"WHATSAPP_SECTION_SUBHEADER": "This API Key is used for the integration with the WhatsApp APIs.",
diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/FinishSetup.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/FinishSetup.vue
index 46a189b39..ec89ec930 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/inbox/FinishSetup.vue
+++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/FinishSetup.vue
@@ -7,6 +7,7 @@ import QRCode from 'qrcode';
import EmptyState from '../../../../components/widgets/EmptyState.vue';
import NextButton from 'dashboard/components-next/button/Button.vue';
import DuplicateInboxBanner from './channels/instagram/DuplicateInboxBanner.vue';
+import EmailInboxFinish from './channels/emailChannels/EmailInboxFinish.vue';
import { useInbox } from 'dashboard/composables/useInbox';
import { INBOX_TYPES } from 'dashboard/helper/inbox';
@@ -86,10 +87,6 @@ const message = computed(() => {
)}`;
}
- if (isAnEmailChannel.value && !currentInbox.value.provider) {
- return t('INBOX_MGMT.ADD.EMAIL_CHANNEL.FINISH_MESSAGE');
- }
-
if (currentInbox.value.web_widget_script) {
return t('INBOX_MGMT.FINISH.WEBSITE_SUCCESS');
}
@@ -176,7 +173,7 @@ onMounted(() => {
/>
@@ -227,12 +224,11 @@ onMounted(() => {
:script="currentInbox.callback_webhook_url"
/>
-
-
-
+ :inbox="currentInbox"
+ :inbox-id="$route.params.inbox_id"
+ />
+import { computed } from 'vue';
+import { useI18n } from 'vue-i18n';
+
+const props = defineProps({
+ inbox: {
+ type: Object,
+ required: true,
+ },
+ inboxId: {
+ type: [String, Number],
+ required: true,
+ },
+});
+
+const { t } = useI18n();
+
+const message = computed(() => {
+ return props.inbox.forwarding_enabled
+ ? t('INBOX_MGMT.ADD.EMAIL_CHANNEL.FINISH_MESSAGE')
+ : t('INBOX_MGMT.ADD.EMAIL_CHANNEL.FINISH_MESSAGE_NO_FORWARDING');
+});
+
+const showForwardingAddress = computed(() => {
+ return props.inbox.forwarding_enabled;
+});
+
+
+
+
+
+ {{ message }}
+
+
+
+
+ {{ $t('INBOX_MGMT.ADD.EMAIL_CHANNEL.FORWARDING_ADDRESS_LABEL') }}
+
+
+
+
+
+
+ {{ $t('INBOX_MGMT.ADD.EMAIL_CHANNEL.CONFIGURE_SMTP_IMAP_LINK') }}
+
+ {{ $t('INBOX_MGMT.ADD.EMAIL_CHANNEL.CONFIGURE_SMTP_IMAP_TEXT') }}
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/ConfigurationPage.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/ConfigurationPage.vue
index 578a788cd..25f96ad3e 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/ConfigurationPage.vue
+++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/ConfigurationPage.vue
@@ -50,6 +50,9 @@ export default {
whatsappAppId() {
return window.chatwootConfig?.whatsappAppId;
},
+ isForwardingEnabled() {
+ return !!this.inbox.forwarding_enabled;
+ },
},
watch: {
inbox() {
@@ -300,9 +303,24 @@ export default {
-
+
+
+
+ {{ $t('INBOX_MGMT.SETTINGS_POPUP.FORWARD_EMAIL_NOT_CONFIGURED') }}
+
+
diff --git a/app/views/api/v1/models/_inbox.json.jbuilder b/app/views/api/v1/models/_inbox.json.jbuilder
index d9134d563..cf7346dde 100644
--- a/app/views/api/v1/models/_inbox.json.jbuilder
+++ b/app/views/api/v1/models/_inbox.json.jbuilder
@@ -74,8 +74,9 @@ end
if resource.email?
## Email Channel Attributes
- json.forward_to_email resource.channel.try(:forward_to_email)
json.email resource.channel.try(:email)
+ json.forwarding_enabled ENV.fetch('MAILER_INBOUND_EMAIL_DOMAIN', '').present?
+ json.forward_to_email resource.channel.try(:forward_to_email) if ENV.fetch('MAILER_INBOUND_EMAIL_DOMAIN', '').present?
## IMAP
if Current.account_user&.administrator?
From 5f2b2f4221a32058f58c2feb41a4a2cb6794e2f9 Mon Sep 17 00:00:00 2001
From: Sojan Jose
Date: Tue, 18 Nov 2025 18:20:58 -0800
Subject: [PATCH 79/80] feat: APIs to assign agents_bots as assignee in
conversations (#12836)
## Summary
- add an assignee_agent_bot_id column as an initital step to prototype
this before fully switching to polymorphic assignee
- update assignment APIs and conversation list / show endpoints to
reflect assignee as agent bot
- ensure webhook payloads contains agent bot assignee
[Codex
Task](https://chatgpt.com/codex/tasks/task_e_6912833377e48326b6641b9eee32d50f)
---------
Co-authored-by: Pranav
---
.../api/v1/accounts/agent_bots_controller.rb | 4 +-
.../conversations/assignments_controller.rb | 28 ++++++---
.../concerns/ensure_current_account_helper.rb | 5 +-
.../dashboard/api/inbox/conversation.js | 7 +--
.../api/specs/inbox/conversation.spec.js | 6 +-
.../widgets/conversation/ReplyBoxBanner.vue | 2 +-
.../conversation/ConversationAction.vue | 2 +-
app/listeners/agent_bot_listener.rb | 33 +++++-----
app/models/agent_bot.rb | 9 +++
app/models/conversation.rb | 25 +++++++-
.../conversations/event_data_presenter.rb | 3 +-
.../conversations/assignment_service.rb | 43 +++++++++++++
.../assignments/create.json.jbuilder | 4 --
.../partials/_conversation.json.jbuilder | 10 ++-
.../v1/models/_agent_bot_slim.json.jbuilder | 6 ++
..._assignee_agent_bot_id_to_conversations.rb | 5 ++
db/schema.rb | 1 +
.../assignments_controller_spec.rb | 24 ++++++-
spec/listeners/agent_bot_listener_spec.rb | 18 ++++++
spec/models/conversation_spec.rb | 5 +-
.../event_data_presenter_spec.rb | 5 +-
.../api/v1/accounts/base_controller_spec.rb | 63 +++++++++++++++++++
.../conversations/assignment_service_spec.rb | 60 ++++++++++++++++++
23 files changed, 316 insertions(+), 52 deletions(-)
create mode 100644 app/services/conversations/assignment_service.rb
delete mode 100644 app/views/api/v1/accounts/conversations/assignments/create.json.jbuilder
create mode 100644 app/views/api/v1/models/_agent_bot_slim.json.jbuilder
create mode 100644 db/migrate/20251022162159_add_assignee_agent_bot_id_to_conversations.rb
create mode 100644 spec/requests/api/v1/accounts/base_controller_spec.rb
create mode 100644 spec/services/conversations/assignment_service_spec.rb
diff --git a/app/controllers/api/v1/accounts/agent_bots_controller.rb b/app/controllers/api/v1/accounts/agent_bots_controller.rb
index 64c35d33d..c2f919659 100644
--- a/app/controllers/api/v1/accounts/agent_bots_controller.rb
+++ b/app/controllers/api/v1/accounts/agent_bots_controller.rb
@@ -4,7 +4,7 @@ class Api::V1::Accounts::AgentBotsController < Api::V1::Accounts::BaseController
before_action :agent_bot, except: [:index, :create]
def index
- @agent_bots = AgentBot.where(account_id: [nil, Current.account.id])
+ @agent_bots = AgentBot.accessible_to(Current.account)
end
def show; end
@@ -37,7 +37,7 @@ class Api::V1::Accounts::AgentBotsController < Api::V1::Accounts::BaseController
private
def agent_bot
- @agent_bot = AgentBot.where(account_id: [nil, Current.account.id]).find(params[:id]) if params[:action] == 'show'
+ @agent_bot = AgentBot.accessible_to(Current.account).find(params[:id]) if params[:action] == 'show'
@agent_bot ||= Current.account.agent_bots.find(params[:id])
end
diff --git a/app/controllers/api/v1/accounts/conversations/assignments_controller.rb b/app/controllers/api/v1/accounts/conversations/assignments_controller.rb
index 1fb2095e3..49806e97c 100644
--- a/app/controllers/api/v1/accounts/conversations/assignments_controller.rb
+++ b/app/controllers/api/v1/accounts/conversations/assignments_controller.rb
@@ -1,7 +1,7 @@
class Api::V1::Accounts::Conversations::AssignmentsController < Api::V1::Accounts::Conversations::BaseController
# assigns agent/team to a conversation
def create
- if params.key?(:assignee_id)
+ if params.key?(:assignee_id) || agent_bot_assignment?
set_agent
elsif params.key?(:team_id)
set_team
@@ -13,17 +13,23 @@ class Api::V1::Accounts::Conversations::AssignmentsController < Api::V1::Account
private
def set_agent
- @agent = Current.account.users.find_by(id: params[:assignee_id])
- @conversation.assignee = @agent
- @conversation.save!
- render_agent
+ resource = Conversations::AssignmentService.new(
+ conversation: @conversation,
+ assignee_id: params[:assignee_id],
+ assignee_type: params[:assignee_type]
+ ).perform
+
+ render_agent(resource)
end
- def render_agent
- if @agent.nil?
- render json: nil
+ def render_agent(resource)
+ case resource
+ when User
+ render partial: 'api/v1/models/agent', formats: [:json], locals: { resource: resource }
+ when AgentBot
+ render partial: 'api/v1/models/agent_bot_slim', formats: [:json], locals: { resource: resource }
else
- render partial: 'api/v1/models/agent', formats: [:json], locals: { resource: @agent }
+ render json: nil
end
end
@@ -32,4 +38,8 @@ class Api::V1::Accounts::Conversations::AssignmentsController < Api::V1::Account
@conversation.update!(team: @team)
render json: @team
end
+
+ def agent_bot_assignment?
+ params[:assignee_type].to_s == 'AgentBot'
+ end
end
diff --git a/app/controllers/concerns/ensure_current_account_helper.rb b/app/controllers/concerns/ensure_current_account_helper.rb
index 3baf9ee1e..ea36a48f2 100644
--- a/app/controllers/concerns/ensure_current_account_helper.rb
+++ b/app/controllers/concerns/ensure_current_account_helper.rb
@@ -25,6 +25,9 @@ module EnsureCurrentAccountHelper
end
def account_accessible_for_bot?(account)
- render_unauthorized('Bot is not authorized to access this account') unless @resource.agent_bot_inboxes.find_by(account_id: account.id)
+ return if @resource.account_id == account.id
+ return if @resource.agent_bot_inboxes.find_by(account_id: account.id)
+
+ render_unauthorized('Bot is not authorized to access this account')
end
end
diff --git a/app/javascript/dashboard/api/inbox/conversation.js b/app/javascript/dashboard/api/inbox/conversation.js
index 0f539bfa9..f94fca452 100644
--- a/app/javascript/dashboard/api/inbox/conversation.js
+++ b/app/javascript/dashboard/api/inbox/conversation.js
@@ -63,10 +63,9 @@ class ConversationApi extends ApiClient {
}
assignAgent({ conversationId, agentId }) {
- return axios.post(
- `${this.url}/${conversationId}/assignments?assignee_id=${agentId}`,
- {}
- );
+ return axios.post(`${this.url}/${conversationId}/assignments`, {
+ assignee_id: agentId,
+ });
}
assignTeam({ conversationId, teamId }) {
diff --git a/app/javascript/dashboard/api/specs/inbox/conversation.spec.js b/app/javascript/dashboard/api/specs/inbox/conversation.spec.js
index dd1615802..de0d7a7d0 100644
--- a/app/javascript/dashboard/api/specs/inbox/conversation.spec.js
+++ b/app/javascript/dashboard/api/specs/inbox/conversation.spec.js
@@ -92,8 +92,10 @@ describe('#ConversationAPI', () => {
it('#assignAgent', () => {
conversationAPI.assignAgent({ conversationId: 12, agentId: 34 });
expect(axiosMock.post).toHaveBeenCalledWith(
- `/api/v1/conversations/12/assignments?assignee_id=34`,
- {}
+ `/api/v1/conversations/12/assignments`,
+ {
+ assignee_id: 34,
+ }
);
});
diff --git a/app/javascript/dashboard/components/widgets/conversation/ReplyBoxBanner.vue b/app/javascript/dashboard/components/widgets/conversation/ReplyBoxBanner.vue
index 3aea41f90..d80910343 100644
--- a/app/javascript/dashboard/components/widgets/conversation/ReplyBoxBanner.vue
+++ b/app/javascript/dashboard/components/widgets/conversation/ReplyBoxBanner.vue
@@ -30,7 +30,7 @@ const assignedAgent = computed({
return currentChat.value?.meta?.assignee;
},
set(agent) {
- const agentId = agent ? agent.id : 0;
+ const agentId = agent ? agent.id : null;
store.dispatch('setCurrentChatAssignee', agent);
store.dispatch('assignAgent', {
conversationId: currentChat.value?.id,
diff --git a/app/javascript/dashboard/routes/dashboard/conversation/ConversationAction.vue b/app/javascript/dashboard/routes/dashboard/conversation/ConversationAction.vue
index f94fc7a9b..76533a94d 100644
--- a/app/javascript/dashboard/routes/dashboard/conversation/ConversationAction.vue
+++ b/app/javascript/dashboard/routes/dashboard/conversation/ConversationAction.vue
@@ -84,7 +84,7 @@ export default {
return this.currentChat.meta.assignee;
},
set(agent) {
- const agentId = agent ? agent.id : 0;
+ const agentId = agent ? agent.id : null;
this.$store.dispatch('setCurrentChatAssignee', agent);
this.$store
.dispatch('assignAgent', {
diff --git a/app/listeners/agent_bot_listener.rb b/app/listeners/agent_bot_listener.rb
index 38c046e34..ccac8005f 100644
--- a/app/listeners/agent_bot_listener.rb
+++ b/app/listeners/agent_bot_listener.rb
@@ -2,61 +2,60 @@ class AgentBotListener < BaseListener
def conversation_resolved(event)
conversation = extract_conversation_and_account(event)[0]
inbox = conversation.inbox
- return unless connected_agent_bot_exist?(inbox)
-
event_name = __method__.to_s
payload = conversation.webhook_data.merge(event: event_name)
- process_webhook_bot_event(inbox.agent_bot, payload)
+ agent_bots_for(inbox, conversation).each { |agent_bot| process_webhook_bot_event(agent_bot, payload) }
end
def conversation_opened(event)
conversation = extract_conversation_and_account(event)[0]
inbox = conversation.inbox
- return unless connected_agent_bot_exist?(inbox)
-
event_name = __method__.to_s
payload = conversation.webhook_data.merge(event: event_name)
- process_webhook_bot_event(inbox.agent_bot, payload)
+ agent_bots_for(inbox, conversation).each { |agent_bot| process_webhook_bot_event(agent_bot, payload) }
end
def message_created(event)
message = extract_message_and_account(event)[0]
inbox = message.inbox
- return unless connected_agent_bot_exist?(inbox)
return unless message.webhook_sendable?
method_name = __method__.to_s
- process_message_event(method_name, inbox.agent_bot, message, event)
+ agent_bots_for(inbox, message.conversation).each { |agent_bot| process_message_event(method_name, agent_bot, message, event) }
end
def message_updated(event)
message = extract_message_and_account(event)[0]
inbox = message.inbox
- return unless connected_agent_bot_exist?(inbox)
return unless message.webhook_sendable?
method_name = __method__.to_s
- process_message_event(method_name, inbox.agent_bot, message, event)
+ agent_bots_for(inbox, message.conversation).each { |agent_bot| process_message_event(method_name, agent_bot, message, event) }
end
def webwidget_triggered(event)
contact_inbox = event.data[:contact_inbox]
inbox = contact_inbox.inbox
- return unless connected_agent_bot_exist?(inbox)
-
event_name = __method__.to_s
payload = contact_inbox.webhook_data.merge(event: event_name)
payload[:event_info] = event.data[:event_info]
- process_webhook_bot_event(inbox.agent_bot, payload)
+ agent_bots_for(inbox).each { |agent_bot| process_webhook_bot_event(agent_bot, payload) }
end
private
- def connected_agent_bot_exist?(inbox)
- return if inbox.agent_bot_inbox.blank?
- return unless inbox.agent_bot_inbox.active?
+ def agent_bots_for(inbox, conversation = nil)
+ bots = []
+ bots << conversation.assignee_agent_bot if conversation&.assignee_agent_bot.present?
+ inbox_bot = active_inbox_agent_bot(inbox)
+ bots << inbox_bot if inbox_bot.present?
+ bots.compact.uniq
+ end
- true
+ def active_inbox_agent_bot(inbox)
+ return unless inbox.agent_bot_inbox&.active?
+
+ inbox.agent_bot
end
def process_message_event(method_name, agent_bot, message, _event)
diff --git a/app/models/agent_bot.rb b/app/models/agent_bot.rb
index be63aebc5..b839f21b4 100644
--- a/app/models/agent_bot.rb
+++ b/app/models/agent_bot.rb
@@ -21,9 +21,18 @@ class AgentBot < ApplicationRecord
include AccessTokenable
include Avatarable
+ scope :accessible_to, lambda { |account|
+ account_id = account&.id
+ where(account_id: [nil, account_id])
+ }
+
has_many :agent_bot_inboxes, dependent: :destroy_async
has_many :inboxes, through: :agent_bot_inboxes
has_many :messages, as: :sender, dependent: :nullify
+ has_many :assigned_conversations, class_name: 'Conversation',
+ foreign_key: :assignee_agent_bot_id,
+ dependent: :nullify,
+ inverse_of: :assignee_agent_bot
belongs_to :account, optional: true
enum bot_type: { webhook: 0 }
diff --git a/app/models/conversation.rb b/app/models/conversation.rb
index ca8a3258e..ac0985416 100644
--- a/app/models/conversation.rb
+++ b/app/models/conversation.rb
@@ -20,6 +20,7 @@
# created_at :datetime not null
# updated_at :datetime not null
# account_id :integer not null
+# assignee_agent_bot_id :bigint
# assignee_id :integer
# campaign_id :bigint
# contact_id :bigint
@@ -65,6 +66,7 @@ class Conversation < ApplicationRecord
validates :inbox_id, presence: true
validates :contact_id, presence: true
before_validation :validate_additional_attributes
+ before_validation :reset_agent_bot_when_assignee_present
validates :additional_attributes, jsonb_attributes_length: true
validates :custom_attributes, jsonb_attributes_length: true
validates :uuid, uniqueness: true
@@ -98,6 +100,7 @@ class Conversation < ApplicationRecord
belongs_to :account
belongs_to :inbox
belongs_to :assignee, class_name: 'User', optional: true, inverse_of: :assigned_conversations
+ belongs_to :assignee_agent_bot, class_name: 'AgentBot', optional: true
belongs_to :contact
belongs_to :contact_inbox
belongs_to :team, optional: true
@@ -180,6 +183,18 @@ class Conversation < ApplicationRecord
true
end
+ # Virtual attribute till we switch completely to polymorphic assignee
+ def assignee_type
+ return 'AgentBot' if assignee_agent_bot_id.present?
+ return 'User' if assignee_id.present?
+
+ nil
+ end
+
+ def assigned_entity
+ assignee_agent_bot || assignee
+ end
+
def tweet?
inbox.inbox_type == 'Twitter' && additional_attributes['type'] == 'tweet'
end
@@ -226,6 +241,12 @@ class Conversation < ApplicationRecord
self.additional_attributes = {} unless additional_attributes.is_a?(Hash)
end
+ def reset_agent_bot_when_assignee_present
+ return if assignee_id.blank?
+
+ self.assignee_agent_bot_id = nil
+ end
+
def determine_conversation_status
self.status = :resolved and return if contact.blocked?
@@ -251,8 +272,8 @@ class Conversation < ApplicationRecord
end
def list_of_keys
- %w[team_id assignee_id status snoozed_until custom_attributes label_list waiting_since first_reply_created_at
- priority]
+ %w[team_id assignee_id assignee_agent_bot_id status snoozed_until custom_attributes label_list waiting_since
+ first_reply_created_at priority]
end
def allowed_keys?
diff --git a/app/presenters/conversations/event_data_presenter.rb b/app/presenters/conversations/event_data_presenter.rb
index 2ef69080d..4a9216b05 100644
--- a/app/presenters/conversations/event_data_presenter.rb
+++ b/app/presenters/conversations/event_data_presenter.rb
@@ -30,7 +30,8 @@ class Conversations::EventDataPresenter < SimpleDelegator
def push_meta
{
sender: contact.push_event_data,
- assignee: assignee&.push_event_data,
+ assignee: assigned_entity&.push_event_data,
+ assignee_type: assignee_type,
team: team&.push_event_data,
hmac_verified: contact_inbox&.hmac_verified
}
diff --git a/app/services/conversations/assignment_service.rb b/app/services/conversations/assignment_service.rb
new file mode 100644
index 000000000..adca34f06
--- /dev/null
+++ b/app/services/conversations/assignment_service.rb
@@ -0,0 +1,43 @@
+class Conversations::AssignmentService
+ def initialize(conversation:, assignee_id:, assignee_type: nil)
+ @conversation = conversation
+ @assignee_id = assignee_id
+ @assignee_type = assignee_type
+ end
+
+ def perform
+ agent_bot_assignment? ? assign_agent_bot : assign_agent
+ end
+
+ private
+
+ attr_reader :conversation, :assignee_id, :assignee_type
+
+ def assign_agent
+ conversation.assignee = assignee
+ conversation.assignee_agent_bot = nil
+ conversation.save!
+ assignee
+ end
+
+ def assign_agent_bot
+ return unless agent_bot
+
+ conversation.assignee = nil
+ conversation.assignee_agent_bot = agent_bot
+ conversation.save!
+ agent_bot
+ end
+
+ def assignee
+ @assignee ||= conversation.account.users.find_by(id: assignee_id)
+ end
+
+ def agent_bot
+ @agent_bot ||= AgentBot.accessible_to(conversation.account).find_by(id: assignee_id)
+ end
+
+ def agent_bot_assignment?
+ assignee_type.to_s == 'AgentBot'
+ end
+end
diff --git a/app/views/api/v1/accounts/conversations/assignments/create.json.jbuilder b/app/views/api/v1/accounts/conversations/assignments/create.json.jbuilder
deleted file mode 100644
index 1c5bd4846..000000000
--- a/app/views/api/v1/accounts/conversations/assignments/create.json.jbuilder
+++ /dev/null
@@ -1,4 +0,0 @@
-json.payload do
- json.assignee @conversation.assignee
- json.conversation_id @conversation.display_id
-end
diff --git a/app/views/api/v1/conversations/partials/_conversation.json.jbuilder b/app/views/api/v1/conversations/partials/_conversation.json.jbuilder
index 8867ba695..4cb13f543 100644
--- a/app/views/api/v1/conversations/partials/_conversation.json.jbuilder
+++ b/app/views/api/v1/conversations/partials/_conversation.json.jbuilder
@@ -7,10 +7,16 @@ json.meta do
json.partial! 'api/v1/models/contact', formats: [:json], resource: conversation.contact
end
json.channel conversation.inbox.try(:channel_type)
- if conversation.assignee&.account
+ if conversation.assigned_entity.is_a?(AgentBot)
json.assignee do
- json.partial! 'api/v1/models/agent', formats: [:json], resource: conversation.assignee
+ json.partial! 'api/v1/models/agent_bot_slim', formats: [:json], resource: conversation.assigned_entity
end
+ json.assignee_type 'AgentBot'
+ elsif conversation.assigned_entity&.account
+ json.assignee do
+ json.partial! 'api/v1/models/agent', formats: [:json], resource: conversation.assigned_entity
+ end
+ json.assignee_type 'User'
end
if conversation.team.present?
json.team do
diff --git a/app/views/api/v1/models/_agent_bot_slim.json.jbuilder b/app/views/api/v1/models/_agent_bot_slim.json.jbuilder
new file mode 100644
index 000000000..29f1e12a5
--- /dev/null
+++ b/app/views/api/v1/models/_agent_bot_slim.json.jbuilder
@@ -0,0 +1,6 @@
+json.id resource.id
+json.name resource.name
+json.description resource.description
+json.thumbnail resource.avatar_url
+json.outgoing_url resource.outgoing_url unless resource.system_bot?
+json.bot_type resource.bot_type
diff --git a/db/migrate/20251022162159_add_assignee_agent_bot_id_to_conversations.rb b/db/migrate/20251022162159_add_assignee_agent_bot_id_to_conversations.rb
new file mode 100644
index 000000000..0a96c319e
--- /dev/null
+++ b/db/migrate/20251022162159_add_assignee_agent_bot_id_to_conversations.rb
@@ -0,0 +1,5 @@
+class AddAssigneeAgentBotIdToConversations < ActiveRecord::Migration[7.1]
+ def change
+ add_column :conversations, :assignee_agent_bot_id, :bigint
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 8a6e6676c..b69b5f61b 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -668,6 +668,7 @@ ActiveRecord::Schema[7.1].define(version: 2025_11_14_173609) do
t.bigint "sla_policy_id"
t.datetime "waiting_since"
t.text "cached_label_list"
+ t.bigint "assignee_agent_bot_id"
t.index ["account_id", "display_id"], name: "index_conversations_on_account_id_and_display_id", unique: true
t.index ["account_id", "id"], name: "index_conversations_on_id_and_account_id"
t.index ["account_id", "inbox_id", "status", "assignee_id"], name: "conv_acid_inbid_stat_asgnid_idx"
diff --git a/spec/controllers/api/v1/accounts/conversations/assignments_controller_spec.rb b/spec/controllers/api/v1/accounts/conversations/assignments_controller_spec.rb
index 8ed70b7a2..18c652c0a 100644
--- a/spec/controllers/api/v1/accounts/conversations/assignments_controller_spec.rb
+++ b/spec/controllers/api/v1/accounts/conversations/assignments_controller_spec.rb
@@ -15,7 +15,7 @@ RSpec.describe 'Conversation Assignment API', type: :request do
end
context 'when it is an authenticated bot with out access to the inbox' do
- let(:agent_bot) { create(:agent_bot, account: account) }
+ let(:agent_bot) { create(:agent_bot) }
let(:agent) { create(:user, account: account, role: :agent) }
before do
@@ -36,6 +36,7 @@ RSpec.describe 'Conversation Assignment API', type: :request do
context 'when it is an authenticated user with access to the inbox' do
let(:agent) { create(:user, account: account, role: :agent) }
+ let(:agent_bot) { create(:agent_bot, account: account) }
let(:team) { create(:team, account: account) }
before do
@@ -54,6 +55,25 @@ RSpec.describe 'Conversation Assignment API', type: :request do
expect(conversation.reload.assignee).to eq(agent)
end
+ it 'assigns an agent bot to the conversation' do
+ params = { assignee_id: agent_bot.id, assignee_type: 'AgentBot' }
+
+ expect(Conversations::AssignmentService).to receive(:new)
+ .with(hash_including(conversation: conversation, assignee_id: agent_bot.id, assignee_type: 'AgentBot'))
+ .and_call_original
+
+ post api_v1_account_conversation_assignments_url(account_id: account.id, conversation_id: conversation.display_id),
+ params: params,
+ headers: agent.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ expect(response.parsed_body['name']).to eq(agent_bot.name)
+ conversation.reload
+ expect(conversation.assignee_agent_bot).to eq(agent_bot)
+ expect(conversation.assignee).to be_nil
+ end
+
it 'assigns a team to the conversation' do
team_member = create(:user, account: account, role: :agent, auto_offline: false)
create(:inbox_member, inbox: conversation.inbox, user: team_member)
@@ -125,7 +145,7 @@ RSpec.describe 'Conversation Assignment API', type: :request do
end
it 'unassigns the assignee from the conversation' do
- params = { assignee_id: 0 }
+ params = { assignee_id: nil }
post api_v1_account_conversation_assignments_url(account_id: account.id, conversation_id: conversation.display_id),
params: params,
headers: agent.create_new_auth_token,
diff --git a/spec/listeners/agent_bot_listener_spec.rb b/spec/listeners/agent_bot_listener_spec.rb
index 2dc2b41df..56c478a1b 100644
--- a/spec/listeners/agent_bot_listener_spec.rb
+++ b/spec/listeners/agent_bot_listener_spec.rb
@@ -36,6 +36,24 @@ describe AgentBotListener do
expect(AgentBots::WebhookJob).not_to receive(:perform_later)
listener.message_created(event)
end
+
+ context 'when conversation has a different assignee agent bot' do
+ let!(:conversation_bot) { create(:agent_bot) }
+
+ before do
+ create(:agent_bot_inbox, inbox: inbox, agent_bot: agent_bot)
+ conversation.update!(assignee_agent_bot: conversation_bot, assignee: nil)
+ end
+
+ it 'sends message to both bots exactly once' do
+ payload = message.webhook_data.merge(event: 'message_created')
+
+ expect(AgentBots::WebhookJob).to receive(:perform_later).with(agent_bot.outgoing_url, payload).once
+ expect(AgentBots::WebhookJob).to receive(:perform_later).with(conversation_bot.outgoing_url, payload).once
+
+ listener.message_created(event)
+ end
+ end
end
end
diff --git a/spec/models/conversation_spec.rb b/spec/models/conversation_spec.rb
index 51bb43384..7a5398456 100644
--- a/spec/models/conversation_spec.rb
+++ b/spec/models/conversation_spec.rb
@@ -525,8 +525,9 @@ RSpec.describe Conversation do
additional_attributes: {},
meta: {
sender: conversation.contact.push_event_data,
- assignee: conversation.assignee,
- team: conversation.team,
+ assignee: conversation.assigned_entity&.push_event_data,
+ assignee_type: conversation.assignee_type,
+ team: conversation.team&.push_event_data,
hmac_verified: conversation.contact_inbox.hmac_verified
},
id: conversation.display_id,
diff --git a/spec/presenters/conversations/event_data_presenter_spec.rb b/spec/presenters/conversations/event_data_presenter_spec.rb
index a645caf1d..bf0eaf6f6 100644
--- a/spec/presenters/conversations/event_data_presenter_spec.rb
+++ b/spec/presenters/conversations/event_data_presenter_spec.rb
@@ -12,8 +12,9 @@ RSpec.describe Conversations::EventDataPresenter do
additional_attributes: {},
meta: {
sender: conversation.contact.push_event_data,
- assignee: conversation.assignee,
- team: conversation.team,
+ assignee: conversation.assigned_entity&.push_event_data,
+ assignee_type: conversation.assignee_type,
+ team: conversation.team&.push_event_data,
hmac_verified: conversation.contact_inbox.hmac_verified
},
id: conversation.display_id,
diff --git a/spec/requests/api/v1/accounts/base_controller_spec.rb b/spec/requests/api/v1/accounts/base_controller_spec.rb
new file mode 100644
index 000000000..6493bc986
--- /dev/null
+++ b/spec/requests/api/v1/accounts/base_controller_spec.rb
@@ -0,0 +1,63 @@
+require 'rails_helper'
+
+RSpec.describe 'Api::V1::Accounts::BaseController', type: :request do
+ let(:account) { create(:account) }
+ let(:inbox) { create(:inbox, account: account) }
+ let!(:conversation) { create(:conversation, account: account, inbox: inbox) }
+ let(:agent) { create(:user, account: account, role: :agent) }
+
+ before do
+ create(:inbox_member, inbox: inbox, user: agent)
+ end
+
+ context 'when agent bot belongs to the account' do
+ let(:agent_bot) { create(:agent_bot, account: account) }
+
+ it 'allows assignments via API' do
+ post api_v1_account_conversation_assignments_url(account_id: account.id, conversation_id: conversation.display_id),
+ headers: { api_access_token: agent_bot.access_token.token },
+ params: { assignee_id: agent.id },
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ end
+ end
+
+ context 'when agent bot belongs to another account' do
+ let(:other_account) { create(:account) }
+ let(:external_bot) { create(:agent_bot, account: other_account) }
+
+ it 'rejects assignment' do
+ post api_v1_account_conversation_assignments_url(account_id: account.id, conversation_id: conversation.display_id),
+ headers: { api_access_token: external_bot.access_token.token },
+ params: { assignee_id: agent.id },
+ as: :json
+
+ expect(response).to have_http_status(:unauthorized)
+ end
+ end
+
+ context 'when agent bot is global' do
+ let(:global_bot) { create(:agent_bot, account: nil) }
+
+ it 'rejects requests without inbox mapping' do
+ post api_v1_account_conversation_assignments_url(account_id: account.id, conversation_id: conversation.display_id),
+ headers: { api_access_token: global_bot.access_token.token },
+ params: { assignee_id: agent.id },
+ as: :json
+
+ expect(response).to have_http_status(:unauthorized)
+ end
+
+ it 'allows requests when inbox mapping exists' do
+ create(:agent_bot_inbox, agent_bot: global_bot, inbox: inbox)
+
+ post api_v1_account_conversation_assignments_url(account_id: account.id, conversation_id: conversation.display_id),
+ headers: { api_access_token: global_bot.access_token.token },
+ params: { assignee_id: agent.id },
+ as: :json
+
+ expect(response).to have_http_status(:success)
+ end
+ end
+end
diff --git a/spec/services/conversations/assignment_service_spec.rb b/spec/services/conversations/assignment_service_spec.rb
new file mode 100644
index 000000000..899236e1d
--- /dev/null
+++ b/spec/services/conversations/assignment_service_spec.rb
@@ -0,0 +1,60 @@
+require 'rails_helper'
+
+describe Conversations::AssignmentService do
+ let(:account) { create(:account) }
+ let(:agent) { create(:user, account: account) }
+ let(:agent_bot) { create(:agent_bot, account: account) }
+ let(:conversation) { create(:conversation, account: account) }
+
+ describe '#perform' do
+ context 'when assignee_id is blank' do
+ before do
+ conversation.update!(assignee: agent, assignee_agent_bot: agent_bot)
+ end
+
+ it 'clears both human and bot assignees' do
+ described_class.new(conversation: conversation, assignee_id: nil).perform
+
+ conversation.reload
+ expect(conversation.assignee_id).to be_nil
+ expect(conversation.assignee_agent_bot_id).to be_nil
+ end
+ end
+
+ context 'when assigning a user' do
+ before do
+ conversation.update!(assignee_agent_bot: agent_bot, assignee: nil)
+ end
+
+ it 'sets the agent and clears agent bot' do
+ result = described_class.new(conversation: conversation, assignee_id: agent.id).perform
+
+ conversation.reload
+ expect(result).to eq(agent)
+ expect(conversation.assignee_id).to eq(agent.id)
+ expect(conversation.assignee_agent_bot_id).to be_nil
+ end
+ end
+
+ context 'when assigning an agent bot' do
+ let(:service) do
+ described_class.new(
+ conversation: conversation,
+ assignee_id: agent_bot.id,
+ assignee_type: 'AgentBot'
+ )
+ end
+
+ it 'sets the agent bot and clears human assignee' do
+ conversation.update!(assignee: agent, assignee_agent_bot: nil)
+
+ result = service.perform
+
+ conversation.reload
+ expect(result).to eq(agent_bot)
+ expect(conversation.assignee_agent_bot_id).to eq(agent_bot.id)
+ expect(conversation.assignee_id).to be_nil
+ end
+ end
+ end
+end
From e9edfcafbbfbd11556435957e03eb5e6edeeed8f Mon Sep 17 00:00:00 2001
From: Sojan Jose
Date: Tue, 18 Nov 2025 18:39:51 -0800
Subject: [PATCH 80/80] Bump version to 4.8.0
---
config/app.yml | 2 +-
package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/config/app.yml b/config/app.yml
index e3d9c2c69..a9f671005 100644
--- a/config/app.yml
+++ b/config/app.yml
@@ -1,5 +1,5 @@
shared: &shared
- version: '4.7.0'
+ version: '4.8.0'
development:
<<: *shared
diff --git a/package.json b/package.json
index 4660b44fa..82e116628 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@chatwoot/chatwoot",
- "version": "4.7.0",
+ "version": "4.8.0",
"license": "MIT",
"scripts": {
"eslint": "eslint app/**/*.{js,vue}",
|