refactor(MikrotikTools): improve table layout and enhance row display with severity indicators for traceroute results
Publish Fast Tabler Docker image / build-and-push-fast (push) Failing after 3m18s

This commit is contained in:
2026-02-12 22:22:53 +07:00
parent 2d6c90ab31
commit dd089453bc
+99 -18
View File
@@ -464,15 +464,15 @@ function MikrotikTools() {
</div>
) : (
<div className="table-responsive">
<table className="table table-sm table-hover table-striped mb-0">
<table className="table table-vcenter card-table table-hover mb-0">
<thead>
<tr>
<th style={{ width: 60 }}>Хоп</th>
<th style={{ width: 70 }}>Хоп</th>
<th>Адрес / узел</th>
<th style={{ width: 120 }}>Среднее, мс</th>
<th style={{ width: 120 }}>Мин / Макс, мс</th>
<th style={{ width: 100 }}>Потери</th>
<th style={{ width: 160 }}>Статус</th>
<th style={{ width: 130 }}>Среднее, мс</th>
<th style={{ width: 140 }}>Мин / Макс, мс</th>
<th style={{ width: 110 }}>Потери</th>
<th style={{ width: 200 }}>Статус</th>
</tr>
</thead>
<tbody>
@@ -488,19 +488,100 @@ function MikrotikTools() {
mainLabel = ip || dns || h.host || '—';
}
const avg = typeof h.avgMs === 'number' ? h.avgMs : null;
const loss = typeof h.loss === 'number' ? h.loss : null;
const statusRaw = (h.status || '').toString();
const statusLower = statusRaw.toLowerCase();
const hasTimeout =
statusLower.includes('timeout') ||
statusLower.includes('no reply') ||
statusLower.includes('unreachable');
let severity = 'ok';
if (hasTimeout || (loss != null && loss >= 50)) {
severity = 'danger';
} else if ((loss != null && loss > 0) || (avg != null && avg > 200)) {
severity = 'warn';
}
const rowClass =
severity === 'danger'
? 'table-danger'
: severity === 'warn'
? 'table-warning'
: '';
return (
<tr key={h.hop || `${ip || h.host}-${Math.random()}`}>
<td>{h.hop}</td>
<td>{mainLabel}</td>
<td>{h.avgMs != null ? h.avgMs.toFixed(1) : '—'}</td>
<td>
{h.bestMs != null ? h.bestMs.toFixed(1) : '—'} /{' '}
{h.worstMs != null ? h.worstMs.toFixed(1) : '—'}
</td>
<td>{h.loss != null ? `${h.loss}%` : '—'}</td>
<td>{h.status || '—'}</td>
</tr>
);})}
<tr key={h.hop || `${ip || h.host}-${Math.random()}`} className={rowClass}>
<td>
<span className="badge bg-blue-lt text-blue">
{h.hop}
</span>
</td>
<td>
<div className="d-flex flex-column">
<span className="fw-semibold text-truncate" title={mainLabel}>
{mainLabel}
</span>
{ip && dns && (
<span className="text-muted small text-truncate" title={ip}>
IP: {ip}
</span>
)}
</div>
</td>
<td>
{avg != null ? (
<span
className={
avg > 200
? 'text-danger fw-semibold'
: avg > 120
? 'text-warning fw-semibold'
: ''
}
>
{avg.toFixed(1)}
</span>
) : (
'—'
)}
</td>
<td>
{h.bestMs != null ? h.bestMs.toFixed(1) : '—'} /{' '}
{h.worstMs != null ? h.worstMs.toFixed(1) : '—'}
</td>
<td>
{loss != null ? (
<span
className={
loss >= 50
? 'badge bg-red-lt text-red'
: loss > 0
? 'badge bg-yellow-lt text-yellow'
: 'badge bg-green-lt text-green'
}
>
{loss}%
</span>
) : (
'—'
)}
</td>
<td>
{severity === 'danger' && (
<span className="badge bg-red-lt text-red me-1">Проблемный хоп</span>
)}
{severity === 'warn' && (
<span className="badge bg-yellow-lt text-yellow me-1">Возможная проблема</span>
)}
<span className="text-muted small">
{statusRaw || (loss != null || avg != null ? 'OK' : '—')}
</span>
</td>
</tr>
);
})}
</tbody>
</table>
</div>