{
## 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
---
app/services/whatsapp/channel_creation_service.rb | 3 +--
config/locales/en.yml | 1 +
.../whatsapp/channel_creation_service_spec.rb | 13 +++++++++----
3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/app/services/whatsapp/channel_creation_service.rb b/app/services/whatsapp/channel_creation_service.rb
index 154f55520..74882c7e5 100644
--- a/app/services/whatsapp/channel_creation_service.rb
+++ b/app/services/whatsapp/channel_creation_service.rb
@@ -10,7 +10,7 @@ class Whatsapp::ChannelCreationService
validate_parameters!
existing_channel = find_existing_channel
- raise "Channel already exists: #{existing_channel.phone_number}" if existing_channel
+ raise I18n.t('errors.whatsapp.phone_number_already_exists', phone_number: existing_channel.phone_number) if existing_channel
create_channel_with_inbox
end
@@ -26,7 +26,6 @@ class Whatsapp::ChannelCreationService
def find_existing_channel
Channel::Whatsapp.find_by(
- account: @account,
phone_number: @phone_info[:phone_number]
)
end
diff --git a/config/locales/en.yml b/config/locales/en.yml
index ad54b8dfa..d0f256146 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -90,6 +90,7 @@ en:
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/spec/services/whatsapp/channel_creation_service_spec.rb b/spec/services/whatsapp/channel_creation_service_spec.rb
index 403fb71b8..983af6c78 100644
--- a/spec/services/whatsapp/channel_creation_service_spec.rb
+++ b/spec/services/whatsapp/channel_creation_service_spec.rb
@@ -62,14 +62,19 @@ describe Whatsapp::ChannelCreationService do
end
end
- context 'when channel already exists' do
+ context 'when channel already exists for the phone number' do
+ let(:different_account) { create(:account) }
+
before do
- create(:channel_whatsapp, account: account, phone_number: '+1234567890',
+ create(:channel_whatsapp, account: different_account, phone_number: '+1234567890',
provider: 'whatsapp_cloud', sync_templates: false, validate_provider_config: false)
end
- it 'raises an error' do
- expect { service.perform }.to raise_error(/Channel already exists/)
+ it 'raises an error even if the channel belongs to a different account' do
+ expect { service.perform }.to raise_error(
+ RuntimeError,
+ I18n.t('errors.whatsapp.phone_number_already_exists', phone_number: '+1234567890')
+ )
end
end
From 5bf39d20e5709ff264b0ea900a21832d313bd035 Mon Sep 17 00:00:00 2001
From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Date: Fri, 7 Nov 2025 06:01:23 +0530
Subject: [PATCH 3/4] feat: Update Captain navigation structure (#12761)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
# Pull Request Template
## Description
This PR includes an update to the Captain navigation structure.
## Route Structure
```javascript
1. captain_assistants_responses_index → /captain/:assistantId/faqs
2. captain_assistants_documents_index → /captain/:assistantId/documents
3. captain_assistants_scenarios_index → /captain/:assistantId/scenarios
4. captain_assistants_playground_index → /captain/:assistantId/playground
5. captain_assistants_inboxes_index → /captain/:assistantId/inboxes
6. captain_tools_index → /captain/tools
7. captain_assistants_settings_index → /captain/:assistantId/settings
8. captain_assistants_guardrails_index → /captain/:assistantId/settings/guardrails
9. captain_assistants_guidelines_index → /captain/:assistantId/settings/guidelines
10. captain_assistants_index → /captain/:navigationPath
```
**How it works:**
1. User clicks sidebar item → Routes to `captain_assistants_index` with
`navigationPath`
2. `AssistantsIndexPage` validates route and gets last active assistant,
if not redirects to assistant create page.
3. Routes to actual page: `/captain/:assistantId/:page`
4. Page loads with correct assistant context
Fixes
https://linear.app/chatwoot/issue/CW-5832/updating-captain-navigation
## Type of change
- [x] New feature (non-breaking change which adds functionality)
## How Has This Been Tested?
## 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
---------
Co-authored-by: Pranav
Co-authored-by: Sojan Jose
---
.../components-next/captain/PageLayout.vue | 115 +++++-
.../captain/SettingsPageLayout.vue | 91 -----
.../captain/assistant/AssistantCard.vue | 7 +-
.../captain/assistant/AssistantPlayground.vue | 16 +-
.../pageComponents/AssistantSelector.vue | 68 ----
.../assistant/CreateAssistantDialog.vue | 16 +-
.../assistant/EditAssistantForm.vue | 333 ------------------
.../settings/AssistantSystemSettingsForm.vue | 37 +-
.../document/CreateDocumentDialog.vue | 13 +-
.../pageComponents/document/DocumentForm.vue | 37 +-
.../response/CreateResponseDialog.vue | 12 +-
.../pageComponents/response/ResponseForm.vue | 34 +-
.../switcher/AssistantSwitcher.vue | 143 ++++++++
.../copilot/CopilotEmptyState.vue | 6 +-
.../components-next/sidebar/Sidebar.vue | 60 +++-
.../components-next/sidebar/provider.js | 39 +-
.../i18n/locale/en/integrations.json | 38 +-
.../dashboard/i18n/locale/en/settings.json | 4 +
.../dashboard/captain/assistants/Edit.vue | 86 -----
.../dashboard/captain/assistants/Index.vue | 93 +----
.../captain/assistants/guardrails/Index.vue | 37 +-
.../captain/assistants/guidelines/Index.vue | 37 +-
.../captain/assistants/inboxes/Index.vue | 30 +-
.../captain/assistants/playground/Index.vue | 24 ++
.../captain/assistants/scenarios/Index.vue | 38 +-
.../captain/assistants/settings/Settings.vue | 219 +++++++-----
.../dashboard/captain/captain.routes.js | 198 +++++------
.../dashboard/captain/documents/Index.vue | 36 +-
.../captain/pages/AssistantsIndexPage.vue | 89 +++++
.../captain/pages/CaptainPageRouteView.vue | 30 ++
.../dashboard/captain/responses/Index.vue | 160 +++------
.../dashboard/captain/responses/Pending.vue | 197 ++++-------
.../routes/dashboard/captain/tools/Index.vue | 1 +
.../store/captain/storeFactory.spec.js | 2 +-
.../store/captain/storeFactoryHelper.js | 2 +-
35 files changed, 991 insertions(+), 1357 deletions(-)
delete mode 100644 app/javascript/dashboard/components-next/captain/SettingsPageLayout.vue
delete mode 100644 app/javascript/dashboard/components-next/captain/pageComponents/AssistantSelector.vue
delete mode 100644 app/javascript/dashboard/components-next/captain/pageComponents/assistant/EditAssistantForm.vue
create mode 100644 app/javascript/dashboard/components-next/captain/pageComponents/switcher/AssistantSwitcher.vue
delete mode 100644 app/javascript/dashboard/routes/dashboard/captain/assistants/Edit.vue
create mode 100644 app/javascript/dashboard/routes/dashboard/captain/assistants/playground/Index.vue
create mode 100644 app/javascript/dashboard/routes/dashboard/captain/pages/AssistantsIndexPage.vue
create mode 100644 app/javascript/dashboard/routes/dashboard/captain/pages/CaptainPageRouteView.vue
diff --git a/app/javascript/dashboard/components-next/captain/PageLayout.vue b/app/javascript/dashboard/components-next/captain/PageLayout.vue
index c394f1b6b..4b6760f98 100644
--- a/app/javascript/dashboard/components-next/captain/PageLayout.vue
+++ b/app/javascript/dashboard/components-next/captain/PageLayout.vue
@@ -1,11 +1,17 @@
@@ -82,9 +118,48 @@ const handlePageChange = event => {
class="flex items-start lg:items-center justify-between w-full py-6 lg:py-0 lg:h-20 gap-4 lg:gap-2 flex-col lg:flex-row"
>