diff --git a/content/sv/status/index.md b/content/sv/status/index.md index 71d139f..2e9d99b 100644 --- a/content/sv/status/index.md +++ b/content/sv/status/index.md @@ -57,7 +57,17 @@ För mer info se vår [dokumentation]({{}}#position-precision). ## Packet typer -Fördelningen av olika pakettyper i nätverket under de senaste dygnet. Diagrammet visar hur nätverket används, inklusive meddelanden, positionstelemetri och andra systempaket. +Fördelningen av olika pakettyper i nätverket under de senaste dygnet. Diagrammet visar hur nätverket används, inklusive meddelanden, positionstelemetri och andra systempaket. Sökrutan till höger kan användas för att visa antalet paket av respektive typ för en given nod. + +
+ +
diff --git a/static/js/status/portnum-distribution-chart.js b/static/js/status/portnum-distribution-chart.js index 27a3499..0114d91 100644 --- a/static/js/status/portnum-distribution-chart.js +++ b/static/js/status/portnum-distribution-chart.js @@ -1,31 +1,150 @@ -async function portnumDistributionChart() { +let allNodes = []; +let highlightedIndex = -1; +let chartInstance; + + +async function fetchNodes() { + const res = await fetch('https://map.sthlm-mesh.se/api/v1/nodes/'); + const data = await res.json(); + + const threshold = new Date(); + threshold.setDate(threshold.getDate() - 1); + allNodes = data.nodes.filter(node => new Date(node.updated_at) >= threshold); +} + +function filterSuggestions(query) { + const lowerQuery = query.toLowerCase(); + return allNodes?.filter(node => node.long_name?.toLowerCase().includes(lowerQuery)) || []; +} + +function showSuggestions(matches) { + const ul = document.getElementById('suggestions'); + ul.innerHTML = ''; + + if (matches.length === 0) { + ul.innerHTML = ''; + ul.style.display = 'block'; + return; + } + + matches.forEach(node => { + const li = document.createElement('li'); + const a = document.createElement('a'); + a.className = 'dropdown-item'; + a.href = '#'; + a.textContent = node.long_name; + a.addEventListener('click', (e) => { + e.preventDefault(); + document.getElementById('nodeSearch').value = node.long_name; + ul.style.display = 'none'; + portnumDistributionChart(node.node_id); + }); + li.appendChild(a); + ul.appendChild(li); + }); + + ul.style.display = 'block'; +} + +function updateHighlight(suggestions) { + suggestions.forEach((el, i) => { + if (i === highlightedIndex) { + el.classList.add('active'); + } else { + el.classList.remove('active'); + } + }); +} + +document.getElementById('nodeSearch').addEventListener('keydown', (e) => { + const suggestions = document.querySelectorAll('#suggestions .dropdown-item'); + + if (suggestions.length === 0) return; + + switch (e.key) { + case 'ArrowDown': + e.preventDefault(); + highlightedIndex = (highlightedIndex + 1) % suggestions.length; + updateHighlight(suggestions); + break; + + case 'ArrowUp': + e.preventDefault(); + highlightedIndex = (highlightedIndex - 1 + suggestions.length) % suggestions.length; + updateHighlight(suggestions); + break; + + case 'Enter': + e.preventDefault(); + if (highlightedIndex >= 0) { + suggestions[highlightedIndex].click(); + } + break; + + case 'Escape': + document.getElementById('nodeSearch').value = ''; + document.getElementById('suggestions').style.display = 'none'; + portnumDistributionChart(); // Reload full chart + highlightedIndex = -1; + break; + } +}); + +document.getElementById('nodeSearch').addEventListener('input', (e) => { + highlightedIndex = -1; + const matches = filterSuggestions(e.target.value); + showSuggestions(matches); +}); + +document.getElementById('clearFilterBtn').addEventListener('click', () => { + highlightedIndex = -1; + document.getElementById('nodeSearch').value = ''; + document.getElementById('suggestions').style.display = 'none'; + portnumDistributionChart(); // Reload full chart +}); + +// Main chart function +async function portnumDistributionChart(nodeId = null) { const canvas = document.getElementById('portnumDistribution'); const ctx = canvas.getContext('2d'); - // Loading message + ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.font = '16px Arial'; ctx.fillStyle = 'gray'; ctx.textAlign = 'center'; ctx.fillText('Loading data...', canvas.width / 2, canvas.height / 2); try { - const response = await fetch('https://map.sthlm-mesh.se/api/v1/stats/portnum-counts'); + const url = nodeId + ? `https://map.sthlm-mesh.se/api/v1/stats/portnum-counts?nodeId=${nodeId}` + : 'https://map.sthlm-mesh.se/api/v1/stats/portnum-counts'; + + const response = await fetch(url); const data = await response.json(); const labels = data.map(entry => entry.label.replace(/_APP$/, '')); const counts = data.map(entry => entry.count); - // Optional: dynamically size the container + const backgroundColors = counts.map(count => { + if (nodeId) { + // Filtered chart: use tighter thresholds + if (count < 50) return '#7EB26D'; // Green + if (count < 100) return '#EAB839'; // Yellow + return '#BF1B00'; // Red + } else { + // Global chart: use broader thresholds + if (count < 500) return '#7EB26D'; // Green + if (count < 2000) return '#EAB839'; // Yellow + return '#BF1B00'; // Red + } + }); + const chartContainer = document.getElementById('portnumDistributionContainer'); chartContainer.style.height = `${labels.length * 35}px`; - const backgroundColors = counts.map(count => { - if (count < 500) return '#7EB26D'; // Green - if (count < 2000) return '#EAB839'; // Yellow - return '#BF1B00'; // Red - }); + if (chartInstance) chartInstance.destroy(); - new Chart(ctx, { + chartInstance = new Chart(ctx, { type: 'bar', data: { labels: labels, @@ -59,4 +178,4 @@ async function portnumDistributionChart() { } } -portnumDistributionChart(); +fetchNodes().then(() => portnumDistributionChart());