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,
|
||||
default: false,
|
||||
},
|
||||
conversationInboxType: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['sendMessage']);
|
||||
@@ -47,7 +51,7 @@ watch(
|
||||
|
||||
<template>
|
||||
<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">
|
||||
<CopilotAgentMessage
|
||||
v-if="message.role === 'user'"
|
||||
@@ -57,12 +61,13 @@ watch(
|
||||
<CopilotAssistantMessage
|
||||
v-else-if="COPILOT_USER_ROLES.includes(message.role)"
|
||||
:message="message"
|
||||
:conversation-inbox-type="conversationInboxType"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<CopilotLoader v-if="isCaptainTyping" />
|
||||
</div>
|
||||
|
||||
<CopilotInput class="mx-3 mb-4 mt-px" @send="sendMessage" />
|
||||
<CopilotInput class="mx-3 mt-px mb-4" @send="sendMessage" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,12 +1,36 @@
|
||||
<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';
|
||||
|
||||
defineProps({
|
||||
const props = defineProps({
|
||||
message: {
|
||||
type: Object,
|
||||
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>
|
||||
|
||||
<template>
|
||||
@@ -22,6 +46,15 @@ defineProps({
|
||||
<div class="break-words">
|
||||
{{ message.content }}
|
||||
</div>
|
||||
<div class="flex flex-row mt-1">
|
||||
<Button
|
||||
:label="$t('CAPTAIN.COPILOT.USE')"
|
||||
faded
|
||||
sm
|
||||
slate
|
||||
@click="useCopilotResponse"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -8,6 +8,10 @@ const props = defineProps({
|
||||
type: [Number, String],
|
||||
required: true,
|
||||
},
|
||||
conversationInboxType: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
const currentUser = useMapGetter('getCurrentUser');
|
||||
const messages = ref([]);
|
||||
@@ -53,6 +57,7 @@ const sendMessage = async message => {
|
||||
:messages="messages"
|
||||
:support-agent="currentUser"
|
||||
:is-captain-typing="isCaptainTyping"
|
||||
:conversation-inbox-type="conversationInboxType"
|
||||
@send-message="sendMessage"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -6,7 +6,7 @@ import ContactPanel from 'dashboard/routes/dashboard/conversation/ContactPanel.v
|
||||
import TabBar from 'dashboard/components-next/tabbar/TabBar.vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
defineProps({
|
||||
const props = defineProps({
|
||||
currentChat: {
|
||||
required: true,
|
||||
type: Object,
|
||||
@@ -16,11 +16,13 @@ defineProps({
|
||||
const emit = defineEmits(['toggleContactPanel']);
|
||||
|
||||
const getters = useStoreGetters();
|
||||
const { t } = useI18n();
|
||||
|
||||
const captainIntegration = computed(() =>
|
||||
getters['integrations/getIntegration'].value('captain', null)
|
||||
);
|
||||
const { t } = useI18n();
|
||||
|
||||
const channelType = computed(() => props.currentChat?.meta?.channel || '');
|
||||
|
||||
const CONTACT_TABS_OPTIONS = [
|
||||
{ key: 'CONTACT', value: 'contact' },
|
||||
@@ -61,7 +63,7 @@ const showCopilotTab = computed(() => {
|
||||
@tab-changed="handleTabChange"
|
||||
/>
|
||||
</div>
|
||||
<div class="overflow-auto flex flex-1">
|
||||
<div class="flex flex-1 overflow-auto">
|
||||
<ContactPanel
|
||||
v-if="!activeTab"
|
||||
:conversation-id="currentChat.id"
|
||||
@@ -71,6 +73,7 @@ const showCopilotTab = computed(() => {
|
||||
<CopilotContainer
|
||||
v-else-if="activeTab === 1 && showCopilotTab"
|
||||
:key="currentChat.id"
|
||||
:conversation-inbox-type="channelType"
|
||||
:conversation-id="currentChat.id"
|
||||
class="flex-1"
|
||||
/>
|
||||
|
||||
@@ -459,11 +459,13 @@ export default {
|
||||
BUS_EVENTS.NEW_CONVERSATION_MODAL,
|
||||
this.onNewConversationModalActive
|
||||
);
|
||||
emitter.on(BUS_EVENTS.INSERT_INTO_NORMAL_EDITOR, this.addIntoEditor);
|
||||
},
|
||||
unmounted() {
|
||||
document.removeEventListener('paste', this.onPaste);
|
||||
document.removeEventListener('keydown', this.handleKeyEvents);
|
||||
emitter.off(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.fetchAndSetReplyTo);
|
||||
emitter.off(BUS_EVENTS.INSERT_INTO_NORMAL_EDITOR, this.addIntoEditor);
|
||||
emitter.off(
|
||||
BUS_EVENTS.NEW_CONVERSATION_MODAL,
|
||||
this.onNewConversationModalActive
|
||||
|
||||
@@ -305,7 +305,8 @@
|
||||
"COPILOT": {
|
||||
"SEND_MESSAGE": "Send message...",
|
||||
"LOADER": "Captain is thinking",
|
||||
"YOU": "You"
|
||||
"YOU": "You",
|
||||
"USE": "Use this"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,4 +14,5 @@ export const BUS_EVENTS = {
|
||||
SHOW_TOAST: 'newToastMessage',
|
||||
NEW_CONVERSATION_MODAL: 'newConversationModal',
|
||||
INSERT_INTO_RICH_EDITOR: 'insertIntoRichEditor',
|
||||
INSERT_INTO_NORMAL_EDITOR: 'insertIntoNormalEditor',
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user