New Messages page

This commit is contained in:
Anton Roslund
2025-03-15 23:09:11 +01:00
parent b76758e6c1
commit 43c580a958
3 changed files with 176 additions and 10 deletions
+31
View File
@@ -0,0 +1,31 @@
---
title: Meddelanden
linkTitle: test
menu: {main: {weight: 50}}
---
<section id="messages" class="pt-0 row td-box td-box--white td-box--height-auto" style="padding-bottom: 0px !important;"x>
<h2 id="senaste-meddelanden" class="pt-3">Senaste meddelanden<a class="td-heading-self-link" href="#senaste-meddelanden" aria-label="Heading self-link"></a></h2>
<div class="btn-toolbar mb-2" role="toolbar" aria-label="Toolbar with button groups">
<div class="btn-group btn-group-sm me-2" role="group" aria-label="Basic radio toggle button group">
<input type="radio" class="btn-check" name="btnradio" id="all" autocomplete="off" checked>
<label class="btn btn-outline-primary" for="all">Alla</label>
</div>
<div class="btn-group btn-group-sm" role="group" aria-label="Basic radio toggle button group">
<input type="radio" class="btn-check" name="btnradio" id="3663385928" autocomplete="off">
<label class="btn btn-outline-primary" for="3663385928">Ros1</label>
<input type="radio" class="btn-check" name="btnradio" id="1978245180" autocomplete="off">
<label class="btn btn-outline-primary" for="1978245180">CVK</label>
<input type="radio" class="btn-check" name="btnradio" id="862351628" autocomplete="off">
<label class="btn btn-outline-primary" for="862351628">JwK</label>
<input type="radio" class="btn-check" name="btnradio" id="2971894662" autocomplete="off">
<label class="btn btn-outline-primary" for="2971894662">Älg</label>
</div>
</div>
<div id="loading"><p>Loading...</p></div>
</section>
<script src="/js/messages.js"></script>
-10
View File
@@ -1,10 +0,0 @@
---
title: Meddelanden
linkTitle: Meddelanden
menu: {main: {weight: 50}}
---
<br>
{{% 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 %}}
+145
View File
@@ -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 = `<p style="color: red;">Error fetching messages: ${error.message}</p>`;
}
}
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 = `
<div class="p-2 flex">
<div class="d-flex rounded-circle shadow text-white justify-content-center align-items-center"
style="width: 48px; height: 48px; background-color: ${getNodeColour(message.from)}; color: #ffffff;">
${getNodeShortName(message.from)}
</div>
</div>
<div class="flex">
<div class="small">
<a target="_blank" href="https://map.sthlm-mesh.se/?node_id=${message.from}" style="color: grey; text-decoration: none;">${getNodeLongName(message.from)}</a>
${message.to !== "4294967295" ? ` → <a target="_blank" href="https://map.sthlm-mesh.se//?node_id=${message.to}" style="color: grey; text-decoration: none;">${getNodeLongName(message.to)}</a>` : ""}
</div>
<div class="px-2 py-1 pb-1 border rounded shadow-sm" style="background-color: #efefef">
<div class="">${escapeMessageText(message.text)}</div>
</div>
<div class="pt-1" style="font-size: 0.65rem;color: grey;">${formatMessageTimestamp(message.created_at)}</div>
</div>
`;
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('<', '&lt;').replaceAll('>', '&gt;').replaceAll('\n', '<br/>');
}
function formatMessageTimestamp(createdAt) {
const date = new Date(createdAt);
return date.toLocaleString('sv-SE', { hour12: false }).replace(' ', ' ').slice(0, 16);
}
await fetchMessages();
setInterval(fetchMessages, 30000);
});