From 2891a72cb9cb43129e3ae8a197412f6184c030d4 Mon Sep 17 00:00:00 2001
From: Tanmay Deep Sharma <32020192+tds-1@users.noreply.github.com>
Date: Thu, 16 Jul 2026 16:18:58 +0530
Subject: [PATCH 01/39] feat(whatsapp): enable reconfigure for embedded signup
inboxes (#15038)
---
.../whatsapp/authorizations_controller.rb | 9 ++-
app/javascript/dashboard/featureFlags.js | 1 +
.../inbox/settingsPage/ConfigurationPage.vue | 60 ++++++++++++++++++-
.../whatsapp/embedded_signup_service.rb | 2 +-
.../whatsapp/reauthorization_service.rb | 6 +-
config/features.yml | 4 ++
.../authorizations_controller_spec.rb | 19 ++----
spec/models/account_spec.rb | 2 +-
.../whatsapp/embedded_signup_service_spec.rb | 4 +-
9 files changed, 82 insertions(+), 25 deletions(-)
diff --git a/app/controllers/api/v1/accounts/whatsapp/authorizations_controller.rb b/app/controllers/api/v1/accounts/whatsapp/authorizations_controller.rb
index db94113d9..580ae77c6 100644
--- a/app/controllers/api/v1/accounts/whatsapp/authorizations_controller.rb
+++ b/app/controllers/api/v1/accounts/whatsapp/authorizations_controller.rb
@@ -1,4 +1,6 @@
class Api::V1::Accounts::Whatsapp::AuthorizationsController < Api::V1::Accounts::BaseController
+ # Reconfiguring/reauthorizing a live inbox swaps its credentials, so restrict it to admins.
+ before_action :check_admin_authorization?, if: -> { params[:inbox_id].present? }
before_action :fetch_and_validate_inbox, if: -> { params[:inbox_id].present? }
# POST /api/v1/accounts/:account_id/whatsapp/authorization
@@ -31,7 +33,7 @@ class Api::V1::Accounts::Whatsapp::AuthorizationsController < Api::V1::Accounts:
end
def validate_reauthorization_required
- return if @inbox.channel.reauthorization_required? || can_upgrade_to_embedded_signup?
+ return if @inbox.channel.reauthorization_required? || can_reconfigure_channel?
render json: {
success: false,
@@ -39,10 +41,13 @@ class Api::V1::Accounts::Whatsapp::AuthorizationsController < Api::V1::Accounts:
}, status: :unprocessable_entity
end
- def can_upgrade_to_embedded_signup?
+ def can_reconfigure_channel?
channel = @inbox.channel
return false unless channel.provider == 'whatsapp_cloud'
+ # Reconfiguring a live embedded-signup channel requires the feature flag.
+ return Current.account.feature_enabled?('whatsapp_reconfigure') if channel.provider_config['source'] == 'embedded_signup'
+
true
end
diff --git a/app/javascript/dashboard/featureFlags.js b/app/javascript/dashboard/featureFlags.js
index e3c57e99d..eb8e1b7bd 100644
--- a/app/javascript/dashboard/featureFlags.js
+++ b/app/javascript/dashboard/featureFlags.js
@@ -8,6 +8,7 @@ export const FEATURE_FLAGS = {
CAMPAIGNS: 'campaigns',
WHATSAPP_CAMPAIGNS: 'whatsapp_campaign',
WHATSAPP_MANUAL_TRANSFER: 'whatsapp_manual_transfer',
+ WHATSAPP_RECONFIGURE: 'whatsapp_reconfigure',
CANNED_RESPONSES: 'canned_responses',
CRM: 'crm',
CUSTOM_ATTRIBUTES: 'custom_attributes',
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 e1ecdbd3f..61038cec1 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/ConfigurationPage.vue
+++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/ConfigurationPage.vue
@@ -1,5 +1,9 @@
+
+
+
+
diff --git a/app/javascript/dashboard/components-next/combobox/ComboBoxDropdown.vue b/app/javascript/dashboard/components-next/combobox/ComboBoxDropdown.vue
index 1ab9e9503..2737cb353 100644
--- a/app/javascript/dashboard/components-next/combobox/ComboBoxDropdown.vue
+++ b/app/javascript/dashboard/components-next/combobox/ComboBoxDropdown.vue
@@ -1,6 +1,8 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ row.label }}
+
+
+ {{ row.subtitle }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/components-next/combobox/specs/ReorderableMultiSelect.spec.js b/app/javascript/dashboard/components-next/combobox/specs/ReorderableMultiSelect.spec.js
new file mode 100644
index 000000000..b07868863
--- /dev/null
+++ b/app/javascript/dashboard/components-next/combobox/specs/ReorderableMultiSelect.spec.js
@@ -0,0 +1,224 @@
+import { mount } from '@vue/test-utils';
+import { h } from 'vue';
+import ReorderableMultiSelect from '../ReorderableMultiSelect.vue';
+
+const OPTIONS = [
+ { value: 1, label: 'Getting started', subtitle: 'Guides' },
+ { value: 2, label: 'Billing', subtitle: 'Payments' },
+ { value: 3, label: 'Security' },
+ { value: 4, label: 'API', icon: '🔌', iconColor: '#000' },
+];
+
+// A findable dropdown stub that exposes the `focus()` the component calls on open.
+const ComboBoxDropdownStub = {
+ name: 'ComboBoxDropdown',
+ props: [
+ 'open',
+ 'options',
+ 'searchValue',
+ 'searchPlaceholder',
+ 'emptyState',
+ 'loading',
+ ],
+ emits: ['select', 'update:searchValue'],
+ methods: { focus() {} },
+ template: '
',
+};
+
+// Renders a real