From 0f41f8daf2006e69291642c11b6997e52a6e9122 Mon Sep 17 00:00:00 2001
From: Kpa-clawbot <259247574+Kpa-clawbot@users.noreply.github.com>
Date: Mon, 30 Mar 2026 19:54:06 -0700
Subject: [PATCH 1/6] Fix channels region filtering for messages and WS
Refs #280
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
public/channels.js | 119 ++-------------
public/index.html | 56 +++----
test-frontend-helpers.js | 316 ---------------------------------------
3 files changed, 42 insertions(+), 449 deletions(-)
diff --git a/public/channels.js b/public/channels.js
index 6000e286..d2e499c3 100644
--- a/public/channels.js
+++ b/public/channels.js
@@ -9,9 +9,7 @@
let autoScroll = true;
let nodeCache = {};
let selectedNode = null;
- let observerIataById = {};
- let observerIataByName = {};
- let messageRequestId = 0;
+ let observerIataMap = {};
var _nodeCacheTTL = 5 * 60 * 1000; // 5 minutes
function getSelectedRegionsSnapshot() {
@@ -19,28 +17,11 @@
return rp ? rp.split(',').filter(Boolean) : null;
}
- function normalizeObserverNameKey(name) {
- if (!name) return '';
- return String(name).trim().toLowerCase();
- }
-
- function shouldProcessWSMessageForRegion(msg, selectedRegions, observerRegionsById, observerRegionsByName) {
+ function shouldProcessWSMessageForRegion(msg, selectedRegions, observerRegions) {
if (!selectedRegions || !selectedRegions.length) return true;
- if (observerRegionsById && observerRegionsById.byId) {
- observerRegionsByName = observerRegionsById.byName || {};
- observerRegionsById = observerRegionsById.byId || {};
- }
- observerRegionsById = observerRegionsById || {};
- observerRegionsByName = observerRegionsByName || {};
-
var observerId = msg?.data?.packet?.observer_id || msg?.data?.observer_id || null;
- var observerRegion = observerId ? observerRegionsById[observerId] : null;
- if (!observerRegion) {
- var observerName = msg?.data?.packet?.observer_name || msg?.data?.observer_name || msg?.data?.observer || null;
- var observerNameKey = normalizeObserverNameKey(observerName);
- if (observerName) observerRegion = observerRegionsByName[observerName];
- if (!observerRegion && observerNameKey) observerRegion = observerRegionsByName[observerNameKey];
- }
+ if (!observerId) return false;
+ var observerRegion = observerRegions[observerId];
if (!observerRegion) return false;
return selectedRegions.indexOf(observerRegion) !== -1;
}
@@ -49,53 +30,17 @@
try {
var data = await api('/observers', { ttl: CLIENT_TTL.observers });
var list = data && data.observers ? data.observers : [];
- var byId = {};
- var byName = {};
+ var map = {};
for (var i = 0; i < list.length; i++) {
var o = list[i];
var id = o.id || o.observer_id;
- var name = o.name || o.observer_name;
- if (!o.iata) continue;
- if (id) byId[id] = o.iata;
- if (name) {
- byName[name] = o.iata;
- var key = normalizeObserverNameKey(name);
- if (key) byName[key] = o.iata;
- }
+ if (!id || !o.iata) continue;
+ map[id] = o.iata;
}
- observerIataById = byId;
- observerIataByName = byName;
+ observerIataMap = map;
} catch {}
}
- function beginMessageRequest(hash, regionParam) {
- return { id: ++messageRequestId, hash: hash, regionParam: regionParam || '' };
- }
-
- function isStaleMessageRequest(req) {
- if (!req) return true;
- var currentRegion = RegionFilter.getRegionParam() || '';
- if (req.id !== messageRequestId) return true;
- if (selectedHash !== req.hash) return true;
- if (currentRegion !== req.regionParam) return true;
- return false;
- }
-
- function reconcileSelectionAfterChannelRefresh() {
- if (!selectedHash || channels.some(ch => ch.hash === selectedHash)) return false;
- selectedHash = null;
- messages = [];
- history.replaceState(null, '', '#/channels');
- renderChannelList();
- const header = document.getElementById('chHeader');
- if (header) header.querySelector('.ch-header-text').textContent = 'Select a channel';
- const msgEl = document.getElementById('chMessages');
- if (msgEl) msgEl.innerHTML = '
Choose a channel from the sidebar to view messages
';
- document.querySelector('.ch-layout')?.classList.remove('ch-show-main');
- document.getElementById('chScrollBtn')?.classList.add('hidden');
- return true;
- }
-
async function lookupNode(name) {
var cached = nodeCache[name];
if (cached !== undefined) {
@@ -473,7 +418,8 @@
}
});
- function processWSBatch(msgs, selectedRegions) {
+ wsHandler = debouncedOnWS(function (msgs) {
+ var selectedRegions = getSelectedRegionsSnapshot();
var dominated = msgs.filter(function (m) {
return m.type === 'message' || (m.type === 'packet' && m.data?.decoded?.header?.payloadTypeName === 'GRP_TXT');
});
@@ -485,7 +431,7 @@
for (var i = 0; i < dominated.length; i++) {
var m = dominated[i];
- if (!shouldProcessWSMessageForRegion(m, selectedRegions, observerIataById, observerIataByName)) continue;
+ if (!shouldProcessWSMessageForRegion(m, selectedRegions, observerIataMap)) continue;
var payload = m.data?.decoded?.payload;
if (!payload) continue;
@@ -586,18 +532,7 @@
if (liveEl) liveEl.textContent = 'New message received';
}
}
- }
-
- function handleWSBatch(msgs) {
- var selectedRegions = getSelectedRegionsSnapshot();
- processWSBatch(msgs, selectedRegions);
- }
-
- wsHandler = debouncedOnWS(function (msgs) {
- handleWSBatch(msgs);
});
- window._channelsHandleWSBatchForTest = handleWSBatch;
- window._channelsProcessWSBatchForTest = processWSBatch;
// Tick relative timestamps every 1s — iterates channels array, updates DOM text only
timeAgoTimer = setInterval(function () {
@@ -639,7 +574,6 @@
return ch;
}).sort((a, b) => (b.lastActivityMs || 0) - (a.lastActivityMs || 0));
renderChannelList();
- reconcileSelectionAfterChannelRefresh();
} catch (e) {
if (!silent) {
const el = document.getElementById('chList');
@@ -682,8 +616,6 @@
}
async function selectChannel(hash) {
- const rp = RegionFilter.getRegionParam() || '';
- const request = beginMessageRequest(hash, rp);
selectedHash = hash;
history.replaceState(null, '', `#/channels/${encodeURIComponent(hash)}`);
renderChannelList();
@@ -699,9 +631,9 @@
msgEl.innerHTML = 'Loading messages…
';
try {
+ const rp = RegionFilter.getRegionParam();
const regionQs = rp ? '®ion=' + encodeURIComponent(rp) : '';
const data = await api(`/channels/${encodeURIComponent(hash)}/messages?limit=200${regionQs}`, { ttl: CLIENT_TTL.channelMessages });
- if (isStaleMessageRequest(request)) return;
messages = data.messages || [];
if (messages.length === 0 && rp) {
msgEl.innerHTML = 'Channel not available in selected region
';
@@ -710,7 +642,6 @@
scrollToBottom();
}
} catch (e) {
- if (isStaleMessageRequest(request)) return;
msgEl.innerHTML = `Failed to load messages: ${e.message}
`;
}
}
@@ -722,12 +653,9 @@
if (!msgEl) return;
const wasAtBottom = msgEl.scrollHeight - msgEl.scrollTop - msgEl.clientHeight < 60;
try {
- const requestHash = selectedHash;
- const rp = RegionFilter.getRegionParam() || '';
- const request = beginMessageRequest(requestHash, rp);
+ const rp = RegionFilter.getRegionParam();
const regionQs = rp ? '®ion=' + encodeURIComponent(rp) : '';
- const data = await api(`/channels/${encodeURIComponent(requestHash)}/messages?limit=200${regionQs}`, { ttl: CLIENT_TTL.channelMessages, bust: !!opts.forceNoCache });
- if (isStaleMessageRequest(request)) return;
+ const data = await api(`/channels/${encodeURIComponent(selectedHash)}/messages?limit=200${regionQs}`, { ttl: CLIENT_TTL.channelMessages, bust: !!opts.forceNoCache });
const newMsgs = data.messages || [];
if (opts.regionSwitch && rp && newMsgs.length === 0) {
messages = [];
@@ -790,25 +718,6 @@
if (msgEl) { msgEl.scrollTop = msgEl.scrollHeight; autoScroll = true; document.getElementById('chScrollBtn')?.classList.add('hidden'); }
}
- window._channelsSetStateForTest = function (state) {
- if (!state) return;
- if (Array.isArray(state.channels)) channels = state.channels;
- if (Array.isArray(state.messages)) messages = state.messages;
- if (Object.prototype.hasOwnProperty.call(state, 'selectedHash')) selectedHash = state.selectedHash;
- };
- window._channelsSetObserverRegionsForTest = function (byId, byName) {
- observerIataById = byId || {};
- observerIataByName = byName || {};
- };
- window._channelsSelectChannelForTest = selectChannel;
- window._channelsRefreshMessagesForTest = refreshMessages;
- window._channelsLoadChannelsForTest = loadChannels;
- window._channelsBeginMessageRequestForTest = beginMessageRequest;
- window._channelsIsStaleMessageRequestForTest = isStaleMessageRequest;
- window._channelsReconcileSelectionForTest = reconcileSelectionAfterChannelRefresh;
- window._channelsGetStateForTest = function () {
- return { channels: channels, messages: messages, selectedHash: selectedHash };
- };
window._channelsShouldProcessWSMessageForRegion = shouldProcessWSMessageForRegion;
registerPage('channels', { init, destroy });
})();
diff --git a/public/index.html b/public/index.html
index 39d1836c..6eb4d5a7 100644
--- a/public/index.html
+++ b/public/index.html
@@ -22,9 +22,9 @@
-
-
-
+
+
+
@@ -81,31 +81,31 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+