mirror of
https://github.com/Roslund/sthlm-mesh.git
synced 2026-08-08 09:53:04 +02:00
New Messages page
This commit is contained in:
@@ -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>
|
||||
@@ -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 %}}
|
||||
@@ -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('<', '<').replaceAll('>', '>').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);
|
||||
});
|
||||
Reference in New Issue
Block a user