mirror of
https://github.com/lingble/chatwoot.git
synced 2025-11-01 03:27:52 +00:00
feat: Insert captain response to reply editor (#10581)
This commit is contained in:
@@ -18,6 +18,10 @@ const props = defineProps({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
conversationInboxType: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['sendMessage']);
|
const emit = defineEmits(['sendMessage']);
|
||||||
@@ -47,7 +51,7 @@ watch(
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col ]mx-auto h-full text-sm leading-6 tracking-tight">
|
<div class="flex flex-col ]mx-auto h-full text-sm leading-6 tracking-tight">
|
||||||
<div ref="chatContainer" class="flex-1 overflow-y-auto py-4 space-y-6 px-4">
|
<div ref="chatContainer" class="flex-1 px-4 py-4 space-y-6 overflow-y-auto">
|
||||||
<template v-for="message in messages" :key="message.id">
|
<template v-for="message in messages" :key="message.id">
|
||||||
<CopilotAgentMessage
|
<CopilotAgentMessage
|
||||||
v-if="message.role === 'user'"
|
v-if="message.role === 'user'"
|
||||||
@@ -57,12 +61,13 @@ watch(
|
|||||||
<CopilotAssistantMessage
|
<CopilotAssistantMessage
|
||||||
v-else-if="COPILOT_USER_ROLES.includes(message.role)"
|
v-else-if="COPILOT_USER_ROLES.includes(message.role)"
|
||||||
:message="message"
|
:message="message"
|
||||||
|
:conversation-inbox-type="conversationInboxType"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<CopilotLoader v-if="isCaptainTyping" />
|
<CopilotLoader v-if="isCaptainTyping" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CopilotInput class="mx-3 mb-4 mt-px" @send="sendMessage" />
|
<CopilotInput class="mx-3 mt-px mb-4" @send="sendMessage" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,12 +1,36 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
|
import { computed } from 'vue';
|
||||||
|
import { emitter } from 'shared/helpers/mitt';
|
||||||
|
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||||
|
import { INBOX_TYPES } from 'dashboard/helper/inbox';
|
||||||
|
|
||||||
|
import Button from 'dashboard/components-next/button/Button.vue';
|
||||||
import Avatar from '../avatar/Avatar.vue';
|
import Avatar from '../avatar/Avatar.vue';
|
||||||
|
|
||||||
defineProps({
|
const props = defineProps({
|
||||||
message: {
|
message: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
conversationInboxType: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const insertIntoRichEditor = computed(() => {
|
||||||
|
return [INBOX_TYPES.WEB, INBOX_TYPES.EMAIL].includes(
|
||||||
|
props.conversationInboxType
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const useCopilotResponse = () => {
|
||||||
|
if (insertIntoRichEditor.value) {
|
||||||
|
emitter.emit(BUS_EVENTS.INSERT_INTO_RICH_EDITOR, props.message?.content);
|
||||||
|
} else {
|
||||||
|
emitter.emit(BUS_EVENTS.INSERT_INTO_NORMAL_EDITOR, props.message?.content);
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -22,6 +46,15 @@ defineProps({
|
|||||||
<div class="break-words">
|
<div class="break-words">
|
||||||
{{ message.content }}
|
{{ message.content }}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex flex-row mt-1">
|
||||||
|
<Button
|
||||||
|
:label="$t('CAPTAIN.COPILOT.USE')"
|
||||||
|
faded
|
||||||
|
sm
|
||||||
|
slate
|
||||||
|
@click="useCopilotResponse"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ const props = defineProps({
|
|||||||
type: [Number, String],
|
type: [Number, String],
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
conversationInboxType: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const currentUser = useMapGetter('getCurrentUser');
|
const currentUser = useMapGetter('getCurrentUser');
|
||||||
const messages = ref([]);
|
const messages = ref([]);
|
||||||
@@ -53,6 +57,7 @@ const sendMessage = async message => {
|
|||||||
:messages="messages"
|
:messages="messages"
|
||||||
:support-agent="currentUser"
|
:support-agent="currentUser"
|
||||||
:is-captain-typing="isCaptainTyping"
|
:is-captain-typing="isCaptainTyping"
|
||||||
|
:conversation-inbox-type="conversationInboxType"
|
||||||
@send-message="sendMessage"
|
@send-message="sendMessage"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import ContactPanel from 'dashboard/routes/dashboard/conversation/ContactPanel.v
|
|||||||
import TabBar from 'dashboard/components-next/tabbar/TabBar.vue';
|
import TabBar from 'dashboard/components-next/tabbar/TabBar.vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
defineProps({
|
const props = defineProps({
|
||||||
currentChat: {
|
currentChat: {
|
||||||
required: true,
|
required: true,
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -16,11 +16,13 @@ defineProps({
|
|||||||
const emit = defineEmits(['toggleContactPanel']);
|
const emit = defineEmits(['toggleContactPanel']);
|
||||||
|
|
||||||
const getters = useStoreGetters();
|
const getters = useStoreGetters();
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
const captainIntegration = computed(() =>
|
const captainIntegration = computed(() =>
|
||||||
getters['integrations/getIntegration'].value('captain', null)
|
getters['integrations/getIntegration'].value('captain', null)
|
||||||
);
|
);
|
||||||
const { t } = useI18n();
|
|
||||||
|
const channelType = computed(() => props.currentChat?.meta?.channel || '');
|
||||||
|
|
||||||
const CONTACT_TABS_OPTIONS = [
|
const CONTACT_TABS_OPTIONS = [
|
||||||
{ key: 'CONTACT', value: 'contact' },
|
{ key: 'CONTACT', value: 'contact' },
|
||||||
@@ -61,7 +63,7 @@ const showCopilotTab = computed(() => {
|
|||||||
@tab-changed="handleTabChange"
|
@tab-changed="handleTabChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-auto flex flex-1">
|
<div class="flex flex-1 overflow-auto">
|
||||||
<ContactPanel
|
<ContactPanel
|
||||||
v-if="!activeTab"
|
v-if="!activeTab"
|
||||||
:conversation-id="currentChat.id"
|
:conversation-id="currentChat.id"
|
||||||
@@ -71,6 +73,7 @@ const showCopilotTab = computed(() => {
|
|||||||
<CopilotContainer
|
<CopilotContainer
|
||||||
v-else-if="activeTab === 1 && showCopilotTab"
|
v-else-if="activeTab === 1 && showCopilotTab"
|
||||||
:key="currentChat.id"
|
:key="currentChat.id"
|
||||||
|
:conversation-inbox-type="channelType"
|
||||||
:conversation-id="currentChat.id"
|
:conversation-id="currentChat.id"
|
||||||
class="flex-1"
|
class="flex-1"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -459,11 +459,13 @@ export default {
|
|||||||
BUS_EVENTS.NEW_CONVERSATION_MODAL,
|
BUS_EVENTS.NEW_CONVERSATION_MODAL,
|
||||||
this.onNewConversationModalActive
|
this.onNewConversationModalActive
|
||||||
);
|
);
|
||||||
|
emitter.on(BUS_EVENTS.INSERT_INTO_NORMAL_EDITOR, this.addIntoEditor);
|
||||||
},
|
},
|
||||||
unmounted() {
|
unmounted() {
|
||||||
document.removeEventListener('paste', this.onPaste);
|
document.removeEventListener('paste', this.onPaste);
|
||||||
document.removeEventListener('keydown', this.handleKeyEvents);
|
document.removeEventListener('keydown', this.handleKeyEvents);
|
||||||
emitter.off(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.fetchAndSetReplyTo);
|
emitter.off(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.fetchAndSetReplyTo);
|
||||||
|
emitter.off(BUS_EVENTS.INSERT_INTO_NORMAL_EDITOR, this.addIntoEditor);
|
||||||
emitter.off(
|
emitter.off(
|
||||||
BUS_EVENTS.NEW_CONVERSATION_MODAL,
|
BUS_EVENTS.NEW_CONVERSATION_MODAL,
|
||||||
this.onNewConversationModalActive
|
this.onNewConversationModalActive
|
||||||
|
|||||||
@@ -305,7 +305,8 @@
|
|||||||
"COPILOT": {
|
"COPILOT": {
|
||||||
"SEND_MESSAGE": "Send message...",
|
"SEND_MESSAGE": "Send message...",
|
||||||
"LOADER": "Captain is thinking",
|
"LOADER": "Captain is thinking",
|
||||||
"YOU": "You"
|
"YOU": "You",
|
||||||
|
"USE": "Use this"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,4 +14,5 @@ export const BUS_EVENTS = {
|
|||||||
SHOW_TOAST: 'newToastMessage',
|
SHOW_TOAST: 'newToastMessage',
|
||||||
NEW_CONVERSATION_MODAL: 'newConversationModal',
|
NEW_CONVERSATION_MODAL: 'newConversationModal',
|
||||||
INSERT_INTO_RICH_EDITOR: 'insertIntoRichEditor',
|
INSERT_INTO_RICH_EDITOR: 'insertIntoRichEditor',
|
||||||
|
INSERT_INTO_NORMAL_EDITOR: 'insertIntoNormalEditor',
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user