diff --git a/frontend/app/PrivateRoutes.tsx b/frontend/app/PrivateRoutes.tsx index 491ac8f13..f16e41523 100644 --- a/frontend/app/PrivateRoutes.tsx +++ b/frontend/app/PrivateRoutes.tsx @@ -103,7 +103,8 @@ const HIGHLIGHTS_PATH = routes.highlights(); const KAI_PATH = routes.kai(); function PrivateRoutes() { - const { projectsStore, userStore, integrationsStore, searchStore } = useStore(); + const { projectsStore, userStore, integrationsStore, searchStore } = + useStore(); const onboarding = userStore.onboarding; const scope = userStore.scopeState; const { tenantId } = userStore.account; @@ -127,8 +128,12 @@ function PrivateRoutes() { React.useEffect(() => { if (!searchStore.urlParsed) return; - debounceCall(() => searchStore.fetchSessions(true), 250)() - }, [searchStore.urlParsed, searchStore.instance.filters, searchStore.instance.eventsOrder]); + debounceCall(() => searchStore.fetchSessions(true), 250)(); + }, [ + searchStore.urlParsed, + searchStore.instance.filters, + searchStore.instance.eventsOrder, + ]); return ( }> @@ -166,13 +171,13 @@ function PrivateRoutes() { case '/integrations/slack': client.post('integrations/slack/add', { code: location.search.split('=')[1], - state: tenantId + state: tenantId, }); break; case '/integrations/msteams': client.post('integrations/msteams/add', { code: location.search.split('=')[1], - state: tenantId + state: tenantId, }); break; } @@ -197,7 +202,7 @@ function PrivateRoutes() { withSiteId(DASHBOARD_PATH, siteIdList), withSiteId(DASHBOARD_SELECT_PATH, siteIdList), withSiteId(DASHBOARD_METRIC_CREATE_PATH, siteIdList), - withSiteId(DASHBOARD_METRIC_DETAILS_PATH, siteIdList) + withSiteId(DASHBOARD_METRIC_DETAILS_PATH, siteIdList), ]} component={enhancedComponents.Dashboard} /> @@ -258,7 +263,7 @@ function PrivateRoutes() { withSiteId(FFLAG_READ_PATH, siteIdList), withSiteId(FFLAG_CREATE_PATH, siteIdList), withSiteId(NOTES_PATH, siteIdList), - withSiteId(BOOKMARKS_PATH, siteIdList) + withSiteId(BOOKMARKS_PATH, siteIdList), ]} component={enhancedComponents.SessionsOverview} /> @@ -274,12 +279,14 @@ function PrivateRoutes() { path={withSiteId(LIVE_SESSION_PATH, siteIdList)} component={enhancedComponents.LiveSession} /> - {hasAi ? : null} + {hasAi ? ( + + ) : null} {Object.entries(routes.redirects).map(([fr, to]) => ( ))} diff --git a/frontend/app/components/Kai/KaiChat.tsx b/frontend/app/components/Kai/KaiChat.tsx index 54267a16b..aad1c7612 100644 --- a/frontend/app/components/Kai/KaiChat.tsx +++ b/frontend/app/components/Kai/KaiChat.tsx @@ -27,6 +27,13 @@ function KaiChat() { const params = new URLSearchParams(location.search); const threadIdFromUrl = params.get('threadId'); + React.useEffect(() => { + // Reset chat state and clear URL params when project changes + setSection('intro'); + setThreadId(null); + history.replace({ search: '' }); + }, [activeSiteId]); + const openChats = () => { showModal( => { + getKaiChats = async ( + projectId: string, + ): Promise<{ title: string; threadId: string }[]> => { const r = await this.client.get(`/kai/${projectId}/chats`); if (!r.ok) { throw new Error('Failed to fetch chats'); } const data = await r.json(); return data; - } + }; - deleteKaiChat = async (projectId: string, threadId: string): Promise => { + deleteKaiChat = async ( + projectId: string, + threadId: string, + ): Promise => { const r = await this.client.delete(`/kai/${projectId}/chats/${threadId}`); if (!r.ok) { throw new Error('Failed to delete chat'); } return true; - } + }; - getKaiChat = async (projectId: string, threadId: string): Promise<{ role: string, content: string, message_id: any, duration?: number }[]> => { + getKaiChat = async ( + projectId: string, + threadId: string, + ): Promise< + { role: string; content: string; message_id: any; duration?: number }[] + > => { const r = await this.client.get(`/kai/${projectId}/chats/${threadId}`); if (!r.ok) { throw new Error('Failed to fetch chat'); } const data = await r.json(); return data; - } + }; createKaiChat = async (projectId: string): Promise => { - const r = await this.client.get(`/kai/${projectId}/chat/new`) + const r = await this.client.get(`/kai/${projectId}/chat/new`); if (!r.ok) { throw new Error('Failed to create chat'); } const data = await r.json(); return data; - } + }; - feedback = async (positive: boolean | null, messageId: string, projectId: string) => { + feedback = async ( + positive: boolean | null, + messageId: string, + projectId: string, + ) => { const r = await this.client.post(`/kai/${projectId}/messages/feedback`, { - message_id: messageId, - value: positive, - user_id: userId, + message_id: messageId, + value: positive, }); if (!r.ok) { throw new Error('Failed to send feedback'); } - return await r.json() - } + return await r.json(); + }; cancelGeneration = async (projectId: string, threadId: string) => { const r = await this.client.post(`/kai/${projectId}/cancel/${threadId}`); @@ -57,5 +70,5 @@ export default class KaiService extends AiService { const data = await r.json(); return data; - } + }; } diff --git a/frontend/app/components/Kai/SocketManager.ts b/frontend/app/components/Kai/SocketManager.ts index 266e99497..d16c3ec69 100644 --- a/frontend/app/components/Kai/SocketManager.ts +++ b/frontend/app/components/Kai/SocketManager.ts @@ -42,7 +42,6 @@ export class ChatManager { socket.on('error', (err) => { console.error('Socket error:', err); }); - socket.onAny((e) => console.log('event', e)); this.socket = socket; } @@ -68,11 +67,9 @@ export class ChatManager { titleCallback: (title: string) => void; }) => { this.socket.on('chunk', (msg: BotChunk) => { - console.log('Received message:', msg); msgCallback(msg); }); this.socket.on('title', (msg: { content: string }) => { - console.log('Received title:', msg); titleCallback(msg.content); }); this.socket.on( diff --git a/frontend/app/components/Kai/components/ChatMsg.tsx b/frontend/app/components/Kai/components/ChatMsg.tsx index f2a67a733..bfa58033c 100644 --- a/frontend/app/components/Kai/components/ChatMsg.tsx +++ b/frontend/app/components/Kai/components/ChatMsg.tsx @@ -2,8 +2,15 @@ import React from 'react'; import { Icon, CopyButton } from 'UI'; import cn from 'classnames'; import Markdown from 'react-markdown'; -import remarkGfm from 'remark-gfm' -import { Loader, ThumbsUp, ThumbsDown, ListRestart, FileDown, Clock } from 'lucide-react'; +import remarkGfm from 'remark-gfm'; +import { + Loader, + ThumbsUp, + ThumbsDown, + ListRestart, + FileDown, + Clock, +} from 'lucide-react'; import { Button, Tooltip } from 'antd'; import { kaiStore } from '../KaiStore'; import { toast } from 'react-toastify'; @@ -27,36 +34,37 @@ export function ChatMsg({ const [isProcessing, setIsProcessing] = React.useState(false); const bodyRef = React.useRef(null); const onRetry = () => { - kaiStore.editMessage(text) - } + kaiStore.editMessage(text); + }; const onFeedback = (feedback: 'like' | 'dislike', messageId: string) => { kaiStore.sendMsgFeedback(feedback, messageId); }; const onExport = () => { setIsProcessing(true); - import('jspdf').then(({ jsPDF }) => { - const doc = new jsPDF(); + import('jspdf') + .then(({ jsPDF }) => { + const doc = new jsPDF(); - doc.html(bodyRef.current, { - callback: function(doc) { - doc.save('document.pdf'); - }, - margin: [10, 10, 10, 10], - x: 0, - y: 0, - width: 190, // Target width - windowWidth: 675 // Window width for rendering + doc.html(bodyRef.current, { + callback: function (doc) { + doc.save('document.pdf'); + }, + margin: [10, 10, 10, 10], + x: 0, + y: 0, + width: 190, // Target width + windowWidth: 675, // Window width for rendering + }); + }) + .catch((e) => { + console.error('Error exporting message:', e); + toast.error('Failed to export message'); + }) + .finally(() => { + setIsProcessing(false); }); - }) - .catch(e => { - console.error('Error exporting message:', e); - toast.error('Failed to export message'); - }) - .finally(() => { - setIsProcessing(false); - }); - } + }; return (
)}
-
+
{text}
{isUser ? ( @@ -99,18 +107,31 @@ export function ChatMsg({ ) : null ) : (
- {duration ? ( - - ) : null} -
- onFeedback('like', messageId)}> + {duration ? : null} +
+ onFeedback('like', messageId)} + > - onFeedback('dislike', messageId)}> + onFeedback('dislike', messageId)} + > - bodyRef.current?.innerHTML} content={text} isIcon format={'text/html'} /> - + bodyRef.current?.innerHTML} + content={text} + isIcon + format={'text/html'} + /> +
@@ -133,23 +154,35 @@ function IconButton({ }) { return ( -