From 43c580a9585e63ce35f29077e79b1843541bf6ce Mon Sep 17 00:00:00 2001 From: Anton Roslund Date: Sat, 15 Mar 2025 23:09:11 +0100 Subject: [PATCH] New Messages page --- content/sv/messages/index.html | 31 +++++++ content/sv/messages/index.md | 10 --- static/js/messages.js | 145 +++++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+), 10 deletions(-) create mode 100644 content/sv/messages/index.html delete mode 100644 content/sv/messages/index.md create mode 100644 static/js/messages.js diff --git a/content/sv/messages/index.html b/content/sv/messages/index.html new file mode 100644 index 0000000..c3d7313 --- /dev/null +++ b/content/sv/messages/index.html @@ -0,0 +1,31 @@ +--- +title: Meddelanden +linkTitle: test +menu: {main: {weight: 50}} +--- +
+

Senaste meddelanden

+ + +

Loading...

+
+ + diff --git a/content/sv/messages/index.md b/content/sv/messages/index.md deleted file mode 100644 index 1845188..0000000 --- a/content/sv/messages/index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: Meddelanden -linkTitle: Meddelanden -menu: {main: {weight: 50}} ---- -
-{{% blocks/section color="white" %}} -## Senaste meddelanden -{{% iframe src="https://map.sthlm-mesh.se/api/v1/text-messages/embed?gateway_id=3663385928" width="100%" style="min-height:65vh;overflow: hidden;" %}} -{{% /blocks/section %}} \ No newline at end of file diff --git a/static/js/messages.js b/static/js/messages.js new file mode 100644 index 0000000..5afc74f --- /dev/null +++ b/static/js/messages.js @@ -0,0 +1,145 @@ +document.addEventListener("DOMContentLoaded", async function () { + const messagesContainer = document.getElementById("messages"); + const radioButtons = document.querySelectorAll("input[name='btnradio']"); + const loadingDiv = document.getElementById("loading"); + const messagesList = document.createElement("div"); + messagesList.style="max-height:70vh;overflow: auto;" + messagesContainer.appendChild(messagesList); + + const state = { + messages: [], + nodesById: {}, + }; + + radioButtons.forEach(radio => { + radio.addEventListener("change", fetchMessages); + }); + + + async function fetchMessages() { + try { + let url = "https://map.sthlm-mesh.se/api/v1/text-messages?order=desc"; + const selectedRadio = document.querySelector("input[name='btnradio']:checked"); + + //If all is not selected we get 15 messages. If not we get 35 due to duplicates + if (selectedRadio.id !== "all") { + url += `&gateway_id=${selectedRadio.id}`; + url += `&count=15`; + } else { + url += `&count=35`; + } + + const response = await fetch(url); + const data = await response.json(); + + //Filter duplicate messages + state.messages = Array.from( + new Map(data.text_messages.map(msg => [msg.packet_id, msg])).values() + ); + + // fetch node info + for(const message of state.messages){ + await fetchNodeInfo(message.to); + await fetchNodeInfo(message.from); + await fetchNodeInfo(message.gateway_id); + } + + updateUI(); + } catch (error) { + console.error("Error fetching messages", error); + loadingDiv.innerHTML = `

Error fetching messages: ${error.message}

`; + } + } + async function fetchNodeInfo(nodeId) { + // do nothing if already fetched + if(nodeId in state.nodesById){ + return; + } + + // do nothing if broadcast address + if(nodeId.toString() === "4294967295"){ + return; + } + + try { + const response = await fetch(`https://map.sthlm-mesh.se/api/v1/nodes/${nodeId}`); + const data = await response.json(); + const node = data.node; + + if(node){ + state.nodesById[node.node_id] = node; + } + + } catch(e) { + // do nothing + } + + } + + function updateUI() { + loadingDiv.innerHTML = ""; // Clear the loading message + messagesList.innerHTML = ""; + state.messages.slice().reverse().forEach(message => { + const messageDiv = document.createElement("div"); + messageDiv.className = "d-flex mb-2"; + messageDiv.innerHTML = ` +
+
+ ${getNodeShortName(message.from)} +
+
+
+
+ ${getNodeLongName(message.from)} + ${message.to !== "4294967295" ? ` → ${getNodeLongName(message.to)}` : ""} +
+
+
${escapeMessageText(message.text)}
+
+
${formatMessageTimestamp(message.created_at)}
+
+ + `; + messagesList.appendChild(messageDiv); + }); + messagesList.scrollTop = messagesList.scrollHeight; + + } + + function getNodeColour(nodeId) { + return "#" + (nodeId & 0x00FFFFFF).toString(16).padStart(6, '0'); + } + + function getNodeHexId(nodeId) { + return "!" + parseInt(nodeId).toString(16); + } + + function getNodeShortName(nodeId) { + return state.nodesById[nodeId]?.short_name?.substring(0, 4) ?? "?"; + } + + function getNodeLongName(nodeId) { + return state.nodesById[nodeId]?.long_name ?? getNodeHexId(nodeId); + } + + function getNodeName(nodeId) { + const node = state.nodesById[nodeId]; + if(!node){ + return getNodeHexId(nodeId); + } + return `[${node.short_name}] ${node.long_name}`; + } + + function escapeMessageText(text) { + return text.replaceAll('<', '<').replaceAll('>', '>').replaceAll('\n', '
'); + } + + function formatMessageTimestamp(createdAt) { + const date = new Date(createdAt); + return date.toLocaleString('sv-SE', { hour12: false }).replace(' ', ' ').slice(0, 16); + } + + await fetchMessages(); + setInterval(fetchMessages, 30000); +});