174 lines
No EOL
6.4 KiB
JavaScript
174 lines
No EOL
6.4 KiB
JavaScript
function filterTable(searchInputId, tableId) {
|
||
const filter = document.getElementById(searchInputId).value.toUpperCase();
|
||
const rows = document.getElementById(tableId).getElementsByTagName("tr");
|
||
|
||
for (let i = 1; i < rows.length; i++) {
|
||
rows[i].style.display = "none";
|
||
for (const cell of rows[i].getElementsByTagName("td")) {
|
||
if ((cell.textContent || cell.innerText).toUpperCase().includes(filter)) {
|
||
rows[i].style.display = "";
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
function sortTable(tableId, columnIndex, th) {
|
||
const tbody = document.getElementById(tableId).tBodies[0];
|
||
const rows = Array.from(tbody.rows);
|
||
const headers = Array.from(th.parentNode.children);
|
||
|
||
headers.forEach(h => h !== th && (h.className = "", h.dataset.sortState = "none"));
|
||
|
||
const state = th.dataset.sortState || "none";
|
||
const newState = state === "none" ? "asc" : state === "asc" ? "desc" : "none";
|
||
th.dataset.sortState = newState;
|
||
th.className = newState !== "none" ? newState : "";
|
||
|
||
if (newState === "none") {
|
||
rows.sort((a, b) => a.dataset.index - b.dataset.index);
|
||
} else {
|
||
rows.sort((a, b) => {
|
||
const aTxt = a.cells[columnIndex].textContent.trim();
|
||
const bTxt = b.cells[columnIndex].textContent.trim();
|
||
const aNum = parseFloat(aTxt.replace(/[^0-9.-]/g, ""));
|
||
const bNum = parseFloat(bTxt.replace(/[^0-9.-]/g, ""));
|
||
const numeric = !isNaN(aNum) && !isNaN(bNum);
|
||
const cmp = numeric ? aNum - bNum : aTxt.localeCompare(bTxt, undefined, { numeric: true });
|
||
return newState === "asc" ? cmp : -cmp;
|
||
});
|
||
}
|
||
rows.forEach(r => tbody.appendChild(r));
|
||
}
|
||
|
||
async function loadBgpTables() {
|
||
const ipv4Sum = document.getElementById("ipv4Summary");
|
||
const ipv6Sum = document.getElementById("ipv6Summary");
|
||
const ipv4Body = document.getElementById("ipv4TableBody");
|
||
const ipv6Body = document.getElementById("ipv6TableBody");
|
||
|
||
try {
|
||
const res = await fetch("/bgp/json");
|
||
const data = await res.json();
|
||
|
||
ipv4Sum.innerHTML = buildSummary("IPv4", data.ipv4_info);
|
||
ipv6Sum.innerHTML = buildSummary("IPv6", data.ipv6_info);
|
||
|
||
const bfdPeersSet = new Set(data.bfd_peers);
|
||
|
||
renderPeers(ipv4Body, data.ipv4_peers, bfdPeersSet);
|
||
renderPeers(ipv6Body, data.ipv6_peers, bfdPeersSet);
|
||
|
||
activatePopovers();
|
||
} catch (e) {
|
||
showError(ipv4Sum, ipv4Body, "IPv4");
|
||
showError(ipv6Sum, ipv6Body, "IPv6");
|
||
}
|
||
}
|
||
|
||
function buildSummary(label, info) {
|
||
const popContent = `
|
||
<strong>BGP Router ID:</strong> ${info.router_id}<br>
|
||
<strong>Local AS:</strong> <a href='https://bgp.tools/search?q=${info.local_as}' target='_blank'>${info.local_as}</a><br>
|
||
<strong>VRF ID:</strong> ${info.vrf_id}<br>
|
||
<strong>RIB Entries:</strong> ${info.rib_entries} (using ${info.rib_memory})<br>
|
||
<strong>Peers:</strong> ${info.peers} (using ${info.peers_memory})<br>
|
||
<strong>BGP Table Version:</strong> ${info.table_version}
|
||
`.trim();
|
||
|
||
return `
|
||
<h2 class="d-inline me-2">${label} Unicast Summary</h2>
|
||
<span tabindex="0" role="button" class="info-icon"
|
||
data-bs-toggle="popover" data-bs-trigger="hover focus"
|
||
data-bs-html="true" data-bs-title="${label} Summary Info"
|
||
data-bs-content="${popContent}">
|
||
ℹ️
|
||
</span>
|
||
<div class="mt-1"><strong>Peers:</strong> ${info.peers}</div>
|
||
`;
|
||
}
|
||
|
||
function renderPeers(tbody, peers, bfdPeersSet) {
|
||
tbody.innerHTML = "";
|
||
if (!peers.length) {
|
||
tbody.innerHTML = `<tr><td colspan="7" class="text-center">No data available.</td></tr>`;
|
||
return;
|
||
}
|
||
|
||
const ip_version = tbody.id.includes('ipv4') ? 'ipv4' : 'ipv6';
|
||
|
||
peers.forEach((p, i) => {
|
||
const popTitle = `<a href="https://bgp.tools/search?q=${p.as_number}" target="_blank" rel="noopener noreferrer">${p.as_number}</a> details<a>`;
|
||
const popContent = `
|
||
Messages Received: ${p.msg_received}<br>
|
||
Messages Sent: ${p.msg_sent}<br>
|
||
Inbound Queue: ${p.in_queue}<br>
|
||
Outbound Queue: ${p.out_queue}
|
||
`.trim();
|
||
|
||
const hasBfd = bfdPeersSet.has(p.neighbor);
|
||
|
||
const tr = document.createElement("tr");
|
||
tr.dataset.index = i;
|
||
tr.innerHTML = `
|
||
<td>${p.neighbor}</td>
|
||
<td><a href="https://bgp.tools/search?q=${p.as_number}" target="_blank">${p.as_number}</a></td>
|
||
<td>${p.up_down}</td>
|
||
<td>${p.state_pfx_rcd}</td>
|
||
<td>${p.prefix_sent}</td>
|
||
<td>${p.description}</td>
|
||
<td class="d-flex justify-content-start">
|
||
<span tabindex="0" role="button" class="icon-info"
|
||
data-bs-toggle="popover" data-bs-trigger="hover focus"
|
||
data-bs-html="true" data-bs-title='${popTitle}'
|
||
data-bs-content="${popContent}">
|
||
</span>
|
||
|
||
<a href="/bgp/neighbor/${ip_version}/${p.neighbor}" class="icon-details" target="_blank" role="button"
|
||
data-bs-toggle="tooltip" data-bs-placement="top" title="Display BGP neighbor details">
|
||
</a>
|
||
|
||
${hasBfd ? `
|
||
<a href="/bfd/peer/${p.neighbor}" class="icon-bfd" target="_blank" role="button"
|
||
data-bs-toggle="tooltip" data-bs-placement="top" title="Display BFD peer details">
|
||
</a>
|
||
` : ''}
|
||
</td>
|
||
`;
|
||
tbody.appendChild(tr);
|
||
});
|
||
}
|
||
|
||
function activatePopovers() {
|
||
const popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
|
||
popoverTriggerList.map(function (popoverTriggerEl) {
|
||
return new bootstrap.Popover(popoverTriggerEl);
|
||
});
|
||
}
|
||
|
||
function activateTooltips() {
|
||
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
||
tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||
return new bootstrap.Tooltip(tooltipTriggerEl);
|
||
});
|
||
}
|
||
|
||
function showError(sumEl, bodyEl, label) {
|
||
sumEl.textContent = `Error fetching ${label} data.`;
|
||
bodyEl.innerHTML = `<tr><td colspan="8" class="text-center text-danger">Error retrieving data.</td></tr>`;
|
||
}
|
||
|
||
function refreshBGPTable() {
|
||
["ipv4Search", "ipv6Search"].forEach(id => (document.getElementById(id).value = ""));
|
||
toggleRefresh(true);
|
||
loadBgpTables().finally(() => toggleRefresh(false));
|
||
}
|
||
|
||
function toggleRefresh(loading) {
|
||
document.getElementById("refreshIcon").classList.toggle("d-none", loading);
|
||
document.getElementById("refreshSpinner").classList.toggle("d-none", !loading);
|
||
document.getElementById("refreshIcon2").classList.toggle("d-none", loading);
|
||
document.getElementById("refreshSpinner2").classList.toggle("d-none", !loading);
|
||
}
|
||
|
||
document.addEventListener("DOMContentLoaded", loadBgpTables); |