diff --git a/static/js/pages/bgp.js b/static/js/pages/bgp.js index cebdf08..2c4c356 100644 --- a/static/js/pages/bgp.js +++ b/static/js/pages/bgp.js @@ -1,141 +1,154 @@ function filterTable(searchInputId, tableId) { - const filter = document.getElementById(searchInputId).value.toUpperCase(); - const rows = document.getElementById(tableId).getElementsByTagName("tr"); + 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; - } - } + 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); + 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")); + 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 : ""; + 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); - return newState === "asc" ? cmp : -cmp; - }); - } - rows.forEach(r => tbody.appendChild(r)); + 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"); + 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(); + try { + const res = await fetch("/bgp/json"); + const data = await res.json(); - ipv4Sum.innerHTML = summaryHtml(data.ipv4_info); - ipv6Sum.innerHTML = summaryHtml(data.ipv6_info); + ipv4Sum.innerHTML = buildSummary("IPv4", data.ipv4_info); + ipv6Sum.innerHTML = buildSummary("IPv6", data.ipv6_info); - renderPeers(ipv4Body, data.ipv4_peers, "ipv4Table"); - renderPeers(ipv6Body, data.ipv6_peers, "ipv6Table"); + renderPeers(ipv4Body, data.ipv4_peers); + renderPeers(ipv6Body, data.ipv6_peers); - bootstrap.Popover.getInstance(document.body)?.dispose?.(); - document.querySelectorAll('[data-bs-toggle="popover"]').forEach(el => new bootstrap.Popover(el)); - - } catch (e) { - showError(ipv4Sum, ipv4Body, "IPv4"); - showError(ipv6Sum, ipv6Body, "IPv6"); - } + activatePopovers(); + } catch (e) { + showError(ipv4Sum, ipv4Body, "IPv4"); + showError(ipv6Sum, ipv6Body, "IPv6"); + } } -function summaryHtml(info) { - return ` -

BGP Router ID: ${info.router_id}, - Local AS: ${info.local_as}, - VRF ID: ${info.vrf_id}

-

${info.rib_entries} RIB Entries, using ${info.rib_memory}

-

${info.peers} Peers, using ${info.peers_memory}

-

BGP Table Version: ${info.table_version}

+function buildSummary(label, info) { + const popContent = ` + BGP Router ID: ${info.router_id}
+ Local AS: ${info.local_as}
+ VRF ID: ${info.vrf_id}
+ RIB Entries: ${info.rib_entries} (using ${info.rib_memory})
+ Peers: ${info.peers}, using ${info.peers_memory}
+ BGP Table Version: ${info.table_version} + `.trim(); + + return ` +

${label} Unicast Summary

+ + ℹ️ + +
Peers: ${info.peers}
+ `; +} + + +function renderPeers(tbody, peers) { + tbody.innerHTML = ""; + if (!peers.length) { + tbody.innerHTML = `No data available.`; + return; + } + + peers.forEach((p, i) => { + const popTitle = `${p.as_number} details`; + const popContent = ` + Messages Received: ${p.msg_received}
+ Messages Sent: ${p.msg_sent}
+ Inbound Q: ${p.in_queue}
+ Outbound Q: ${p.out_queue} + `.trim(); + + const tr = document.createElement("tr"); + tr.dataset.index = i; + tr.innerHTML = ` + ${p.neighbor} +
${p.as_number} + ${p.up_down} + ${p.state_pfx_rcd} + ${p.prefix_sent} + ${p.description} + + + ℹ️ + + `; + tbody.appendChild(tr); + }); } -function renderPeers(tbody, peers, tableId) { - tbody.innerHTML = ""; - if (!peers.length) { - tbody.innerHTML = `No data available.`; - return; - } - - peers.forEach((p, i) => { - const popTitle = - `${p.as_number} details`; - - const popContent = ` - Messages Received: ${p.msg_received}
- Messages Sent: ${p.msg_sent}
- Inbound Queue: ${p.in_queue}
- Outbound Queue: ${p.out_queue} - `.trim(); - - const tr = document.createElement("tr"); - tr.dataset.index = i; - tr.innerHTML = ` - ${p.neighbor} -
${p.as_number} - ${p.up_down} - ${p.state_pfx_rcd} - ${p.prefix_sent} - ${p.description} - - - ℹ️ - - - `; - tbody.appendChild(tr); - }); +function activatePopovers() { + document.querySelectorAll('[data-bs-toggle="popover"]').forEach(el => { + const existing = bootstrap.Popover.getInstance(el); + if (existing) existing.dispose(); + new bootstrap.Popover(el); + }); } - function showError(sumEl, bodyEl, label) { - sumEl.textContent = `Error fetching ${label} data.`; - bodyEl.innerHTML = `Error retrieving data.`; + sumEl.textContent = `Error fetching ${label} data.`; + bodyEl.innerHTML = `Error retrieving data.`; } function refreshBGPTable() { - ["ipv4Search", "ipv6Search"].forEach(id => (document.getElementById(id).value = "")); - toggleRefresh(true); - loadBgpTables().finally(() => toggleRefresh(false)); + ["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.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); \ No newline at end of file