Compare commits

...

1 Commits

Author SHA1 Message Date
l5y
b7e38e5788 Rebuild chat log on each refresh 2025-09-21 09:16:09 +02:00

View File

@@ -377,8 +377,6 @@
};
let allNodes = [];
let shortInfoAnchor = null;
const seenNodeIds = new Set();
const seenMessageIds = new Set();
let lastChatDate;
const NODE_LIMIT = 1000;
const CHAT_LIMIT = 1000;
@@ -920,16 +918,8 @@
requestAnimationFrame(positionShortInfoOverlay);
}
function appendChatEntry(div) {
chatEl.appendChild(div);
while (chatEl.childElementCount > CHAT_LIMIT) {
chatEl.removeChild(chatEl.firstChild);
}
chatEl.scrollTop = chatEl.scrollHeight;
}
function maybeAddDateDivider(ts) {
if (!ts) return;
function maybeCreateDateDivider(ts) {
if (!ts) return null;
const d = new Date(ts * 1000);
const key = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
if (lastChatDate !== key) {
@@ -939,30 +929,60 @@
const div = document.createElement('div');
div.className = 'chat-entry-date';
div.textContent = `-- ${formatDate(midnight)} --`;
appendChatEntry(div);
return div;
}
return null;
}
function addNewNodeChatEntry(n) {
maybeAddDateDivider(n.first_heard);
function createNodeChatEntry(n) {
const div = document.createElement('div');
const ts = formatTime(new Date(n.first_heard * 1000));
div.className = 'chat-entry-node';
const short = renderShortHtml(n.short_name, n.role, n.long_name, n);
const longName = escapeHtml(n.long_name || '');
div.innerHTML = `[${ts}] ${short} <em>New node: ${longName}</em>`;
appendChatEntry(div);
return div;
}
function addNewMessageChatEntry(m) {
maybeAddDateDivider(m.rx_time);
function createMessageChatEntry(m) {
const div = document.createElement('div');
const ts = formatTime(new Date(m.rx_time * 1000));
const short = renderShortHtml(m.node?.short_name, m.node?.role, m.node?.long_name, m.node);
const text = escapeHtml(m.text || '');
div.className = 'chat-entry-msg';
div.innerHTML = `[${ts}] ${short} ${text}`;
appendChatEntry(div);
return div;
}
function renderChatLog(nodes, messages) {
if (!chatEl) return;
const entries = [];
for (const n of nodes || []) {
entries.push({ type: 'node', ts: n.first_heard ?? 0, item: n });
}
for (const m of messages || []) {
entries.push({ type: 'msg', ts: m.rx_time ?? 0, item: m });
}
entries.sort((a, b) => {
if (a.ts !== b.ts) return a.ts - b.ts;
return a.type === 'node' && b.type === 'msg' ? -1 : a.type === 'msg' && b.type === 'node' ? 1 : 0;
});
const frag = document.createDocumentFragment();
lastChatDate = null;
for (const entry of entries) {
const divider = maybeCreateDateDivider(entry.ts);
if (divider) frag.appendChild(divider);
if (entry.type === 'node') {
frag.appendChild(createNodeChatEntry(entry.item));
} else {
frag.appendChild(createMessageChatEntry(entry.item));
}
}
chatEl.replaceChildren(frag);
while (chatEl.childElementCount > CHAT_LIMIT) {
chatEl.removeChild(chatEl.firstChild);
}
chatEl.scrollTop = chatEl.scrollHeight;
}
function pad(n) { return String(n).padStart(2, "0"); }
@@ -1142,35 +1162,8 @@
statusEl.textContent = 'refreshing…';
const nodes = await fetchNodes();
computeDistances(nodes);
const newNodes = [];
for (const n of nodes) {
if (n.node_id && !seenNodeIds.has(n.node_id)) {
newNodes.push(n);
}
}
const messages = await fetchMessages();
const newMessages = [];
for (const m of messages) {
if (m.id && !seenMessageIds.has(m.id)) {
newMessages.push(m);
}
}
const entries = [];
for (const n of newNodes) entries.push({ type: 'node', ts: n.first_heard ?? 0, item: n });
for (const m of newMessages) entries.push({ type: 'msg', ts: m.rx_time ?? 0, item: m });
entries.sort((a, b) => {
if (a.ts !== b.ts) return a.ts - b.ts;
return a.type === 'node' && b.type === 'msg' ? -1 : a.type === 'msg' && b.type === 'node' ? 1 : 0;
});
for (const e of entries) {
if (e.type === 'node') {
addNewNodeChatEntry(e.item);
if (e.item.node_id) seenNodeIds.add(e.item.node_id);
} else {
addNewMessageChatEntry(e.item);
if (e.item.id) seenMessageIds.add(e.item.id);
}
}
renderChatLog(nodes, messages);
allNodes = nodes;
applyFilter();
statusEl.textContent = 'updated ' + new Date().toLocaleTimeString();