From 55688a27b22e90d8421c1cf688f77a6403a6bf4c Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Tue, 24 Mar 2026 20:24:49 +0100 Subject: [PATCH] [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 Signed-off-by: Stan Grams --- src/trx-client/src/main.rs | 14 +- src/trx-client/trx-frontend/src/lib.rs | 37 ++--- .../trx-frontend-http/assets/web/app.js | 15 +- .../trx-frontend-http/assets/web/index.html | 3 + .../assets/web/plugins/bookmarks.js | 55 ++++++- .../trx-frontend/trx-frontend-http/src/api.rs | 92 ++++++++---- .../trx-frontend-http/src/audio.rs | 135 ++++++++++++------ .../src/background_decode.rs | 10 +- .../trx-frontend-http/src/bookmarks.rs | 72 +++++++++- .../trx-frontend-http/src/scheduler.rs | 130 +++++++++++++---- .../trx-frontend-http/src/server.rs | 29 ++-- 11 files changed, 436 insertions(+), 156 deletions(-) diff --git a/src/trx-client/src/main.rs b/src/trx-client/src/main.rs index 9cd93c3..0cc3b08 100644 --- a/src/trx-client/src/main.rs +++ b/src/trx-client/src/main.rs @@ -474,7 +474,7 @@ async fn async_init() -> DynResult { message.ts_ms = Some(current_timestamp_ms()); } if let Ok(mut history) = ais_history.lock() { - history.push_back((now, message)); + history.push_back((now, None, message)); } } DecodedMessage::Vdes(mut message) => { @@ -482,7 +482,7 @@ async fn async_init() -> DynResult { message.ts_ms = Some(current_timestamp_ms()); } if let Ok(mut history) = vdes_history.lock() { - history.push_back((now, message)); + history.push_back((now, None, message)); } } DecodedMessage::Aprs(mut packet) => { @@ -490,7 +490,7 @@ async fn async_init() -> DynResult { packet.ts_ms = Some(current_timestamp_ms()); } if let Ok(mut history) = aprs_history.lock() { - history.push_back((now, packet)); + history.push_back((now, None, packet)); } } DecodedMessage::HfAprs(mut packet) => { @@ -498,17 +498,17 @@ async fn async_init() -> DynResult { packet.ts_ms = Some(current_timestamp_ms()); } if let Ok(mut history) = hf_aprs_history.lock() { - history.push_back((now, packet)); + history.push_back((now, None, packet)); } } DecodedMessage::Cw(event) => { if let Ok(mut history) = cw_history.lock() { - history.push_back((now, event)); + history.push_back((now, None, event)); } } DecodedMessage::Ft8(message) => { if let Ok(mut history) = ft8_history.lock() { - history.push_back((now, message)); + history.push_back((now, None, message)); } } DecodedMessage::Ft4(_) => { @@ -519,7 +519,7 @@ async fn async_init() -> DynResult { } DecodedMessage::Wspr(message) => { if let Ok(mut history) = wspr_history.lock() { - history.push_back((now, message)); + history.push_back((now, None, message)); } } } diff --git a/src/trx-client/trx-frontend/src/lib.rs b/src/trx-client/trx-frontend/src/lib.rs index 43f32df..213d8ec 100644 --- a/src/trx-client/trx-frontend/src/lib.rs +++ b/src/trx-client/trx-frontend/src/lib.rs @@ -194,24 +194,25 @@ pub struct FrontendRuntimeContext { pub audio_info: Option>>, /// Decode message broadcast channel pub decode_rx: Option>, - /// AIS decode history (timestamp, message) - pub ais_history: Arc>>, - /// VDES decode history (timestamp, message) - pub vdes_history: Arc>>, - /// APRS decode history (timestamp, packet) - pub aprs_history: Arc>>, - /// HF APRS decode history (timestamp, packet) - pub hf_aprs_history: Arc>>, - /// CW decode history (timestamp, event) - pub cw_history: Arc>>, - /// FT8 decode history (timestamp, message) - pub ft8_history: Arc>>, - /// FT4 decode history (timestamp, message) - pub ft4_history: Arc>>, - /// FT2 decode history (timestamp, message) - pub ft2_history: Arc>>, - /// WSPR decode history (timestamp, message) - pub wspr_history: Arc>>, + /// Decode history entry: (record_time, rig_id, message). + /// AIS decode history + pub ais_history: Arc, AisMessage)>>>, + /// VDES decode history + pub vdes_history: Arc, VdesMessage)>>>, + /// APRS decode history + pub aprs_history: Arc, AprsPacket)>>>, + /// HF APRS decode history + pub hf_aprs_history: Arc, AprsPacket)>>>, + /// CW decode history + pub cw_history: Arc, CwEvent)>>>, + /// FT8 decode history + pub ft8_history: Arc, Ft8Message)>>>, + /// FT4 decode history + pub ft4_history: Arc, Ft8Message)>>>, + /// FT2 decode history + pub ft2_history: Arc, Ft8Message)>>>, + /// WSPR decode history + pub wspr_history: Arc, WsprMessage)>>>, /// Authentication tokens for HTTP-JSON frontend pub auth_tokens: HashSet, /// Active HTTP SSE clients (incremented on /events connect, decremented on disconnect). diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js index 365e9ca..6eea5e5 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js @@ -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; diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html index f25a00f..93aa01c 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html @@ -368,6 +368,9 @@