feat(route-optimizer): add Home to Jumphost candidate display and probability metrics in route optimization UI
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m54s

This commit is contained in:
2026-03-05 10:28:16 +07:00
parent 8012968ab5
commit 79828eace9
+58
View File
@@ -92,7 +92,11 @@ export default function RouteOptimizerPage() {
<div className="row g-3">
{homes.map((entry) => {
const best = entry.bestFullRoute;
const bestHomeToJh = entry.bestHomeToJumphost || null;
const home = entry.home || {};
const hjCandidates = Array.isArray(entry.homeToJumphostCandidates)
? entry.homeToJumphostCandidates
: [];
const routes = Array.isArray(entry.fullRouteCandidates) ? entry.fullRouteCandidates : [];
return (
<div className="col-12" key={home.id || home.ip || home.dns || home.label || 'home'}>
@@ -113,6 +117,59 @@ export default function RouteOptimizerPage() {
)}
</div>
<div className="card-body">
<div className="mb-4">
<div className="d-flex flex-wrap align-items-center justify-content-between gap-2 mb-2">
<div className="fw-semibold">Оптимальный маршрут Home Jumphost</div>
{bestHomeToJh ? (
<MetricBadge
label="Вероятность оптимальности"
value={`${bestHomeToJh.probabilityOptimal}%`}
tone="green"
/>
) : (
<MetricBadge label="Статус" value="Нет кандидатов Home→Jumphost" tone="orange" />
)}
</div>
<div className="table-responsive">
<table className="table table-vcenter card-table">
<thead>
<tr>
<th>Jumphost</th>
<th>Интерфейс</th>
<th>Ping / Speed</th>
<th>Score / Confidence</th>
<th>Вероятность</th>
</tr>
</thead>
<tbody>
{hjCandidates.length === 0 ? (
<tr>
<td colSpan={5} className="text-muted">
Кандидаты HomeJumphost не найдены.
</td>
</tr>
) : hjCandidates.map((c) => (
<tr key={c.id}>
<td className="fw-semibold">{c.jumphost?.label || c.jumphost?.dns || c.jumphost?.ip || 'jumphost'}</td>
<td className="small text-muted">{c.interfaceName || '—'}</td>
<td className="small text-muted">
ping: {c.pingMs ?? '—'} ms, speed: {c.speedMbps ?? '—'} Mbps
</td>
<td className="small">
{c.score} / {c.confidence}
</td>
<td>
<span className={`badge ${bestHomeToJh?.id === c.id ? 'bg-green-lt text-green' : 'bg-secondary-lt text-secondary'}`}>
{fmtProb(c.probabilityOptimal)}
</span>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
{best ? (
<div className="mb-3">
<div className="fw-semibold mb-2">Оптимальный маршрут</div>
@@ -128,6 +185,7 @@ export default function RouteOptimizerPage() {
</div>
) : null}
<div className="fw-semibold mb-2">Полные маршруты Home Jumphost Exit</div>
<div className="table-responsive">
<table className="table table-vcenter card-table">
<thead>