import React, { useEffect, useRef, useState } from 'react'; import { Accordion, AccordionSummary, AccordionDetails, CircularProgress, Pagination, Button, Dialog, Typography, Chip } from "@mui/material"; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import ThumbUpOffAltIcon from '@mui/icons-material/ThumbUpOffAlt'; import ThumbDownOffAlt from '@mui/icons-material/ThumbDownOffAlt'; import { green, red } from '@mui/material/colors'; import { DialogItem } from './Analytics'; import { useComponents } from "../../contexts/ComponentContext"; import useChatMessages from '../../hooks/useChatMessages'; import { groupDialogsByDate } from "../../utils/formatChatsDate.ts"; import Chat from "../Chat/Chat"; import { ChatMessage } from '../Chat/ChatMessage'; import PayloadViewer from "../Chat/PayloadViewer"; import JSONViewer from "../Chat/JSONViewer"; interface ChatHistoryProps { isLoading: boolean; dialogs: DialogItem[]; pagesNum: number; page: number; flows: any[]; changePage: (event: React.ChangeEvent, page: number) => void; } export const ChatHistory = ({ isLoading, dialogs, pagesNum, page, flows, changePage, }: ChatHistoryProps) => { const { ChatComponent } = useComponents(); const [expandedAccordion, setExpandedAccordion] = useState(false); const [popoverOpen, setPopoverOpen] = useState(false); const [selectedChatId, setSelectedChatId] = useState(null); const listTopRef = useRef(null); const ActiveChatComponent = ChatComponent || Chat; const MessageComponent = (ChatComponent as any)?.ChatMessage || ChatMessage; const [trace, setTrace] = useState | null>(null); const [payload, setPayload] = useState(null); const [messageStates, setMessageStates] = useState<{ [key: string]: { copied: boolean; expandedReferences: boolean; } }>({}); const { data: fullChatMessages, isLoading: isFullChatLoading } = useChatMessages( selectedChatId && popoverOpen ? selectedChatId : null ); const handleMessageCopy = (messageId: string, copied: boolean) => { setMessageStates(prev => ({ ...prev, [messageId]: { ...prev[messageId], copied } })); if (copied) { setTimeout(() => { setMessageStates(prev => ({ ...prev, [messageId]: { ...prev[messageId], copied: false } })); }, 3000); } }; const handleReferenceToggle = (messageId: string) => { setMessageStates(prev => ({ ...prev, [messageId]: { ...prev[messageId], expandedReferences: !prev[messageId]?.expandedReferences } })); }; useEffect(() => { if (listTopRef.current) { listTopRef.current.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }, [page]); const handleAccordionChange = (dialogId: string) => (_: React.SyntheticEvent, isExpanded: boolean) => { setExpandedAccordion(isExpanded ? dialogId : false); }; const handleViewFullConversation = (chatId: string) => { setSelectedChatId(chatId); setPopoverOpen(true); }; const handleClosePopover = () => { setPopoverOpen(false); setSelectedChatId(null); }; const getBackgroundColor = (dialog: DialogItem) => { if (dialog.has_error || !dialog.system_message) { return '!bg-yellow-50/80 dark:!bg-yellow-900/10'; } return '!bg-green-50/80 dark:!bg-green-900/10'; }; const formatDate = (timestamp: string) => { return new Date(timestamp).toLocaleString(); }; const getFlowName = (flowId?: string) => { const flow = flows?.find(f => f.id === flowId); return flow?.description || flow?.id || 'Unknown Flow'; }; const groupedDialogs = groupDialogsByDate(dialogs); if (isLoading) { return (
); } if (dialogs.length === 0) { return (
No dialog history found
); } return (
{Object.entries(groupedDialogs).map(([groupTitle, groupDialogs]) => (
{groupTitle}
{groupDialogs.map((dialog: DialogItem) => { const messageId = dialog.msg_id; const messageState = messageStates[messageId] || {}; return ( } aria-controls={`${messageId}-content`} id={`${messageId}-header`} className="hover:bg-primary-lt/50 dark:hover:bg-opacity-10" sx={{ '& .Mui-expanded': { marginTop: '12px !important', marginBottom: '12px !important' }, }} >
{dialog.user_message.text || "Question"}
{dialog.user_id}
{formatDate(dialog.timestamp)}
{dialog.has_error && ( )}
{dialog.system_message ? (
{MessageComponent ? (
handleMessageCopy(messageId, copied)} onTraceClick={setTrace} onPayloadClick={setPayload} onReferenceToggle={() => handleReferenceToggle(messageId)} expandedReferences={{ 0: messageState.expandedReferences || false }} copiedStates={{ 0: messageState.copied || false }} />
) : (

{dialog.system_message.text}

)}
) : (
{dialog.has_error ? 'An error occurred processing this message' : 'No response was generated for this message'}
)}
) })}
))} {pagesNum > 1 && (
)}
Full Conversation
{isFullChatLoading ? (
) : fullChatMessages ? ( ) : (
No conversation data available
)}
setTrace(null)} /> setPayload(null)} />
); };