This commit is contained in:
Name committed 2026-04-19 14:58:25 -06:00
1 parent 6ef3abe393
commit ab7c9531ae
2 files changed
+204 -2

No files matched your search

@@ -1580,6 +1580,38 @@ let topAsnSortColumn = 'rate';
let topAsnSortDirection = 'desc';
let trafficCurrentPage = 1;
let trafficPageSize = DEFAULT_TRAFFIC_PAGE_SIZE;
const TOP_ASN_TABLE_COLUMNS = [
{ group: "attribution" },
{ group: "attribution" },
{ group: "rates", numeric: true },
{ group: "rates", numeric: true },
{ group: "quality", numeric: true },
{ group: "quality", numeric: true },
{ group: "quality", numeric: true },
{ group: "quality", numeric: true },
{ group: "quality", numeric: true },
{ group: "quality", numeric: true },
{ group: "flows", numeric: true },
];
const TRAFFIC_TABLE_COLUMNS = [
{ group: "identity" },
{ group: "rates", numeric: true },
{ group: "rates", numeric: true },
{ group: "volume", numeric: true },
{ group: "volume", numeric: true },
{ group: "volume", numeric: true },
{ group: "volume", numeric: true },
{ group: "quality", numeric: true },
{ group: "quality", numeric: true },
{ group: "quality", numeric: true },
{ group: "quality", numeric: true },
{ group: "quality", numeric: true },
{ group: "quality", numeric: true },
{ group: "attribution" },
{ group: "attribution" },
{ group: "attribution" },
{ group: "actions", action: true },
];
function formatQooScore(score0to100, fallback = "-") {
if (score0to100 === null || score0to100 === undefined) {
@@ -1630,6 +1662,106 @@ function truncatedTrafficCell(text, cellClass) {
return td;
}
function applyCircuitTableCellChrome(cell, columns, startIndex, endIndex) {
const descriptor = columns[startIndex];
if (!descriptor) {
return;
}
const group = String(descriptor.group || "default");
cell.classList.add("lqos-circuit-table-cell", `lqos-circuit-colgroup-${group}`);
if (descriptor.numeric) {
cell.classList.add("lqos-circuit-cell-numeric");
}
if (descriptor.action) {
cell.classList.add("lqos-circuit-cell-action");
}
if (startIndex > 0 && columns[startIndex - 1]?.group !== group) {
cell.classList.add("lqos-circuit-col-start");
}
if (endIndex < columns.length - 1 && columns[endIndex + 1]?.group !== group) {
cell.classList.add("lqos-circuit-col-end");
}
cell.dataset.columnStart = String(startIndex);
cell.dataset.columnEnd = String(endIndex);
}
function annotateCircuitDataTable(table, columns) {
const headRow = table.tHead?.rows?.[0];
if (headRow) {
let columnIndex = 0;
Array.from(headRow.cells).forEach((cell) => {
const span = Math.max(1, Number(cell.colSpan) || 1);
const startIndex = columnIndex;
const endIndex = Math.min(columns.length - 1, startIndex + span - 1);
applyCircuitTableCellChrome(cell, columns, startIndex, endIndex);
columnIndex += span;
});
}
Array.from(table.tBodies).forEach((tbody) => {
Array.from(tbody.rows).forEach((row) => {
if (row.cells.length !== columns.length) {
return;
}
Array.from(row.cells).forEach((cell, index) => {
applyCircuitTableCellChrome(cell, columns, index, index);
});
});
});
wireCircuitDataTableHover(table);
}
function wireCircuitDataTableHover(table) {
let activeStart = null;
let activeEnd = null;
const paintRange = (start, end) => {
Array.from(table.querySelectorAll("[data-column-start][data-column-end]")).forEach((cell) => {
const cellStart = Number.parseInt(cell.dataset.columnStart || "", 10);
const cellEnd = Number.parseInt(cell.dataset.columnEnd || "", 10);
const shouldHighlight = Number.isFinite(cellStart)
&& Number.isFinite(cellEnd)
&& cellStart <= end
&& cellEnd >= start;
cell.classList.toggle("is-column-hover", shouldHighlight);
});
};
const clearRange = () => {
activeStart = null;
activeEnd = null;
Array.from(table.querySelectorAll(".is-column-hover")).forEach((cell) => {
cell.classList.remove("is-column-hover");
});
};
table.addEventListener("pointerover", (event) => {
const cell = event.target.closest("th, td");
if (!cell || !table.contains(cell)) {
return;
}
const start = Number.parseInt(cell.dataset.columnStart || "", 10);
const end = Number.parseInt(cell.dataset.columnEnd || "", 10);
if (!Number.isFinite(start) || !Number.isFinite(end)) {
return;
}
if (activeStart === start && activeEnd === end) {
return;
}
activeStart = start;
activeEnd = end;
paintRange(start, end);
});
table.addEventListener("pointerleave", () => {
clearRange();
});
}
function visibleTrafficRows() {
return Array.isArray(latestTrafficPage?.rows) ? latestTrafficPage.rows : [];
}
@@ -1735,7 +1867,7 @@ function renderTopAsnTab() {
tableWrap.classList.add("lqos-table-wrap");
const table = document.createElement("table");
table.classList.add("lqos-table", "lqos-table-tight", "lqos-circuit-traffic-table");
table.classList.add("lqos-table", "lqos-table-tight", "lqos-circuit-traffic-table", "lqos-circuit-data-table");
const thead = document.createElement("thead", "small");
thead.style.fontSize = "0.8em";
@@ -1797,6 +1929,7 @@ function renderTopAsnTab() {
}
table.appendChild(tbody);
annotateCircuitDataTable(table, TOP_ASN_TABLE_COLUMNS);
tableWrap.appendChild(table);
clearDiv(target);
target.appendChild(tableWrap);
@@ -1818,7 +1951,7 @@ function renderTrafficTab() {
tableWrap.classList.add("lqos-table-wrap");
let table = document.createElement("table");
table.classList.add("lqos-table", "lqos-table-tight", "lqos-circuit-traffic-table");
table.classList.add("lqos-table", "lqos-table-tight", "lqos-circuit-traffic-table", "lqos-circuit-data-table");
let thead = document.createElement("thead", "small");
thead.style.fontSize = "0.8em";
@@ -1903,6 +2036,7 @@ function renderTrafficTab() {
}
table.appendChild(tbody);
annotateCircuitDataTable(table, TRAFFIC_TABLE_COLUMNS);
tableWrap.appendChild(table);
clearDiv(target);
target.appendChild(tableWrap);
@@ -1567,6 +1567,74 @@ h5 {
max-width: 100%;
}
.lqos-circuit-data-table th,
.lqos-circuit-data-table td {
--lqos-circuit-group-tint: transparent;
--lqos-circuit-hover-tint: transparent;
background-image:
linear-gradient(var(--lqos-circuit-hover-tint), var(--lqos-circuit-hover-tint)),
linear-gradient(var(--lqos-circuit-group-tint), var(--lqos-circuit-group-tint));
background-clip: padding-box;
transition:
background-color 140ms ease,
border-color 140ms ease,
box-shadow 140ms ease;
}
.lqos-circuit-data-table thead th + th,
.lqos-circuit-data-table tbody td + td {
border-left: 1px solid color-mix(in srgb, var(--lqos-border) 42%, transparent);
}
.lqos-circuit-data-table .lqos-circuit-col-start {
border-left-color: color-mix(in srgb, var(--lqos-border) 92%, transparent);
}
.lqos-circuit-data-table .lqos-circuit-colgroup-identity,
.lqos-circuit-data-table .lqos-circuit-colgroup-actions {
--lqos-circuit-group-tint: color-mix(in srgb, var(--lqos-surface) 14%, transparent);
}
.lqos-circuit-data-table .lqos-circuit-colgroup-rates {
--lqos-circuit-group-tint: color-mix(in srgb, var(--bs-info) 7%, transparent);
}
.lqos-circuit-data-table .lqos-circuit-colgroup-volume {
--lqos-circuit-group-tint: color-mix(in srgb, #d39f37 7%, transparent);
}
.lqos-circuit-data-table .lqos-circuit-colgroup-quality {
--lqos-circuit-group-tint: color-mix(in srgb, #2b8a57 7%, transparent);
}
.lqos-circuit-data-table .lqos-circuit-colgroup-attribution,
.lqos-circuit-data-table .lqos-circuit-colgroup-flows {
--lqos-circuit-group-tint: color-mix(in srgb, var(--bs-secondary-color) 8%, transparent);
}
.lqos-circuit-data-table .lqos-circuit-cell-numeric {
text-align: right;
font-variant-numeric: tabular-nums;
}
.lqos-circuit-data-table .lqos-circuit-cell-action {
text-align: center;
}
.lqos-circuit-data-table .is-column-hover {
--lqos-circuit-hover-tint: rgba(255, 255, 255, 0.035);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.05),
inset 0 0 0 1px color-mix(in srgb, var(--lqos-border) 70%, transparent);
}
[data-bs-theme="light"] .lqos-circuit-data-table .is-column-hover {
--lqos-circuit-hover-tint: rgba(17, 29, 45, 0.045);
box-shadow:
inset 0 1px 0 rgba(255, 255, 255, 0.28),
inset 0 0 0 1px color-mix(in srgb, var(--lqos-border) 74%, transparent);
}
.lqos-tree-stack {
display: flex;
flex-direction: column;