Add failover channel events to activity journal
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { assertActivityJournalPage, type ActivityJournalEvent } from '../../../shared/activityJournal.js';
|
||||
import { compactActivityJournalEvents, refreshStreakCopy, type ActivityJournalDisplayItem } from './activityJournalModel.js';
|
||||
import { compactActivityJournalEvents, activityJournalEventCopy, refreshStreakCopy, type ActivityJournalDisplayItem } from './activityJournalModel.js';
|
||||
import { Drawer } from '../../ui/Drawer.js';
|
||||
import { RailAction } from '../../ui/RailAction.js';
|
||||
|
||||
@@ -56,28 +56,19 @@ export function ActivityJournalToggle({ feature, open, onToggle }: {
|
||||
</RailAction>;
|
||||
}
|
||||
|
||||
function eventCopy(event: ActivityJournalEvent) {
|
||||
const value = event.data;
|
||||
const copies: Record<string, [string, string]> = {
|
||||
'connection.started': ['VPN включён', [value.profileLabel, value.serverLabel].filter(Boolean).join(' · ')],
|
||||
'connection.stopped': ['VPN выключен', 'Остановлен пользователем'],
|
||||
'connection.failed': ['VPN не запущен', String(value.errorCode || '')],
|
||||
'subscription.added': ['Подписка добавлена', `${value.profileLabel || ''} · серверов: ${value.serverCount || 0}`],
|
||||
'subscription.refreshed': ['Подписка обновлена', `${value.profileLabel || ''} · серверов: ${value.serverCount || 0} · +${value.added || 0} / −${value.removed || 0}`],
|
||||
'subscription.refresh_failed': ['Подписка не обновлена', `${value.profileLabel || ''} · ${value.errorCode || ''}`],
|
||||
'subscription.deleted': ['Подписка удалена', String(value.profileLabel || '')],
|
||||
'failover.enabled': ['Резервный канал включён', 'Мониторинг начнётся после активации dual-config'],
|
||||
'failover.disabled': ['Резервный канал выключен', 'Автоматика полностью остановлена'],
|
||||
'failover.paused': ['Автопереключение на паузе', 'Проверки продолжаются'],
|
||||
'failover.resumed': ['Автопереключение возобновлено', ''],
|
||||
'failover.waiting_for_idle': ['Переключение отложено', 'Обнаружен активный трафик'],
|
||||
'failover.switched': ['Новые соединения переключены', `${value.fromRole || ''} → ${value.toRole || ''} · ${value.reason || ''}`],
|
||||
'failover.switch_failed': ['Переключение не выполнено', String(value.errorCode || '')],
|
||||
'failover.both_unhealthy': ['Оба канала недоступны', 'Текущий маршрут сохранён'],
|
||||
'failover.recovered': ['Основной канал восстановлен', String(value.reason || '')],
|
||||
'journal.recovered': ['Журнал восстановлен', 'Повреждённый файл сохранён отдельно'],
|
||||
};
|
||||
return copies[event.type] || ['Системное событие', ''];
|
||||
function eventTargetRole(event: ActivityJournalEvent) {
|
||||
if (event.type === 'failover.switched') return event.data.toRole;
|
||||
if (
|
||||
event.type === 'failover.reserve_unavailable'
|
||||
|| event.type === 'failover.reserve_recovered'
|
||||
|| (event.type === 'failover.recovered' && event.data.role === 'reserve')
|
||||
) return 'reserve';
|
||||
if (
|
||||
event.type === 'failover.primary_unavailable'
|
||||
|| event.type === 'failover.primary_recovered'
|
||||
|| (event.type === 'failover.recovered' && event.data.role === 'primary')
|
||||
) return 'primary';
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function dayLabel(value: string) {
|
||||
@@ -155,13 +146,13 @@ export function ActivityJournalPanel({ feature, loadPage }: {
|
||||
<h3>{group.label}</h3>
|
||||
<ol>{group.items.map((item) => {
|
||||
const { event } = item;
|
||||
const [title, details] = refreshStreakCopy(item) || eventCopy(event);
|
||||
const [title, details] = refreshStreakCopy(item) || activityJournalEventCopy(event);
|
||||
return <li
|
||||
key={event.id}
|
||||
className="client-journal-event"
|
||||
data-event-type={event.type}
|
||||
data-severity={event.severity}
|
||||
data-target-role={event.type === 'failover.switched' ? event.data.toRole : undefined}
|
||||
data-target-role={eventTargetRole(event)}
|
||||
>
|
||||
<div className="client-journal-time"><time dateTime={event.occurredAt}>{new Intl.DateTimeFormat('ru-RU', { hour: '2-digit', minute: '2-digit' }).format(new Date(event.occurredAt))}</time><span>{event.source}</span></div>
|
||||
<div><strong>{title}</strong>{details && <span>{details}</span>}{event.severity !== 'info' && <em>{event.severity === 'error' ? 'Ошибка' : 'Внимание'}</em>}</div>
|
||||
|
||||
Reference in New Issue
Block a user