import { useState, useMemo } from 'react'; import { createColumnHelper, flexRender, getCoreRowModel, useReactTable, } from '@tanstack/react-table'; import { ScrollArea } from '../components/ScrollArea'; import { JsonTree } from '../components/JsonTree'; import { WebSocketMessageType } from '../../shared/websocket-events'; import { WebSocketNetworkEntry } from '../state/model'; import { useWebSocketMessages } from '../state/hooks'; export type MessagesTabProps = { selectedRequest: WebSocketNetworkEntry; }; interface WebSocketMessageRow { id: string; direction: 'sent' | 'received'; data: string; messageType: 'text' | 'binary'; timestamp: number; } const columnHelper = createColumnHelper(); export const MessagesTab = ({ selectedRequest }: MessagesTabProps) => { const websocketMessages = useWebSocketMessages(selectedRequest.id); const [selectedMessageId, setSelectedMessageId] = useState( null ); const selectedMessage = useMemo(() => { if (!selectedMessageId) return null; return ( websocketMessages.find((msg) => msg.id === selectedMessageId) || null ); }, [selectedMessageId, websocketMessages]); const formatTimestamp = (timestamp: number) => { const date = new Date(timestamp); const timeString = date.toLocaleTimeString('en-US', { hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit', }); const milliseconds = date.getMilliseconds().toString().padStart(3, '0'); return `${timeString}.${milliseconds}`; }; const formatData = (data: string, messageType: WebSocketMessageType) => { if (messageType === 'binary') { return 'Binary message'; } if (typeof data === 'string') { try { const jsonData = JSON.parse(data); return (
); } catch { // Fallback to pre tag if JSON parsing fails return (
            {data}
          
); } } return 'Binary message'; }; const getMessageTypeColor = (type: 'sent' | 'received') => { return type === 'sent' ? 'text-blue-400' : 'text-green-400'; }; const getMessageTypeIcon = (type: 'sent' | 'received') => { return type === 'sent' ? '↑' : '↓'; }; const tableData = useMemo(() => { return websocketMessages.map( (message): WebSocketMessageRow => ({ id: message.id, direction: message.direction, data: message.data, messageType: message.messageType, timestamp: message.timestamp, }) ); }, [websocketMessages]); const formatPreviewData = ( data: string, messageType: WebSocketMessageType ) => { if (messageType === 'binary') { return Binary message; } return ( {data.substring(0, 100) + (data.length > 100 ? '...' : '')} ); }; const columns = [ columnHelper.accessor('direction', { header: 'Type', cell: ({ getValue }) => { const direction = getValue(); return ( {getMessageTypeIcon(direction)} {direction} ); }, size: 80, }), columnHelper.accessor('data', { header: 'Data', cell: ({ getValue, row }) => { const data = getValue(); const messageType = row.original.messageType; return formatPreviewData(data, messageType); }, size: 300, }), columnHelper.accessor('timestamp', { header: 'Timestamp', cell: ({ getValue }) => (
{formatTimestamp(getValue())}
), size: 120, }), ]; const table = useReactTable({ data: tableData, columns, getCoreRowModel: getCoreRowModel(), }); if (websocketMessages.length === 0) { return (
No WebSocket messages available for this connection. Messages will appear here when the WebSocket connection sends or receives data.
); } return (
{/* Messages Table */}
{table.getHeaderGroups().map((headerGroup) => ( {headerGroup.headers.map((header) => ( ))} ))} {table.getRowModel().rows.map((row) => ( setSelectedMessageId(row.original.id)} > {row.getVisibleCells().map((cell) => ( ))} ))}
{header.isPlaceholder ? null : flexRender( header.column.columnDef.header, header.getContext() )}
{flexRender( cell.column.columnDef.cell, cell.getContext() )}
{/* Message Details Panel */} {selectedMessage && (

Message Details

Type: {selectedMessage.direction}
Message Type: {selectedMessage.messageType}
Timestamp: {formatTimestamp(selectedMessage.timestamp)}
Content:
{formatData( selectedMessage.data, selectedMessage.messageType )}
)}
); };