+
+
From 17500cc62d3fdf23c5ff1c8c238e866289de7dab Mon Sep 17 00:00:00 2001
From: Muhsin Keloth
Date: Thu, 10 Jul 2025 11:36:37 +0530
Subject: [PATCH 03/20] chore: Auto assign PR to author when PR opened (#11890)
- gh action to auto-assign PR to author when PR opened
---
.github/workflows/auto-assign-pr.yml | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 .github/workflows/auto-assign-pr.yml
diff --git a/.github/workflows/auto-assign-pr.yml b/.github/workflows/auto-assign-pr.yml
new file mode 100644
index 000000000..98df89707
--- /dev/null
+++ b/.github/workflows/auto-assign-pr.yml
@@ -0,0 +1,28 @@
+name: Auto-assign PR to Author
+
+on:
+ pull_request:
+ types: [opened]
+
+jobs:
+ auto-assign:
+ runs-on: ubuntu-latest
+ permissions:
+ pull-requests: write
+ steps:
+ - name: Auto-assign PR to author
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const { owner, repo } = context.repo;
+ const pull_number = context.payload.pull_request.number;
+ const author = context.payload.pull_request.user.login;
+
+ await github.rest.issues.addAssignees({
+ owner,
+ repo,
+ issue_number: pull_number,
+ assignees: [author]
+ });
+
+ console.log(`Assigned PR #${pull_number} to ${author}`);
\ No newline at end of file
From 802f0694ed9971d5ab441bd06b82638e403cc1bb Mon Sep 17 00:00:00 2001
From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Date: Fri, 11 Jul 2025 11:46:15 +0530
Subject: [PATCH 04/20] chore: Alphabetically sort inbox list on settings page
(#11921)
# Pull Request Template
## Description
This PR updates the inbox list on the settings page to be sorted
alphabetically.
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## 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
- [ ] 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/inbox/Index.vue | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/Index.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/Index.vue
index aae2263a7..c4cf5f5ad 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/inbox/Index.vue
+++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/Index.vue
@@ -1,12 +1,16 @@
@@ -24,22 +24,25 @@ const onClick = event => {
diff --git a/app/javascript/dashboard/components-next/captain/SettingsPageLayout.vue b/app/javascript/dashboard/components-next/captain/SettingsPageLayout.vue
new file mode 100644
index 000000000..4a48794b3
--- /dev/null
+++ b/app/javascript/dashboard/components-next/captain/SettingsPageLayout.vue
@@ -0,0 +1,91 @@
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/featureFlags.js b/app/javascript/dashboard/featureFlags.js
index 1a6ada9fa..98234539b 100644
--- a/app/javascript/dashboard/featureFlags.js
+++ b/app/javascript/dashboard/featureFlags.js
@@ -36,6 +36,7 @@ export const FEATURE_FLAGS = {
REPORT_V4: 'report_v4',
CHANNEL_INSTAGRAM: 'channel_instagram',
CONTACT_CHATWOOT_SUPPORT_TEAM: 'contact_chatwoot_support_team',
+ CAPTAIN_V2: 'captain_integration_v2',
};
export const PREMIUM_FEATURES = [
@@ -44,4 +45,5 @@ export const PREMIUM_FEATURES = [
FEATURE_FLAGS.CUSTOM_ROLES,
FEATURE_FLAGS.AUDIT_LOGS,
FEATURE_FLAGS.HELP_CENTER,
+ FEATURE_FLAGS.CAPTAIN_V2,
];
diff --git a/app/javascript/dashboard/i18n/locale/en/integrations.json b/app/javascript/dashboard/i18n/locale/en/integrations.json
index b3e091722..fc8cff644 100644
--- a/app/javascript/dashboard/i18n/locale/en/integrations.json
+++ b/app/javascript/dashboard/i18n/locale/en/integrations.json
@@ -478,6 +478,37 @@
"ERROR_MESSAGE": "There was an error updating the assistant, please try again.",
"NOT_FOUND": "Could not find the assistant. Please try again."
},
+ "SETTINGS": {
+ "BREADCRUMB": {
+ "ASSISTANT": "Assistant"
+ },
+ "BASIC_SETTINGS": {
+ "TITLE": "Basic settings",
+ "DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
+ },
+ "SYSTEM_SETTINGS": {
+ "TITLE": "System settings",
+ "DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
+ },
+ "CONTROL_ITEMS": {
+ "TITLE": "The Fun Stuff",
+ "DESCRIPTION": "Add more control to the assistant. (a bit more visual like a story : Query guardrail → scenarios → output) Nudges user to actually utilise these.",
+ "OPTIONS": {
+ "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."
+ },
+ "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?"
+ }
+ }
+ }
+ },
"OPTIONS": {
"EDIT_ASSISTANT": "Edit Assistant",
"DELETE_ASSISTANT": "Delete Assistant",
diff --git a/app/javascript/dashboard/routes/dashboard/captain/assistants/Edit.vue b/app/javascript/dashboard/routes/dashboard/captain/assistants/Edit.vue
index 8b64e2663..2b2506934 100644
--- a/app/javascript/dashboard/routes/dashboard/captain/assistants/Edit.vue
+++ b/app/javascript/dashboard/routes/dashboard/captain/assistants/Edit.vue
@@ -5,10 +5,13 @@ import { useStore } from 'dashboard/composables/store';
import { useMapGetter } from 'dashboard/composables/store';
import { useAlert } from 'dashboard/composables';
import { useI18n } from 'vue-i18n';
+import { FEATURE_FLAGS } from 'dashboard/featureFlags';
import PageLayout from 'dashboard/components-next/captain/PageLayout.vue';
import EditAssistantForm from '../../../../components-next/captain/pageComponents/assistant/EditAssistantForm.vue';
import AssistantPlayground from 'dashboard/components-next/captain/assistant/AssistantPlayground.vue';
+import AssistantSettings from 'dashboard/routes/dashboard/captain/assistants/settings/Settings.vue';
+
const route = useRoute();
const store = useStore();
const { t } = useI18n();
@@ -19,6 +22,16 @@ const assistant = computed(() =>
store.getters['captainAssistants/getRecord'](Number(assistantId))
);
+const isFeatureEnabledonAccount = useMapGetter(
+ 'accounts/isFeatureEnabledonAccount'
+);
+const currentAccountId = useMapGetter('getCurrentAccountId');
+
+const isCaptainV2Enabled = isFeatureEnabledonAccount.value(
+ currentAccountId.value,
+ FEATURE_FLAGS.CAPTAIN_V2
+);
+
const isAssistantAvailable = computed(() => !!assistant.value?.id);
const handleSubmit = async updatedAssistant => {
@@ -36,14 +49,16 @@ const handleSubmit = async updatedAssistant => {
};
onMounted(() => {
- if (!isAssistantAvailable.value) {
+ if (!isAssistantAvailable.value || !isCaptainV2Enabled) {
store.dispatch('captainAssistants/show', assistantId);
}
});
+
+import { computed, onMounted } from 'vue';
+import { useRoute } from 'vue-router';
+import { useI18n } from 'vue-i18n';
+import { useAlert } from 'dashboard/composables';
+import { useStore } from 'dashboard/composables/store';
+import { useMapGetter } from 'dashboard/composables/store';
+import SettingsPageLayout from 'dashboard/components-next/captain/SettingsPageLayout.vue';
+import SettingsHeader from 'dashboard/components-next/captain/pageComponents/settings/SettingsHeader.vue';
+import AssistantBasicSettingsForm from 'dashboard/components-next/captain/pageComponents/assistant/settings/AssistantBasicSettingsForm.vue';
+import AssistantSystemSettingsForm from 'dashboard/components-next/captain/pageComponents/assistant/settings/AssistantSystemSettingsForm.vue';
+import AssistantControlItems from 'dashboard/components-next/captain/pageComponents/assistant/settings/AssistantControlItems.vue';
+
+const { t } = useI18n();
+const route = useRoute();
+const store = useStore();
+const assistantId = route.params.assistantId;
+const uiFlags = useMapGetter('captainAssistants/getUIFlags');
+const isFetching = computed(() => uiFlags.value.fetchingItem);
+const assistant = computed(() =>
+ store.getters['captainAssistants/getRecord'](Number(assistantId))
+);
+
+const isAssistantAvailable = computed(() => !!assistant.value?.id);
+
+const controlItems = computed(() => {
+ return [
+ {
+ name: t(
+ 'CAPTAIN.ASSISTANTS.SETTINGS.CONTROL_ITEMS.OPTIONS.GUARDRAILS.TITLE'
+ ),
+ description: t(
+ 'CAPTAIN.ASSISTANTS.SETTINGS.CONTROL_ITEMS.OPTIONS.GUARDRAILS.DESCRIPTION'
+ ),
+ // routeName: 'captain_assistants_guardrails_index',
+ },
+ {
+ name: t(
+ 'CAPTAIN.ASSISTANTS.SETTINGS.CONTROL_ITEMS.OPTIONS.SCENARIOS.TITLE'
+ ),
+ description: t(
+ 'CAPTAIN.ASSISTANTS.SETTINGS.CONTROL_ITEMS.OPTIONS.SCENARIOS.DESCRIPTION'
+ ),
+ // routeName: 'captain_assistants_scenarios_index',
+ },
+ {
+ name: t(
+ 'CAPTAIN.ASSISTANTS.SETTINGS.CONTROL_ITEMS.OPTIONS.RESPONSE_GUIDELINES.TITLE'
+ ),
+ description: t(
+ 'CAPTAIN.ASSISTANTS.SETTINGS.CONTROL_ITEMS.OPTIONS.RESPONSE_GUIDELINES.DESCRIPTION'
+ ),
+ // routeName: 'captain_assistants_guidelines_index',
+ },
+ ];
+});
+
+const breadcrumbItems = computed(() => {
+ const activeControlItem = controlItems.value?.find(
+ item => item.routeName === route.name
+ );
+
+ return [
+ {
+ label: t('CAPTAIN.ASSISTANTS.SETTINGS.BREADCRUMB.ASSISTANT'),
+ routeName: 'captain_assistants_index',
+ },
+ { label: assistant.value?.name, routeName: 'captain_assistants_edit' },
+ ...(activeControlItem
+ ? [
+ {
+ label: activeControlItem.name,
+ routeName: activeControlItem.routeName,
+ },
+ ]
+ : []),
+ ];
+});
+
+const handleSubmit = async updatedAssistant => {
+ try {
+ await store.dispatch('captainAssistants/update', {
+ id: assistantId,
+ ...updatedAssistant,
+ });
+ useAlert(t('CAPTAIN.ASSISTANTS.EDIT.SUCCESS_MESSAGE'));
+ } catch (error) {
+ const errorMessage =
+ error?.message || t('CAPTAIN.ASSISTANTS.EDIT.ERROR_MESSAGE');
+ useAlert(errorMessage);
+ }
+};
+
+onMounted(() => {
+ if (!isAssistantAvailable.value) {
+ store.dispatch('captainAssistants/show', assistantId);
+ }
+});
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/captain/captain.routes.js b/app/javascript/dashboard/routes/dashboard/captain/captain.routes.js
index 17afeca14..7294a7433 100644
--- a/app/javascript/dashboard/routes/dashboard/captain/captain.routes.js
+++ b/app/javascript/dashboard/routes/dashboard/captain/captain.routes.js
@@ -3,6 +3,7 @@ import { INSTALLATION_TYPES } from 'dashboard/constants/installationTypes';
import { frontendURL } from '../../../helper/URLHelper';
import AssistantIndex from './assistants/Index.vue';
import AssistantEdit from './assistants/Edit.vue';
+// import AssistantSettings from './assistants/settings/Settings.vue';
import AssistantInboxesIndex from './assistants/inboxes/Index.vue';
import DocumentsIndex from './documents/Index.vue';
import ResponsesIndex from './responses/Index.vue';
diff --git a/config/features.yml b/config/features.yml
index 5171b1c01..d41f705ad 100644
--- a/config/features.yml
+++ b/config/features.yml
@@ -176,3 +176,7 @@
- name: notion_integration
display_name: Notion Integration
enabled: false
+- name: captain_integration_v2
+ display_name: Captain V2
+ enabled: false
+ premium: true
From 661326ae51ed7cd21d87e4aec5be19f327d3cdc6 Mon Sep 17 00:00:00 2001
From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Date: Mon, 14 Jul 2025 10:27:50 +0530
Subject: [PATCH 08/20] fix: Contact name editing did not allow spaces (#11931)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
# Pull Request Template
## Description
This PR fixes an issue where editing a contact name from the “Contacts”
tab would not allow spaces in the First or Last Name fields — the space
would disappear immediately after typing.
This issue did not occur in the sidebar editor or when adding a new
contact.
**Cause:** The form had a deep watcher on `contactData`, which triggered
`prepareStateBasedOnProps()` on every nested change. This caused the
form state to reset.
**Solution:** Replaced the deep watcher with a shallow watcher that only
watches `contactData.id`.
This fires once on mount and whenever a new contact is selected,
avoiding unnecessary re-hydration while the user is typing.
Fixes https://github.com/chatwoot/chatwoot/issues/11922 ,
CW-[4623](https://linear.app/chatwoot/issue/CW-4623/inconsistent-name-field-validation-when-editing-contacts-from-contacts)
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
### Screencast
https://github.com/user-attachments/assets/e088f627-d7b1-4d67-85eb-58911ac0c012
## 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
---
.../Contacts/ContactsForm/ContactsForm.vue | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/app/javascript/dashboard/components-next/Contacts/ContactsForm/ContactsForm.vue b/app/javascript/dashboard/components-next/Contacts/ContactsForm/ContactsForm.vue
index cd8c767b8..e77a0c10d 100644
--- a/app/javascript/dashboard/components-next/Contacts/ContactsForm/ContactsForm.vue
+++ b/app/javascript/dashboard/components-next/Contacts/ContactsForm/ContactsForm.vue
@@ -218,10 +218,13 @@ const resetForm = () => {
Object.assign(state, defaultState);
};
-watch(() => props.contactData, prepareStateBasedOnProps, {
- immediate: true,
- deep: true,
-});
+watch(
+ () => props.contactData?.id,
+ id => {
+ if (id) prepareStateBasedOnProps();
+ },
+ { immediate: true }
+);
// Expose state to parent component for avatar upload
defineExpose({
From 07dd6448f47580332ac7f6cb803ea470b2ee8e76 Mon Sep 17 00:00:00 2001
From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
Date: Mon, 14 Jul 2025 11:02:51 +0530
Subject: [PATCH 09/20] fix: fast scrolling in canned responses list on mouse
hover (#11933)
# Pull Request Template
## Description
This PR fixes a fast scrolling issue in the canned responses list that
occurred when hovering near the top or bottom edge.
Fixes https://github.com/chatwoot/chatwoot/issues/11923,
[CW-4624](https://linear.app/chatwoot/issue/CW-4624/canned-responses-menu-scrolls-too-fast-when-mouse-near-top-or-bottom)
## Type of change
- [x] Bug fix (non-breaking change which fixes an issue)
## How Has This Been Tested?
### Screencast
**Before**
https://github.com/user-attachments/assets/1c39ad33-c5c9-49ce-a252-542428b7f7e3
**After**
https://github.com/user-attachments/assets/19c73713-0ffe-461a-9c3d-486e53e21abf
## 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
---
.../widgets/mentions/MentionBox.vue | 23 ++++++++-----------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/app/javascript/dashboard/components/widgets/mentions/MentionBox.vue b/app/javascript/dashboard/components/widgets/mentions/MentionBox.vue
index 894ab3045..999ec758d 100644
--- a/app/javascript/dashboard/components/widgets/mentions/MentionBox.vue
+++ b/app/javascript/dashboard/components/widgets/mentions/MentionBox.vue
@@ -1,5 +1,5 @@