mirror of
https://github.com/pablorevilla-meshtastic/meshview.git
synced 2026-03-04 23:27:46 +01:00
fixing node graph selector
This commit is contained in:
14
dbcleanup.log
Normal file
14
dbcleanup.log
Normal file
@@ -0,0 +1,14 @@
|
||||
2025-10-14 20:13:45,221 [INFO] Daily cleanup is disabled by configuration.
|
||||
2025-10-14 20:25:47,645 [INFO] Daily cleanup is disabled by configuration.
|
||||
2025-10-14 20:34:48,026 [INFO] Daily cleanup is disabled by configuration.
|
||||
2025-10-14 21:11:16,069 [INFO] Daily cleanup is disabled by configuration.
|
||||
2025-10-14 21:19:58,777 [INFO] Daily cleanup is disabled by configuration.
|
||||
2025-10-14 21:20:29,595 [INFO] Daily cleanup is disabled by configuration.
|
||||
2025-10-15 10:28:37,193 [INFO] Daily cleanup is disabled by configuration.
|
||||
2025-10-15 15:54:56,829 [INFO] Daily cleanup is disabled by configuration.
|
||||
2025-10-15 15:59:16,304 [INFO] Daily cleanup is disabled by configuration.
|
||||
2025-10-15 16:27:05,307 [INFO] Daily cleanup is disabled by configuration.
|
||||
2025-10-15 16:29:14,882 [INFO] Daily cleanup is disabled by configuration.
|
||||
2025-10-15 17:04:31,298 [INFO] Daily cleanup is disabled by configuration.
|
||||
2025-10-15 17:11:28,215 [INFO] Daily cleanup is disabled by configuration.
|
||||
2025-10-15 18:00:31,833 [INFO] Daily cleanup is disabled by configuration.
|
||||
@@ -216,6 +216,7 @@ const edges = [
|
||||
{
|
||||
source: "{{ edge.from }}", // edge source as string
|
||||
target: "{{ edge.to }}", // edge target as string
|
||||
type: {{ edge.type | tojson }},
|
||||
originalColor: colors.edge[{{edge.type | tojson}}],
|
||||
lineStyle: {
|
||||
color: colors.edge[{{edge.type | tojson}}],
|
||||
@@ -228,32 +229,55 @@ const edges = [
|
||||
let filteredNodes = [];
|
||||
let filteredEdges = [];
|
||||
let lastSelectedNode = null;
|
||||
const nodeChannelSet = [...new Set(nodes.map(n => n.channel).filter(Boolean))];
|
||||
let channelOptions = [...nodeChannelSet].sort();
|
||||
|
||||
async function fetchChannelOptionsFromAPI() {
|
||||
try {
|
||||
const res = await fetch('/api/channels?period_type=day&length=30');
|
||||
if (!res.ok) return [];
|
||||
const data = await res.json();
|
||||
if (!data || !Array.isArray(data.channels)) return [];
|
||||
return data.channels.filter(ch => typeof ch === 'string' && ch.trim().length > 0);
|
||||
} catch (err) {
|
||||
console.error('Channel fetch failed:', err);
|
||||
return [];
|
||||
const normalizeChannel = (value) => {
|
||||
const trimmed = (value || '').toString().trim();
|
||||
return trimmed || 'Unknown';
|
||||
};
|
||||
|
||||
const channelByNodeId = new Map();
|
||||
nodes.forEach(n=>{
|
||||
const key = String(n.name ?? n.node_id ?? '');
|
||||
if(key){
|
||||
channelByNodeId.set(key, normalizeChannel(n.channel));
|
||||
}
|
||||
});
|
||||
|
||||
const tracerouteChannelCounts = new Map();
|
||||
edges.forEach(edge=>{
|
||||
if(edge.type === 'traceroute'){
|
||||
const weight = typeof edge.weight === 'number' ? edge.weight : 1;
|
||||
const fromChannel = channelByNodeId.get(String(edge.source));
|
||||
const toChannel = channelByNodeId.get(String(edge.target));
|
||||
if(fromChannel){
|
||||
tracerouteChannelCounts.set(fromChannel, (tracerouteChannelCounts.get(fromChannel) || 0) + weight);
|
||||
}
|
||||
if(toChannel){
|
||||
tracerouteChannelCounts.set(toChannel, (tracerouteChannelCounts.get(toChannel) || 0) + weight);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let channelOptions = [];
|
||||
if (tracerouteChannelCounts.size) {
|
||||
channelOptions = Array.from(
|
||||
[...tracerouteChannelCounts.entries()]
|
||||
.filter(([_, count]) => count > 0)
|
||||
.map(([channel]) => channel)
|
||||
).sort();
|
||||
}
|
||||
|
||||
async function initializeChannelOptions() {
|
||||
const fetched = await fetchChannelOptionsFromAPI();
|
||||
const merged = new Set([...nodeChannelSet, ...fetched]);
|
||||
if (hasChannelSelection(selectedChannel)) {
|
||||
merged.add(selectedChannel);
|
||||
}
|
||||
channelOptions = Array.from(merged).sort();
|
||||
if (!hasChannelSelection(selectedChannel) && channelOptions.length) {
|
||||
selectedChannel = channelOptions[0];
|
||||
}
|
||||
if (!channelOptions.length) {
|
||||
channelOptions = Array.from(new Set(nodes.map(n=>normalizeChannel(n.channel)))).sort();
|
||||
}
|
||||
|
||||
if (hasChannelSelection(selectedChannel) && channelOptions.length && !channelOptions.includes(selectedChannel)) {
|
||||
channelOptions.push(selectedChannel);
|
||||
channelOptions.sort();
|
||||
}
|
||||
|
||||
if (!hasChannelSelection(selectedChannel) && channelOptions.length) {
|
||||
selectedChannel = channelOptions[0];
|
||||
}
|
||||
|
||||
function populateChannelDropdown() {
|
||||
|
||||
@@ -223,20 +223,45 @@ function updateStatsAndChart() {
|
||||
}
|
||||
|
||||
// Sort table
|
||||
function sortTable(n) {
|
||||
function sortTable(columnIndex) {
|
||||
const table = document.getElementById("trafficTable");
|
||||
const rows = Array.from(table.rows).slice(1);
|
||||
const header = table.rows[0].cells[n];
|
||||
const isNumeric = !isNaN(rows[0].cells[n].innerText.replace('%',''));
|
||||
let sortedRows = rows.sort((a,b)=>{
|
||||
const valA = isNumeric ? parseFloat(a.cells[n].innerText.replace('%','')) : a.cells[n].innerText.toLowerCase();
|
||||
const valB = isNumeric ? parseFloat(b.cells[n].cells[n].innerText.replace('%','')) : b.cells[n].innerText.toLowerCase();
|
||||
return valA > valB ? 1 : -1;
|
||||
});
|
||||
if(header.getAttribute('data-sort-direction')==='asc'){ sortedRows.reverse(); header.setAttribute('data-sort-direction','desc'); }
|
||||
else header.setAttribute('data-sort-direction','asc');
|
||||
const tbody = table.tBodies[0];
|
||||
sortedRows.forEach(row=>tbody.appendChild(row));
|
||||
const headerCell = table.tHead.rows[0].cells[columnIndex];
|
||||
const rows = Array.from(tbody.rows);
|
||||
|
||||
if (!rows.length) return;
|
||||
|
||||
const sampleText = rows[0].cells[columnIndex].innerText.trim().replace('%','');
|
||||
const isNumeric = sampleText !== '' && !isNaN(sampleText);
|
||||
|
||||
const currentDirection = headerCell.getAttribute('data-sort-direction') || 'none';
|
||||
const sortAscending = currentDirection === 'desc' || currentDirection === 'none';
|
||||
|
||||
rows.sort((rowA, rowB) => {
|
||||
const textA = rowA.cells[columnIndex].innerText.trim();
|
||||
const textB = rowB.cells[columnIndex].innerText.trim();
|
||||
|
||||
let valueA = isNumeric ? parseFloat(textA.replace('%','')) : textA.toLowerCase();
|
||||
let valueB = isNumeric ? parseFloat(textB.replace('%','')) : textB.toLowerCase();
|
||||
|
||||
if (isNumeric) {
|
||||
valueA = isNaN(valueA) ? Number.NEGATIVE_INFINITY : valueA;
|
||||
valueB = isNaN(valueB) ? Number.NEGATIVE_INFINITY : valueB;
|
||||
}
|
||||
|
||||
if (valueA > valueB) return 1;
|
||||
if (valueA < valueB) return -1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
if (!sortAscending) {
|
||||
rows.reverse();
|
||||
}
|
||||
|
||||
Array.from(table.tHead.rows[0].cells).forEach(cell => cell.removeAttribute('data-sort-direction'));
|
||||
headerCell.setAttribute('data-sort-direction', sortAscending ? 'asc' : 'desc');
|
||||
|
||||
rows.forEach(row => tbody.appendChild(row));
|
||||
}
|
||||
|
||||
// Initialize
|
||||
|
||||
Reference in New Issue
Block a user