Fix jwt-token

This commit is contained in:
2025-09-22 09:59:22 +02:00
parent 8b6aab6cf4
commit 90f2c8fefb

View File

@@ -49,6 +49,33 @@ const Alerts = () => {
}
};
// Group alerts by alert_event_id to show related alerts together
const groupAlertsByEvent = (logs) => {
const grouped = {};
const ungrouped = [];
logs.forEach(log => {
if (log.alert_event_id) {
if (!grouped[log.alert_event_id]) {
grouped[log.alert_event_id] = [];
}
grouped[log.alert_event_id].push(log);
} else {
ungrouped.push(log);
}
});
// Convert grouped object to array of arrays, sorted by most recent alert in each group
const groupedArrays = Object.values(grouped).map(group =>
group.sort((a, b) => new Date(b.sent_at) - new Date(a.sent_at))
).sort((a, b) => new Date(b[0].sent_at) - new Date(a[0].sent_at));
// Add ungrouped alerts as individual groups
ungrouped.forEach(log => groupedArrays.push([log]));
return groupedArrays;
};
const handleDeleteRule = async (ruleId) => {
if (window.confirm('Are you sure you want to delete this alert rule?')) {
try {
@@ -356,39 +383,63 @@ const Alerts = () => {
<th>{t('alerts.detection')}</th>
<th>{t('alerts.message')}</th>
<th>{t('alerts.sentAt')}</th>
<th>Event ID</th>
</tr>
</thead>
<tbody>
{(alertLogs || []).map((log) => (
<tr key={log.id} className="hover:bg-gray-50">
{groupAlertsByEvent(alertLogs || []).map((alertGroup, groupIndex) => {
// Display the primary alert (first in group)
const primaryAlert = alertGroup[0];
const relatedAlerts = alertGroup.slice(1);
return (
<React.Fragment key={`group-${groupIndex}`}>
<tr className="hover:bg-gray-50 border-b-2 border-gray-200">
<td>
<div className="flex items-center space-x-2">
{getStatusIcon(log.status)}
{getStatusIcon(primaryAlert.status)}
<span className="text-sm text-gray-900 capitalize">
{log.status}
{primaryAlert.status}
</span>
{relatedAlerts.length > 0 && (
<span className="ml-2 px-2 py-1 bg-blue-100 text-blue-800 rounded text-xs">
+{relatedAlerts.length} more
</span>
)}
</div>
</td>
<td>
<div className="flex flex-wrap gap-1">
<span className="px-2 py-1 bg-blue-100 text-blue-800 rounded text-xs">
{log.alert_type}
{primaryAlert.alert_type}
</span>
</td>
<td>
<div className="text-sm text-gray-900">
{log.recipient}
{relatedAlerts.map((alert, idx) => (
<span key={idx} className="px-2 py-1 bg-gray-100 text-gray-600 rounded text-xs">
{alert.alert_type}
</span>
))}
</div>
</td>
<td>
<div className="text-sm text-gray-900">
{log.rule?.name || t('alerts.unknownRule')}
{primaryAlert.recipient}
{relatedAlerts.length > 0 && relatedAlerts.some(a => a.recipient !== primaryAlert.recipient) && (
<div className="text-xs text-gray-500 mt-1">
+{relatedAlerts.filter(a => a.recipient !== primaryAlert.recipient).length} others
</div>
)}
</div>
</td>
<td>
<div className="text-sm text-gray-900">
{log.detection?.drone_id ? (
{primaryAlert.rule?.name || t('alerts.unknownRule')}
</div>
</td>
<td>
<div className="text-sm text-gray-900">
{primaryAlert.detection?.drone_id ? (
<span className="px-2 py-1 bg-purple-100 text-purple-800 rounded text-xs font-mono">
{log.detection.drone_id}
{primaryAlert.detection.drone_id}
</span>
) : (
<span className="text-gray-400 text-sm">{t('alerts.na')}</span>
@@ -396,10 +447,10 @@ const Alerts = () => {
</div>
</td>
<td>
{log.detection_id ? (
{primaryAlert.detection_id ? (
<button
onClick={() => handleViewDetection(log.detection_id)}
className="text-primary-600 hover:text-primary-900 text-sm font-medium"
onClick={() => handleViewDetection(primaryAlert.detection_id)}
className="text-blue-600 hover:text-blue-800 text-sm underline"
>
{t('alerts.viewDetails')}
</button>
@@ -408,20 +459,107 @@ const Alerts = () => {
)}
</td>
<td>
<div className="text-sm text-gray-900 max-w-xs truncate">
{log.message}
<div className="text-sm text-gray-900 max-w-xs overflow-hidden">
<div className="truncate" title={primaryAlert.message}>
{primaryAlert.message}
</div>
</div>
</td>
<td>
<div className="text-sm text-gray-900">
{log.sent_at
? format(new Date(log.sent_at), 'MMM dd, HH:mm')
: 'Not sent'
}
{format(new Date(primaryAlert.sent_at), 'MMM dd, HH:mm')}
</div>
</td>
<td>
<div className="text-xs text-gray-500 font-mono">
{primaryAlert.alert_event_id ? (
<span title={primaryAlert.alert_event_id}>
{primaryAlert.alert_event_id.substring(0, 8)}...
</span>
) : (
<span className="text-gray-400">-</span>
)}
</div>
</td>
</tr>
{/* Show related alerts as sub-rows if any */}
{relatedAlerts.map((alert, alertIndex) => (
<tr key={`related-${groupIndex}-${alertIndex}`} className="bg-gray-50 border-l-4 border-blue-200">
<td className="pl-8">
<div className="flex items-center space-x-2">
{getStatusIcon(alert.status)}
<span className="text-sm text-gray-700 capitalize">
{alert.status}
</span>
</div>
</td>
<td>
<span className="px-2 py-1 bg-gray-100 text-gray-600 rounded text-xs">
{alert.alert_type}
</span>
</td>
<td>
<div className="text-sm text-gray-700">
{alert.recipient}
</div>
</td>
<td>
<div className="text-sm text-gray-700">
{alert.rule?.name || t('alerts.unknownRule')}
</div>
</td>
<td>
<div className="text-sm text-gray-700">
{alert.detection?.drone_id ? (
<span className="px-2 py-1 bg-purple-50 text-purple-600 rounded text-xs font-mono">
{alert.detection.drone_id}
</span>
) : (
<span className="text-gray-400 text-sm">{t('alerts.na')}</span>
)}
</div>
</td>
<td>
{alert.detection_id ? (
<button
onClick={() => handleViewDetection(alert.detection_id)}
className="text-blue-500 hover:text-blue-700 text-sm underline"
>
{t('alerts.viewDetails')}
</button>
) : (
<span className="text-gray-400 text-sm">{t('alerts.na')}</span>
)}
</td>
<td>
<div className="text-sm text-gray-700 max-w-xs overflow-hidden">
<div className="truncate" title={alert.message}>
{alert.message}
</div>
</div>
</td>
<td>
<div className="text-sm text-gray-700">
{format(new Date(alert.sent_at), 'MMM dd, HH:mm')}
</div>
</td>
<td>
<div className="text-xs text-gray-400 font-mono">
{alert.alert_event_id ? (
<span title={alert.alert_event_id}>
{alert.alert_event_id.substring(0, 8)}...
</span>
) : (
<span>-</span>
)}
</div>
</td>
</tr>
))}
</React.Fragment>
);
})}
</tbody>
</table>
</div>