Merge branch 'develop' of github.com:chatwoot/chatwoot into feat/rollup-refactor

This commit is contained in:
Shivam Mishra
2026-03-13 10:45:19 +05:30
125 changed files with 6100 additions and 1684 deletions
@@ -18,10 +18,18 @@ const newMessage = ref('');
const isLoading = ref(false);
const formatMessagesForApi = () => {
return messages.value.map(message => ({
role: message.sender,
content: message.content,
}));
return messages.value.map(message => {
const payload = {
role: message.sender,
content: message.content,
};
if (message.sender === 'assistant' && message.agentName) {
payload.agent_name = message.agentName;
}
return payload;
});
};
const resetConversation = () => {
@@ -62,6 +70,7 @@ const sendMessage = async () => {
messages.value.push({
content: data.response,
sender: 'assistant',
agentName: data.agent_name,
timestamp: new Date().toISOString(),
});
} catch (error) {
@@ -71,6 +80,12 @@ const sendMessage = async () => {
isLoading.value = false;
}
};
const handleEnterKey = event => {
if (event.isComposing) return;
event.preventDefault();
sendMessage();
};
</script>
<template>
@@ -104,7 +119,7 @@ const sendMessage = async () => {
v-model="newMessage"
class="flex-1 bg-transparent border-none focus:outline-none text-sm mb-0 text-n-slate-12 placeholder:text-n-slate-10"
:placeholder="t('CAPTAIN.PLAYGROUND.MESSAGE_PLACEHOLDER')"
@keyup.enter="sendMessage"
@keydown.enter.exact="handleEnterKey"
/>
<NextButton
ghost
@@ -29,6 +29,12 @@ const handleInput = () => {
nextTick(adjustHeight);
};
const handleEnterKey = event => {
if (event.isComposing) return;
event.preventDefault();
sendMessage();
};
onMounted(() => {
nextTick(adjustHeight);
});
@@ -43,7 +49,7 @@ onMounted(() => {
class="w-full reset-base bg-n-alpha-3 ltr:pl-4 ltr:pr-12 rtl:pl-12 rtl:pr-4 py-3 text-sm border border-n-weak rounded-lg focus:outline-0 focus:outline-none focus:ring-2 focus:ring-n-blue-11 focus:border-n-blue-11 resize-none overflow-hidden max-h-[200px] mb-0 text-n-slate-12"
rows="1"
@input="handleInput"
@keydown.enter.exact.prevent="sendMessage"
@keydown.enter.exact="handleEnterKey"
/>
<button
class="absolute ltr:right-1 rtl:left-1 top-1/2 -translate-y-1/2 h-9 w-10 flex items-center justify-center text-n-slate-11 hover:text-n-blue-11"
@@ -107,7 +107,8 @@ function onKeydown(view, event) {
emit('keydown');
// Handle Enter key to send message (Shift+Enter for new line)
if (event.key === 'Enter' && !event.shiftKey) {
// Skip if IME composition is active (CJK character confirmation)
if (event.key === 'Enter' && !event.shiftKey && !event.isComposing) {
event.preventDefault();
handleSubmit();
return true; // Prevent ProseMirror's default Enter handling
@@ -78,7 +78,7 @@ const onSend = () => {
<div
v-else-if="isGeneratingContent"
key="loading-state"
class="bg-n-iris-5 rounded min-h-16 w-full mb-4 p-4 flex items-start"
class="bg-n-iris-5 rounded min-h-[4.75rem] w-full mb-4 p-4 flex items-start"
>
<div class="flex items-center gap-2">
<CaptainLoader class="text-n-iris-10 size-4" />
@@ -162,7 +162,8 @@ export default {
this.inReplyTo?.id &&
!this.isPrivate &&
this.inboxHasFeature(INBOX_FEATURES.REPLY_TO) &&
!this.is360DialogWhatsAppChannel
!this.is360DialogWhatsAppChannel &&
!this.copilot.isActive.value
);
},
showWhatsappTemplates() {
@@ -1464,7 +1465,7 @@ export default {
}
.reply-box__top {
@apply relative py-0 px-4 -mt-px;
@apply relative py-0 px-3 -mt-px;
}
.emoji-dialog {
@@ -14,7 +14,7 @@ const emit = defineEmits(['dismiss']);
<template>
<div
class="reply-editor bg-n-slate-9/10 rounded-md py-1 pl-2 pr-1 text-xs tracking-wide mt-2 flex items-center gap-1.5 -mx-2"
class="reply-editor bg-n-slate-9/10 rounded-md py-1 pl-2 pr-1 text-xs tracking-wide mt-2 flex items-center gap-1.5"
>
<fluent-icon class="flex-shrink-0 icon" icon="arrow-reply" size="14" />
<div class="flex-grow gap-1 mt-px text-xs truncate">
@@ -38,7 +38,7 @@ describe('useAutomation', () => {
});
useMapGetter.mockImplementation(getter => {
const getterMap = {
'agents/getAgents': agents,
'agents/getVerifiedAgents': agents,
'campaigns/getAllCampaigns': campaigns,
'contacts/getContacts': contacts,
'inboxes/getInboxes': inboxes,
@@ -111,7 +111,7 @@ describe('useMacros', () => {
useStoreGetters.mockReturnValue({
'labels/getLabels': { value: mockLabels },
'teams/getTeams': { value: mockTeams },
'agents/getAgents': { value: mockAgents },
'agents/getVerifiedAgents': { value: mockAgents },
});
});
@@ -167,7 +167,7 @@ describe('useMacros', () => {
useStoreGetters.mockReturnValue({
'labels/getLabels': { value: [] },
'teams/getTeams': { value: [] },
'agents/getAgents': { value: [] },
'agents/getVerifiedAgents': { value: [] },
});
const { getMacroDropdownValues } = useMacros();
@@ -20,7 +20,7 @@ import {
export default function useAutomationValues() {
const getters = useStoreGetters();
const { t } = useI18n();
const agents = useMapGetter('agents/getAgents');
const agents = useMapGetter('agents/getVerifiedAgents');
const campaigns = useMapGetter('campaigns/getAllCampaigns');
const contacts = useMapGetter('contacts/getContacts');
const inboxes = useMapGetter('inboxes/getInboxes');
@@ -13,7 +13,7 @@ export const useMacros = () => {
const labels = computed(() => getters['labels/getLabels'].value);
const teams = computed(() => getters['teams/getTeams'].value);
const agents = computed(() => getters['agents/getAgents'].value);
const agents = computed(() => getters['agents/getVerifiedAgents'].value);
/**
* Get dropdown values based on the specified type
@@ -191,7 +191,7 @@ onMounted(() => {
<template>
<PageLayout
:header-title="$t('CAPTAIN.DOCUMENTS.HEADER')"
:header-title="$t('CAPTAIN.ASSISTANTS.SCENARIOS.TITLE')"
:is-fetching="isFetching"
:show-know-more="false"
:show-pagination-footer="false"