Skip to main content
Glama
MiddleBottomPanel.tsx8.02 kB
import { useEffect, useState } from 'react' import type { ChatMessage } from '../types' interface EngineResult { id: number raw_event_id: number engine_name: string serverName: string producer: string severity: string score: number detail: string created_at: string } interface MiddleBottomPanelProps { selectedMessage: ChatMessage | null } function MiddleBottomPanel({ selectedMessage }: MiddleBottomPanelProps) { const [engineResults, setEngineResults] = useState<EngineResult[]>([]) useEffect(() => { if (selectedMessage && selectedMessage.id) { fetchEngineResults(selectedMessage.id) } else { setEngineResults([]) } }, [selectedMessage]) const fetchEngineResults = async (rawEventId: string | number) => { try { const results = await window.electronAPI.getEngineResultsByEvent(Number(rawEventId)) setEngineResults(results) } catch (error) { console.error('Error fetching engine results:', error) setEngineResults([]) } } if (!selectedMessage) { return ( <div className="h-full bg-white flex items-center justify-center text-gray-500"> <p>Select a message to view details</p> </div> ) } return ( <div className="h-full bg-white overflow-y-auto"> <div className="p-6"> {/* Message Type */} <div className="mb-6"> <h3 className="text-sm font-semibold text-gray-500 mb-2">Message Type</h3> <p className="text-lg font-mono font-medium text-gray-800"> {selectedMessage.type} </p> </div> {/* Malicious Detect */} <div className="mb-6"> <h3 className="text-sm font-semibold text-gray-500 mb-2">Malicious Detect</h3> <div className="bg-gray-50 rounded-lg p-4"> <div className="flex items-center gap-2"> <span className="text-sm text-gray-600">Score:</span> <span className={`font-mono text-lg font-semibold ${ selectedMessage.maliciousScore > 50 ? 'text-red-600' : selectedMessage.maliciousScore > 20 ? 'text-yellow-600' : 'text-green-600' }`}> {selectedMessage.maliciousScore !== undefined ? selectedMessage.maliciousScore : 'N/A'} </span> <span className="text-sm text-gray-500">/ 100</span> </div> <div className="mt-3 bg-gray-200 rounded-full h-2 overflow-hidden"> <div className={`h-full transition-all ${ selectedMessage.maliciousScore > 50 ? 'bg-red-500' : selectedMessage.maliciousScore > 20 ? 'bg-yellow-500' : 'bg-green-500' }`} style={{ width: `${(selectedMessage.maliciousScore || 0)}%` }} /> </div> <div className="mt-2 text-xs text-gray-600"> {selectedMessage.maliciousScore > 50 ? '[!] High Risk' : selectedMessage.maliciousScore > 20 ? '[*] Medium Risk' : '[OK] Safe'} </div> {/* Engine Detection Details */} {engineResults.length > 0 && ( <div className="mt-4 pt-4 border-t border-gray-300"> <h4 className="text-sm font-semibold text-gray-700 mb-3">Detection Details</h4> <div className="space-y-3"> {engineResults.map((result) => ( <div key={result.id} className="bg-white border border-gray-300 rounded-lg p-3"> <div className="flex items-start justify-between mb-2"> <div className="flex-1"> <div className="flex items-center gap-2 mb-1"> <span className="font-mono text-sm font-semibold text-gray-800"> {result.engine_name} </span> <span className={`text-xs px-2 py-0.5 rounded ${ result.severity === 'high' ? 'bg-red-100 text-red-700' : result.severity === 'medium' || result.severity === 'mid' ? 'bg-yellow-100 text-yellow-700' : 'bg-green-100 text-green-700' }`}> {result.severity} </span> </div> <p className="text-xs text-gray-600 mt-1">{result.detail}</p> </div> <div className="ml-3 flex flex-col items-end"> <span className={`font-mono text-lg font-bold ${ result.score > 50 ? 'text-red-600' : result.score > 20 ? 'text-yellow-600' : 'text-green-600' }`}> {result.score} </span> <span className="text-xs text-gray-500">score</span> </div> </div> </div> ))} </div> </div> )} {engineResults.length === 0 && selectedMessage.maliciousScore === 0 && ( <div className="mt-4 pt-4 border-t border-gray-300"> <p className="text-xs text-gray-500 text-center">No threats detected</p> </div> )} </div> </div> {/* Message Data */} <div className="mb-6"> <h3 className="text-sm font-semibold text-gray-500 mb-2">Message Content</h3> <div className="bg-gray-50 rounded-lg p-4"> <pre className="text-xs font-mono text-gray-700 overflow-x-auto whitespace-pre-wrap"> {JSON.stringify(selectedMessage.data?.message, null, 2)} </pre> </div> </div> {/* Parameters */} {selectedMessage.data?.message?.params && Object.keys(selectedMessage.data.message.params).length > 0 && ( <div className="mb-6"> <h3 className="text-sm font-semibold text-gray-500 mb-2">Parameters</h3> <div className="bg-gray-50 rounded-lg p-4 space-y-3"> {Object.entries(selectedMessage.data.message.params) .filter(([key]) => key !== 'arguments') // arguments는 제외 .map(([key, value]) => ( <div key={key} className="flex flex-col gap-1"> <span className="font-mono text-sm font-semibold text-gray-600">{key}:</span> <div className="bg-white border border-gray-300 rounded px-3 py-2 text-sm text-gray-700"> {typeof value === 'object' ? JSON.stringify(value, null, 2) : String(value)} </div> </div> ))} {/* Arguments를 Parameters 안에 포함 */} {selectedMessage.data.message?.params?.arguments && Object.keys(selectedMessage.data.message.params.arguments).length > 0 && ( <div className="mt-4 pt-4 border-t border-gray-300"> <h4 className="text-sm font-semibold text-gray-700 mb-3">Arguments</h4> <div className="space-y-2"> {Object.entries(selectedMessage.data.message.params.arguments).map(([key, value]) => ( <div key={key} className="flex flex-col gap-1"> <span className="font-mono text-sm font-semibold text-gray-600">{key}:</span> <div className="bg-white border border-gray-300 rounded px-3 py-2 text-sm text-gray-900 font-mono"> {typeof value === 'object' ? JSON.stringify(value, null, 2) : String(value)} </div> </div> ))} </div> </div> )} </div> </div> )} </div> </div> ) } export default MiddleBottomPanel

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/seungwon9201/MCP-Dandan'

If you have feedback or need assistance with the MCP directory API, please join our Discord server