[feat](trx-frontend-http): per-rig bookmarks, scheduler, and decode filtering

Two-tier bookmark system: general bookmarks shared across all rigs plus
rig-specific bookmarks with scope picker in the Bookmarks tab. Scheduler
storage split into per-rig files with migration from legacy single file.
Decode history tagged with rig_id and filterable via ?remote= on
/decode/history endpoint. Decode SSE reconnects on rig switch to refresh
filtered history.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
2026-03-24 20:24:49 +01:00
parent b50c6bca96
commit 55688a27b2
11 changed files with 436 additions and 156 deletions
@@ -973,6 +973,8 @@ function applyRigList(activeRigId, rigIds, displayNames) {
updateRigSubtitle(lastActiveRigId);
if (typeof setSchedulerRig === "function") setSchedulerRig(lastActiveRigId);
if (typeof setBackgroundDecodeRig === "function") setBackgroundDecodeRig(lastActiveRigId);
if (typeof bmPopulateScopePicker === "function") bmPopulateScopePicker();
if (typeof bmFetch === "function") bmFetch(document.getElementById("bm-category-filter")?.value || "");
updateMapRigFilter();
}
@@ -3498,6 +3500,9 @@ async function switchRigFromSelect(selectEl) {
updateRigSubtitle(lastActiveRigId);
if (typeof setSchedulerRig === "function") setSchedulerRig(lastActiveRigId);
if (typeof setBackgroundDecodeRig === "function") setBackgroundDecodeRig(lastActiveRigId);
if (typeof bmFetch === "function") bmFetch(document.getElementById("bm-category-filter")?.value || "");
// Reconnect decode SSE so history is re-fetched with the new rig filter.
connectDecode();
// Switch this session's rig and reconnect SSE to the new rig's
// state channel.
try {
@@ -8101,8 +8106,14 @@ function scheduleDecodeHistoryDrainStep(callback) {
}
}
function decodeHistoryUrl() {
let url = "/decode/history";
if (lastActiveRigId) url += "?remote=" + encodeURIComponent(lastActiveRigId);
return url;
}
function loadDecodeHistoryOnMainThread(onReady, onError) {
fetch("/decode/history").then(async (resp) => {
fetch(decodeHistoryUrl()).then(async (resp) => {
if (!resp.ok) return null;
setDecodeHistoryOverlayVisible(true, "Loading decode history…", "Receiving compressed history payload");
const payload = await resp.arrayBuffer();
@@ -8328,7 +8339,7 @@ function connectDecode() {
};
worker.postMessage({
type: "fetch-history",
url: "/decode/history",
url: decodeHistoryUrl(),
batchLimit: DECODE_HISTORY_WORKER_GROUP_LIMIT,
});
return true;