Commit c3468ac8 authored by Vitaly Lipatov's avatar Vitaly Lipatov

web-api: vertical gateway table, show availability first

Reorder check results: gateways first, then IPs, routes, whois. Change gateway layout from horizontal badges to vertical list. Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 730ded05
......@@ -772,9 +772,9 @@ HTML_PAGE = """\
border-top-color: #3498db; border-radius: 50%; vertical-align: middle;
margin-left: 8px; animation: spin 0.8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.check-gateways { display: flex; flex-wrap: wrap; gap: 6px; }
.check-gateways { display: flex; flex-direction: column; gap: 2px; }
.check-gw { padding: 4px 10px; border-radius: 4px; font-family: monospace;
font-size: 0.85em; }
font-size: 0.85em; display: block; }
.check-gw.ok { background: #d4edda; color: #155724; }
.check-gw.slow { background: #f8d7da; color: #721c24; }
.check-gw.block { background: #f8d7da; color: #721c24; }
......@@ -1109,35 +1109,7 @@ function renderCheck(data) {
const container = $('check-gateways');
container.textContent = '';
// IPs
if (data.ips && data.ips.length) {
const sec = mkDiv('check-section');
sec.appendChild(mkDiv('check-section-title', 'IP-\\u0430\\u0434\\u0440\\u0435\\u0441\\u0430'));
sec.appendChild(mkDiv('check-ips', data.ips.join(', ')));
container.appendChild(sec);
}
// Routes — group by group/list, one line per list
const rsec = mkDiv('check-section');
rsec.appendChild(mkDiv('check-section-title', '\\u0412 \\u0441\\u043f\\u0438\\u0441\\u043a\\u0430\\u0445 \\u043c\\u0430\\u0440\\u0448\\u0440\\u0443\\u0442\\u043e\\u0432'));
if (data.routes && data.routes.length) {
const byList = {};
data.routes.forEach(r => {
const key = r.group + '/' + r.list;
if (!byList[key]) byList[key] = [];
byList[key].push(r.ip ? r.ip + ' \\u2208 ' + r.entry : r.entry);
});
for (const [key, items] of Object.entries(byList)) {
const unique = [...new Set(items)];
const el = mkDiv('check-route', key + ': ' + unique.join(', '));
rsec.appendChild(el);
}
} else {
rsec.appendChild(mkDiv('check-no-route', '\\u041d\\u0435 \\u043d\\u0430\\u0439\\u0434\\u0435\\u043d\\u043e \\u0432 \\u0441\\u043f\\u0438\\u0441\\u043a\\u0430\\u0445 \\u043c\\u0430\\u0440\\u0448\\u0440\\u0443\\u0442\\u043e\\u0432'));
}
container.appendChild(rsec);
// Gateways (IPv4 + IPv6) — only when checks data present (domain mode)
// 1. Gateways (IPv4 + IPv6) — first, only when checks data present (domain mode)
if (data.checks && Object.keys(data.checks).length) {
const thr = data.throttle || {};
const spd = data.speed || {};
......@@ -1194,7 +1166,35 @@ function renderCheck(data) {
}
}
// Whois
// 2. IPs
if (data.ips && data.ips.length) {
const sec = mkDiv('check-section');
sec.appendChild(mkDiv('check-section-title', 'IP-\\u0430\\u0434\\u0440\\u0435\\u0441\\u0430'));
sec.appendChild(mkDiv('check-ips', data.ips.join(', ')));
container.appendChild(sec);
}
// 3. Routes — group by group/list, one line per list
const rsec = mkDiv('check-section');
rsec.appendChild(mkDiv('check-section-title', '\\u0412 \\u0441\\u043f\\u0438\\u0441\\u043a\\u0430\\u0445 \\u043c\\u0430\\u0440\\u0448\\u0440\\u0443\\u0442\\u043e\\u0432'));
if (data.routes && data.routes.length) {
const byList = {};
data.routes.forEach(r => {
const key = r.group + '/' + r.list;
if (!byList[key]) byList[key] = [];
byList[key].push(r.ip ? r.ip + ' \\u2208 ' + r.entry : r.entry);
});
for (const [key, items] of Object.entries(byList)) {
const unique = [...new Set(items)];
const el = mkDiv('check-route', key + ': ' + unique.join(', '));
rsec.appendChild(el);
}
} else {
rsec.appendChild(mkDiv('check-no-route', '\\u041d\\u0435 \\u043d\\u0430\\u0439\\u0434\\u0435\\u043d\\u043e \\u0432 \\u0441\\u043f\\u0438\\u0441\\u043a\\u0430\\u0445 \\u043c\\u0430\\u0440\\u0448\\u0440\\u0443\\u0442\\u043e\\u0432'));
}
container.appendChild(rsec);
// 4. Whois
if (data.whois && data.whois.length) {
const wsec = mkDiv('check-section');
wsec.appendChild(mkDiv('check-section-title', 'WHOIS'));
......@@ -1259,7 +1259,8 @@ async function checkDomain() {
speedWrap = document.createElement('div');
speedWrap.className = 'check-gateways';
speedSection.appendChild(speedWrap);
$('check-gateways').appendChild(speedSection);
const cg = $('check-gateways');
cg.insertBefore(speedSection, cg.firstChild);
}
} else if (evType === 'speed' && speedWrap) {
const gw = parsed.gateway;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment