Files
aerbim-ht-monitor/frontend/components/alerts/AlertsList.tsx — копия

162 lines
7.2 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useState, useMemo } from 'react'
import * as statusColors from '../../lib/statusColors'
interface AlertItem {
id: number
type: string
message: string
timestamp: string
acknowledged: boolean
priority: string
detector_id?: string
detector_name?: string
location?: string
object?: string
}
interface AlertsListProps {
alerts: AlertItem[]
onAcknowledgeToggle: (alertId: number) => void
initialSearchTerm?: string
}
const AlertsList: React.FC<AlertsListProps> = ({ alerts, onAcknowledgeToggle, initialSearchTerm = '' }) => {
const [searchTerm, setSearchTerm] = useState(initialSearchTerm)
const filteredAlerts = useMemo(() => {
return alerts.filter(alert => {
const matchesSearch = searchTerm === '' || alert.detector_id?.toString() === searchTerm
return matchesSearch
})
}, [alerts, searchTerm])
const interSemiboldStyle = { fontFamily: 'Inter, sans-serif', fontWeight: 600 }
const interRegularStyle = { fontFamily: 'Inter, sans-serif', fontWeight: 400 }
const getStatusColor = (type: string) => {
switch (type) {
case 'critical':
return statusColors.STATUS_COLOR_CRITICAL
case 'warning':
return statusColors.STATUS_COLOR_WARNING
case 'info':
return statusColors.STATUS_COLOR_NORMAL
default:
return statusColors.STATUS_COLOR_UNKNOWN
}
}
return (
<div className="space-y-6">
{/* Поиск */}
<div className="flex items-center justify-end gap-4 mb-6">
<div className="relative">
<input
type="text"
placeholder="Поиск по ID детектора..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="bg-[#161824] text-white placeholder-gray-400 px-4 py-2 rounded-lg border border-gray-600 focus:border-blue-500 focus:outline-none w-64"
/>
<svg className="absolute right-3 top-2.5 w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</div>
</div>
{/* Таблица алертов */}
<div className="bg-[#161824] rounded-[20px] p-6">
<div className="mb-4 flex items-center justify-between">
<h2 style={interSemiboldStyle} className="text-xl text-white">История тревог</h2>
<span style={interRegularStyle} className="text-sm text-gray-400">Всего: {filteredAlerts.length}</span>
</div>
<div className="overflow-x-auto">
<table className="w-full">
<thead>
<tr className="border-b border-gray-700">
<th style={interSemiboldStyle} className="text-left text-white text-sm py-3">Детектор</th>
<th style={interSemiboldStyle} className="text-left text-white text-sm py-3">Статус</th>
<th style={interSemiboldStyle} className="text-left text-white text-sm py-3">Сообщение</th>
<th style={interSemiboldStyle} className="text-left text-white text-sm py-3">Местоположение</th>
<th style={interSemiboldStyle} className="text-left text-white text-sm py-3">Приоритет</th>
<th style={interSemiboldStyle} className="text-left text-white text-sm py-3">Подтверждено</th>
<th style={interSemiboldStyle} className="text-left text-white text-sm py-3">Время</th>
</tr>
</thead>
<tbody>
{filteredAlerts.map((item) => (
<tr key={item.id} className="border-b border-gray-700 hover:bg-gray-800/50 transition-colors">
<td style={interRegularStyle} className="py-4 text-sm text-white">
<div>{item.detector_name || 'Детектор'}</div>
{item.detector_id ? (
<div className="text-gray-400">ID: {item.detector_id}</div>
) : null}
</td>
<td className="py-4">
<div className="flex items-center gap-2">
<div
className="w-3 h-3 rounded-full"
style={{ backgroundColor: getStatusColor(item.type) }}
></div>
<span style={interRegularStyle} className="text-sm text-gray-300">
{item.type === 'critical' ? 'Критический' : item.type === 'warning' ? 'Предупреждение' : 'Информация'}
</span>
</div>
</td>
<td style={interRegularStyle} className="py-4 text-sm text-white">
{item.message}
</td>
<td style={interRegularStyle} className="py-4 text-sm text-white">
{item.location || '-'}
</td>
<td className="py-4">
<span
className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium text-white"
style={{
backgroundColor:
item.priority === 'high'
? statusColors.STATUS_COLOR_CRITICAL
: item.priority === 'medium'
? statusColors.STATUS_COLOR_WARNING
: statusColors.STATUS_COLOR_NORMAL,
}}
>
{item.priority === 'high' ? 'Высокий' : item.priority === 'medium' ? 'Средний' : 'Низкий'}
</span>
</td>
<td className="py-4">
<span style={interRegularStyle} className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs ${
item.acknowledged ? 'bg-green-600/20 text-green-300 ring-1 ring-green-600/40' : 'bg-red-600/20 text-red-300 ring-1 ring-red-600/40'
}`}>
{item.acknowledged ? 'Да' : 'Нет'}
</span>
<button
onClick={() => onAcknowledgeToggle(item.id)}
style={interRegularStyle}
className="ml-2 inline-flex items-center px-2 py-1 rounded text-xs bg-[#2a2e3e] text-white hover:bg-[#353a4d]"
>
{item.acknowledged ? 'Снять' : 'Подтвердить'}
</button>
</td>
<td style={interRegularStyle} className="py-4 text-sm text-gray-300">
{new Date(item.timestamp).toLocaleString('ru-RU')}
</td>
</tr>
))}
{filteredAlerts.length === 0 && (
<tr>
<td colSpan={7} className="py-8 text-center text-gray-400">
Записей не найдено
</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
</div>
)
}
export default AlertsList