n8n/packages/editor-ui/src/components/AskAssistant/AskAssistantChat.vue
Mutasem Aldmour 351134f786
Some checks failed
Test Master / install-and-build (push) Has been cancelled
Test Master / Unit tests (18.x) (push) Has been cancelled
Test Master / Unit tests (20.x) (push) Has been cancelled
Test Master / Unit tests (22.4) (push) Has been cancelled
Test Master / Lint (push) Has been cancelled
Test Master / Notify Slack on failure (push) Has been cancelled
fix(editor): Ensure toasts show above modal overlays (#11410)
2024-10-25 16:56:47 +02:00

116 lines
3.3 KiB
Vue

<script lang="ts" setup>
import { useAssistantStore } from '@/stores/assistant.store';
import { useDebounce } from '@/composables/useDebounce';
import { useUsersStore } from '@/stores/users.store';
import { computed } from 'vue';
import SlideTransition from '@/components/transitions/SlideTransition.vue';
import AskAssistantChat from 'n8n-design-system/components/AskAssistantChat/AskAssistantChat.vue';
import { useTelemetry } from '@/composables/useTelemetry';
const assistantStore = useAssistantStore();
const usersStore = useUsersStore();
const telemetry = useTelemetry();
const user = computed(() => ({
firstName: usersStore.currentUser?.firstName ?? '',
lastName: usersStore.currentUser?.lastName ?? '',
}));
const loadingMessage = computed(() => assistantStore.assistantThinkingMessage);
function onResize(data: { direction: string; x: number; width: number }) {
assistantStore.updateWindowWidth(data.width);
}
function onResizeDebounced(data: { direction: string; x: number; width: number }) {
void useDebounce().callDebounced(onResize, { debounceTime: 10, trailing: true }, data);
}
async function onUserMessage(content: string, quickReplyType?: string, isFeedback = false) {
// If there is no current session running, initialize the support chat session
if (!assistantStore.currentSessionId) {
await assistantStore.initSupportChat(content);
} else {
await assistantStore.sendMessage({ text: content, quickReplyType });
}
const task = assistantStore.chatSessionTask;
const solutionCount = assistantStore.chatMessages.filter(
(msg) => msg.role === 'assistant' && !['text', 'event'].includes(msg.type),
).length;
if (isFeedback) {
telemetry.track('User gave feedback', {
task,
chat_session_id: assistantStore.currentSessionId,
is_quick_reply: !!quickReplyType,
is_positive: quickReplyType === 'all-good',
solution_count: solutionCount,
response: content,
});
}
}
async function onCodeReplace(index: number) {
await assistantStore.applyCodeDiff(index);
telemetry.track('User clicked solution card action', {
action: 'replace_code',
});
}
async function undoCodeDiff(index: number) {
await assistantStore.undoCodeDiff(index);
telemetry.track('User clicked solution card action', {
action: 'undo_code_replace',
});
}
function onClose() {
assistantStore.closeChat();
telemetry.track('User closed assistant', { source: 'top-toggle' });
}
</script>
<template>
<SlideTransition>
<n8n-resize-wrapper
v-show="assistantStore.isAssistantOpen"
:supported-directions="['left']"
:width="assistantStore.chatWidth"
:class="$style.container"
data-test-id="ask-assistant-sidebar"
@resize="onResizeDebounced"
>
<div
:style="{ width: `${assistantStore.chatWidth}px` }"
:class="$style.wrapper"
data-test-id="ask-assistant-chat"
tabindex="0"
@keydown.stop
>
<AskAssistantChat
:user="user"
:messages="assistantStore.chatMessages"
:streaming="assistantStore.streaming"
:loading-message="loadingMessage"
:session-id="assistantStore.currentSessionId"
@close="onClose"
@message="onUserMessage"
@code-replace="onCodeReplace"
@code-undo="undoCodeDiff"
/>
</div>
</n8n-resize-wrapper>
</SlideTransition>
</template>
<style module>
.container {
height: 100%;
flex-basis: content;
z-index: var(--z-index-ask-assistant-chat);
}
.wrapper {
height: 100%;
}
</style>