feat(alerts): add tunnel high ping and low speed alert settings with corresponding UI controls
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m55s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m55s
This commit is contained in:
+185
-17
@@ -114,6 +114,11 @@ export default function SettingsPage() {
|
||||
const [alertHighHddEnabled, setAlertHighHddEnabled] = useState(true);
|
||||
const [alertHighHddThreshold, setAlertHighHddThreshold] = useState('90');
|
||||
const [alertHighHddDurationMinutes, setAlertHighHddDurationMinutes] = useState('10');
|
||||
const [alertTunnelHighPingEnabled, setAlertTunnelHighPingEnabled] = useState(false);
|
||||
const [alertTunnelHighPingThresholdMs, setAlertTunnelHighPingThresholdMs] = useState('0');
|
||||
const [alertTunnelLowSpeedEnabled, setAlertTunnelLowSpeedEnabled] = useState(false);
|
||||
const [alertTunnelLowSpeedMinDownload, setAlertTunnelLowSpeedMinDownload] = useState('0');
|
||||
const [alertTunnelLowSpeedMinUpload, setAlertTunnelLowSpeedMinUpload] = useState('0');
|
||||
const [serversList, setServersList] = useState([]);
|
||||
const [sidebarSearch, setSidebarSearch] = useState('');
|
||||
const [activeSection, setActiveSection] = useState(() => {
|
||||
@@ -321,18 +326,49 @@ export default function SettingsPage() {
|
||||
);
|
||||
const a = data?.alertSettings || {};
|
||||
setAlertServerOffline(a.serverOffline?.enabled !== false);
|
||||
setAlertServerOfflineMinutes(a.serverOffline?.offlineMinutes != null ? String(a.serverOffline.offlineMinutes) : '5');
|
||||
setAlertServerOfflineMinutes(
|
||||
a.serverOffline?.offlineMinutes != null ? String(a.serverOffline.offlineMinutes) : '5'
|
||||
);
|
||||
setAlertMikrotikUnreachable(a.mikrotikUnreachable?.enabled !== false);
|
||||
setAlertMikrotikUnreachableMinutes(a.mikrotikUnreachable?.durationMinutes != null ? String(a.mikrotikUnreachable.durationMinutes) : '5');
|
||||
setAlertMikrotikUnreachableMinutes(
|
||||
a.mikrotikUnreachable?.durationMinutes != null
|
||||
? String(a.mikrotikUnreachable.durationMinutes)
|
||||
: '5'
|
||||
);
|
||||
setAlertHighCpuEnabled(a.highCpu?.enabled !== false);
|
||||
setAlertHighCpuThreshold(a.highCpu?.thresholdPercent != null ? String(a.highCpu.thresholdPercent) : '85');
|
||||
setAlertHighCpuDurationMinutes(a.highCpu?.durationMinutes != null ? String(a.highCpu.durationMinutes) : '10');
|
||||
setAlertHighCpuThreshold(
|
||||
a.highCpu?.thresholdPercent != null ? String(a.highCpu.thresholdPercent) : '85'
|
||||
);
|
||||
setAlertHighCpuDurationMinutes(
|
||||
a.highCpu?.durationMinutes != null ? String(a.highCpu.durationMinutes) : '10'
|
||||
);
|
||||
setAlertHighRamEnabled(a.highRam?.enabled !== false);
|
||||
setAlertHighRamThreshold(a.highRam?.thresholdPercent != null ? String(a.highRam.thresholdPercent) : '85');
|
||||
setAlertHighRamDurationMinutes(a.highRam?.durationMinutes != null ? String(a.highRam.durationMinutes) : '10');
|
||||
setAlertHighRamThreshold(
|
||||
a.highRam?.thresholdPercent != null ? String(a.highRam.thresholdPercent) : '85'
|
||||
);
|
||||
setAlertHighRamDurationMinutes(
|
||||
a.highRam?.durationMinutes != null ? String(a.highRam.durationMinutes) : '10'
|
||||
);
|
||||
setAlertHighHddEnabled(a.highHdd?.enabled !== false);
|
||||
setAlertHighHddThreshold(a.highHdd?.thresholdPercent != null ? String(a.highHdd.thresholdPercent) : '90');
|
||||
setAlertHighHddDurationMinutes(a.highHdd?.durationMinutes != null ? String(a.highHdd.durationMinutes) : '10');
|
||||
setAlertHighHddThreshold(
|
||||
a.highHdd?.thresholdPercent != null ? String(a.highHdd.thresholdPercent) : '90'
|
||||
);
|
||||
setAlertHighHddDurationMinutes(
|
||||
a.highHdd?.durationMinutes != null ? String(a.highHdd.durationMinutes) : '10'
|
||||
);
|
||||
setAlertTunnelHighPingEnabled(a.tunnelHighPing?.enabled === true);
|
||||
setAlertTunnelHighPingThresholdMs(
|
||||
a.tunnelHighPing?.thresholdMs != null ? String(a.tunnelHighPing.thresholdMs) : '0'
|
||||
);
|
||||
setAlertTunnelLowSpeedEnabled(a.tunnelLowSpeed?.enabled === true);
|
||||
setAlertTunnelLowSpeedMinDownload(
|
||||
a.tunnelLowSpeed?.minDownloadMbps != null
|
||||
? String(a.tunnelLowSpeed.minDownloadMbps)
|
||||
: '0'
|
||||
);
|
||||
setAlertTunnelLowSpeedMinUpload(
|
||||
a.tunnelLowSpeed?.minUploadMbps != null ? String(a.tunnelLowSpeed.minUploadMbps) : '0'
|
||||
);
|
||||
const e =
|
||||
settingsRes?.headers?.etag || settingsRes?.headers?.ETag || '';
|
||||
setEtag(e ? String(e) : '');
|
||||
@@ -447,29 +483,71 @@ export default function SettingsPage() {
|
||||
interfaceName: p.interfaceName,
|
||||
}))
|
||||
: [],
|
||||
alertSettings: {
|
||||
alertSettings: {
|
||||
serverOffline: {
|
||||
enabled: alertServerOffline,
|
||||
offlineMinutes: Math.max(1, Math.min(1440, parseInt(alertServerOfflineMinutes, 10) || 5)),
|
||||
offlineMinutes: Math.max(
|
||||
1,
|
||||
Math.min(1440, parseInt(alertServerOfflineMinutes, 10) || 5)
|
||||
),
|
||||
},
|
||||
mikrotikUnreachable: {
|
||||
enabled: alertMikrotikUnreachable,
|
||||
durationMinutes: Math.max(1, Math.min(1440, parseInt(alertMikrotikUnreachableMinutes, 10) || 5)),
|
||||
durationMinutes: Math.max(
|
||||
1,
|
||||
Math.min(1440, parseInt(alertMikrotikUnreachableMinutes, 10) || 5)
|
||||
),
|
||||
},
|
||||
highCpu: {
|
||||
enabled: alertHighCpuEnabled,
|
||||
thresholdPercent: Math.max(1, Math.min(100, parseInt(alertHighCpuThreshold, 10) || 85)),
|
||||
durationMinutes: Math.max(1, Math.min(1440, parseInt(alertHighCpuDurationMinutes, 10) || 10)),
|
||||
thresholdPercent: Math.max(
|
||||
1,
|
||||
Math.min(100, parseInt(alertHighCpuThreshold, 10) || 85)
|
||||
),
|
||||
durationMinutes: Math.max(
|
||||
1,
|
||||
Math.min(1440, parseInt(alertHighCpuDurationMinutes, 10) || 10)
|
||||
),
|
||||
},
|
||||
highRam: {
|
||||
enabled: alertHighRamEnabled,
|
||||
thresholdPercent: Math.max(1, Math.min(100, parseInt(alertHighRamThreshold, 10) || 85)),
|
||||
durationMinutes: Math.max(1, Math.min(1440, parseInt(alertHighRamDurationMinutes, 10) || 10)),
|
||||
thresholdPercent: Math.max(
|
||||
1,
|
||||
Math.min(100, parseInt(alertHighRamThreshold, 10) || 85)
|
||||
),
|
||||
durationMinutes: Math.max(
|
||||
1,
|
||||
Math.min(1440, parseInt(alertHighRamDurationMinutes, 10) || 10)
|
||||
),
|
||||
},
|
||||
highHdd: {
|
||||
enabled: alertHighHddEnabled,
|
||||
thresholdPercent: Math.max(1, Math.min(100, parseInt(alertHighHddThreshold, 10) || 90)),
|
||||
durationMinutes: Math.max(1, Math.min(1440, parseInt(alertHighHddDurationMinutes, 10) || 10)),
|
||||
thresholdPercent: Math.max(
|
||||
1,
|
||||
Math.min(100, parseInt(alertHighHddThreshold, 10) || 90)
|
||||
),
|
||||
durationMinutes: Math.max(
|
||||
1,
|
||||
Math.min(1440, parseInt(alertHighHddDurationMinutes, 10) || 10)
|
||||
),
|
||||
},
|
||||
tunnelHighPing: {
|
||||
enabled: alertTunnelHighPingEnabled,
|
||||
thresholdMs: Math.max(
|
||||
1,
|
||||
Math.min(5000, parseInt(alertTunnelHighPingThresholdMs, 10) || 0)
|
||||
),
|
||||
},
|
||||
tunnelLowSpeed: {
|
||||
enabled: alertTunnelLowSpeedEnabled,
|
||||
minDownloadMbps: Math.max(
|
||||
0,
|
||||
Math.min(10000, parseInt(alertTunnelLowSpeedMinDownload, 10) || 0)
|
||||
),
|
||||
minUploadMbps: Math.max(
|
||||
0,
|
||||
Math.min(10000, parseInt(alertTunnelLowSpeedMinUpload, 10) || 0)
|
||||
),
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1320,6 +1398,96 @@ export default function SettingsPage() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Пинг по туннелям (карта сети) */}
|
||||
<div className="list-group-item d-flex flex-column flex-md-row align-items-stretch align-items-md-center gap-3 py-3">
|
||||
<div className="flex-grow-1 min-w-0">
|
||||
<div className="fw-semibold">Пинг по туннелям</div>
|
||||
<div className="text-muted small">
|
||||
Срабатывает, если средний пинг по туннелю на карте сети превышает указанный порог.
|
||||
Применяется ко всем туннелям из раздела «Сетевые настройки».
|
||||
</div>
|
||||
</div>
|
||||
<div className="d-flex flex-wrap align-items-center gap-2">
|
||||
<div className="input-group input-group-sm" style={{ width: 110 }}>
|
||||
<input
|
||||
type="number"
|
||||
className="form-control"
|
||||
min={1}
|
||||
max={5000}
|
||||
value={alertTunnelHighPingThresholdMs}
|
||||
onChange={(e) => setAlertTunnelHighPingThresholdMs(e.target.value)}
|
||||
disabled={saving || !alertTunnelHighPingEnabled}
|
||||
/>
|
||||
<span className="input-group-text">ms</span>
|
||||
</div>
|
||||
<div className="form-check form-switch mb-0">
|
||||
<input
|
||||
className="form-check-input"
|
||||
type="checkbox"
|
||||
id="alertTunnelHighPingEnabled"
|
||||
checked={alertTunnelHighPingEnabled}
|
||||
onChange={(e) => setAlertTunnelHighPingEnabled(e.target.checked)}
|
||||
disabled={saving}
|
||||
/>
|
||||
<label className="form-check-label small" htmlFor="alertTunnelHighPingEnabled">
|
||||
Вкл
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Скорость по туннелям (карта сети) */}
|
||||
<div className="list-group-item d-flex flex-column flex-md-row align-items-stretch align-items-md-center gap-3 py-3">
|
||||
<div className="flex-grow-1 min-w-0">
|
||||
<div className="fw-semibold">Скорость по туннелям</div>
|
||||
<div className="text-muted small">
|
||||
Срабатывает, если измеренная скорость по туннелю (download и/или upload) ниже указанных
|
||||
порогов. Используются последние результаты планировщика карты сети.
|
||||
</div>
|
||||
</div>
|
||||
<div className="d-flex flex-wrap align-items-center gap-2">
|
||||
<div className="input-group input-group-sm" style={{ width: 130 }}>
|
||||
<span className="input-group-text">↓</span>
|
||||
<input
|
||||
type="number"
|
||||
className="form-control"
|
||||
min={0}
|
||||
max={10000}
|
||||
value={alertTunnelLowSpeedMinDownload}
|
||||
onChange={(e) => setAlertTunnelLowSpeedMinDownload(e.target.value)}
|
||||
disabled={saving || !alertTunnelLowSpeedEnabled}
|
||||
/>
|
||||
<span className="input-group-text">Мбит/с</span>
|
||||
</div>
|
||||
<div className="input-group input-group-sm" style={{ width: 130 }}>
|
||||
<span className="input-group-text">↑</span>
|
||||
<input
|
||||
type="number"
|
||||
className="form-control"
|
||||
min={0}
|
||||
max={10000}
|
||||
value={alertTunnelLowSpeedMinUpload}
|
||||
onChange={(e) => setAlertTunnelLowSpeedMinUpload(e.target.value)}
|
||||
disabled={saving || !alertTunnelLowSpeedEnabled}
|
||||
/>
|
||||
<span className="input-group-text">Мбит/с</span>
|
||||
</div>
|
||||
<div className="form-check form-switch mb-0">
|
||||
<input
|
||||
className="form-check-input"
|
||||
type="checkbox"
|
||||
id="alertTunnelLowSpeedEnabled"
|
||||
checked={alertTunnelLowSpeedEnabled}
|
||||
onChange={(e) => setAlertTunnelLowSpeedEnabled(e.target.checked)}
|
||||
disabled={saving}
|
||||
/>
|
||||
<label className="form-check-label small" htmlFor="alertTunnelLowSpeedEnabled">
|
||||
Вкл
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user