[fix](trx-frontend-http): refresh background decode settings UI
Co-authored-by: OpenAI Codex <codex@openai.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -750,6 +750,7 @@ function applyRigList(activeRigId, rigIds, displayNames) {
|
||||
populateRigPicker(headerRigSwitchSelect, lastRigIds, activeRigId, disableSwitch);
|
||||
updateRigSubtitle(activeRigId);
|
||||
if (typeof reloadSchedulerRigSelect === "function") reloadSchedulerRigSelect();
|
||||
if (typeof reloadBackgroundDecodeRigSelect === "function") reloadBackgroundDecodeRigSelect();
|
||||
}
|
||||
|
||||
async function refreshRigList() {
|
||||
|
||||
@@ -804,7 +804,7 @@
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<div id="background-decode-bookmark-list" class="bgd-bookmark-list"></div>
|
||||
<div id="background-decode-bookmark-list" class="sch-extra-bm-list bgd-bookmark-list"></div>
|
||||
</div>
|
||||
|
||||
<div class="sch-actions">
|
||||
|
||||
+27
-9
@@ -26,6 +26,7 @@
|
||||
if (!sel) return;
|
||||
const rigs = typeof getAvailableRigIds === "function" ? getAvailableRigIds() : [];
|
||||
if (!rigs.length) return;
|
||||
const prevRigId = currentRigId;
|
||||
sel.innerHTML = "";
|
||||
rigs.forEach(function (rigId) {
|
||||
const opt = document.createElement("option");
|
||||
@@ -37,6 +38,11 @@
|
||||
if (!currentRigId || !rigs.includes(currentRigId)) {
|
||||
currentRigId = rigs[0];
|
||||
sel.value = currentRigId;
|
||||
} else {
|
||||
sel.value = currentRigId;
|
||||
}
|
||||
if (currentRigId && currentRigId !== prevRigId) {
|
||||
loadBackgroundDecode();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,14 +164,13 @@
|
||||
ids.forEach(function (id) {
|
||||
const bookmark = bookmarkList.find(function (item) { return item.id === id; });
|
||||
const chip = document.createElement("div");
|
||||
chip.className = "bgd-bookmark-chip";
|
||||
chip.className = "sch-extra-bm-tag bgd-bookmark-tag";
|
||||
const decoders = bookmarkDecoderKinds(bookmark);
|
||||
chip.innerHTML =
|
||||
'<span>' + escHtml(bookmark ? bookmark.name : id) + '</span>' +
|
||||
'<span class="bgd-bookmark-chip-meta">' + escHtml(bookmark ? (formatFreq(bookmark.freq_hz) + " " + bookmark.mode + " · " + decoders.join("/").toUpperCase()) : "Missing bookmark") + '</span>';
|
||||
const btn = document.createElement("button");
|
||||
btn.type = "button";
|
||||
btn.className = "bgd-bookmark-chip-remove sch-write";
|
||||
'<span class="bgd-bookmark-meta">' + escHtml(bookmark ? (formatFreq(bookmark.freq_hz) + " " + bookmark.mode + " · " + decoders.join("/").toUpperCase()) : "Missing bookmark") + '</span>';
|
||||
const btn = document.createElement("span");
|
||||
btn.className = "sch-extra-bm-rm";
|
||||
btn.textContent = "×";
|
||||
btn.addEventListener("click", function () {
|
||||
removeBookmark(id);
|
||||
@@ -293,9 +298,11 @@
|
||||
case "active": return "Active";
|
||||
case "out_of_span": return "Out of span";
|
||||
case "waiting_for_spectrum": return "Waiting";
|
||||
case "waiting_for_user": return "No user";
|
||||
case "missing_bookmark": return "Missing";
|
||||
case "no_supported_decoders": return "Unsupported";
|
||||
case "disabled": return "Disabled";
|
||||
case "handled_by_scheduler": return "Scheduler";
|
||||
default: return "Inactive";
|
||||
}
|
||||
}
|
||||
@@ -333,7 +340,8 @@
|
||||
|
||||
function wireBackgroundDecodeEvents() {
|
||||
const rigSel = document.getElementById("background-decode-rig-select");
|
||||
if (rigSel) {
|
||||
if (rigSel && !rigSel._wired) {
|
||||
rigSel._wired = true;
|
||||
rigSel.addEventListener("change", function () {
|
||||
currentRigId = rigSel.value;
|
||||
loadBackgroundDecode();
|
||||
@@ -341,15 +349,25 @@
|
||||
}
|
||||
|
||||
const addBtn = document.getElementById("background-decode-bookmark-add");
|
||||
if (addBtn) addBtn.addEventListener("click", addBookmark);
|
||||
if (addBtn && !addBtn._wired) {
|
||||
addBtn._wired = true;
|
||||
addBtn.addEventListener("click", addBookmark);
|
||||
}
|
||||
|
||||
const saveBtn = document.getElementById("background-decode-save-btn");
|
||||
if (saveBtn) saveBtn.addEventListener("click", saveBackgroundDecode);
|
||||
if (saveBtn && !saveBtn._wired) {
|
||||
saveBtn._wired = true;
|
||||
saveBtn.addEventListener("click", saveBackgroundDecode);
|
||||
}
|
||||
|
||||
const resetBtn = document.getElementById("background-decode-reset-btn");
|
||||
if (resetBtn) resetBtn.addEventListener("click", resetBackgroundDecode);
|
||||
if (resetBtn && !resetBtn._wired) {
|
||||
resetBtn._wired = true;
|
||||
resetBtn.addEventListener("click", resetBackgroundDecode);
|
||||
}
|
||||
}
|
||||
|
||||
window.initBackgroundDecode = initBackgroundDecode;
|
||||
window.wireBackgroundDecodeEvents = wireBackgroundDecodeEvents;
|
||||
window.reloadBackgroundDecodeRigSelect = renderRigSelect;
|
||||
})();
|
||||
|
||||
@@ -3493,6 +3493,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
|
||||
.sch-extra-bm-rm:hover { opacity: 1; }
|
||||
.bgd-toggle-wrap {
|
||||
min-width: 18rem;
|
||||
flex: 1 1 20rem;
|
||||
}
|
||||
.bgd-toggle-row {
|
||||
display: inline-flex;
|
||||
@@ -3506,41 +3507,25 @@ button:focus-visible, input:focus-visible, select:focus-visible {
|
||||
display: flex;
|
||||
gap: 0.55rem;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
.bgd-bookmark-pick {
|
||||
min-width: min(34rem, 100%);
|
||||
flex: 1 1 28rem;
|
||||
min-width: 16rem;
|
||||
}
|
||||
.bgd-add-row .status-input {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.bgd-bookmark-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.55rem;
|
||||
min-height: 1.8rem;
|
||||
}
|
||||
.bgd-bookmark-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.45rem;
|
||||
padding: 0.35rem 0.55rem;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--border-light);
|
||||
background: var(--btn-bg);
|
||||
color: var(--text);
|
||||
font-size: 0.85rem;
|
||||
.bgd-bookmark-tag {
|
||||
padding-right: 0.3rem;
|
||||
}
|
||||
.bgd-bookmark-chip-meta {
|
||||
.bgd-bookmark-meta {
|
||||
color: var(--text-muted);
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
.bgd-bookmark-chip-remove {
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--text-muted);
|
||||
cursor: pointer;
|
||||
padding: 0;
|
||||
height: auto;
|
||||
}
|
||||
.bgd-bookmark-chip-remove:hover {
|
||||
color: var(--text);
|
||||
}
|
||||
.bgd-status-list {
|
||||
display: grid;
|
||||
gap: 0.65rem;
|
||||
@@ -3572,7 +3557,9 @@ button:focus-visible, input:focus-visible, select:focus-visible {
|
||||
}
|
||||
.bgd-status-state[data-state="out_of_span"],
|
||||
.bgd-status-state[data-state="waiting_for_spectrum"],
|
||||
.bgd-status-state[data-state="inactive"] {
|
||||
.bgd-status-state[data-state="waiting_for_user"],
|
||||
.bgd-status-state[data-state="inactive"],
|
||||
.bgd-status-state[data-state="handled_by_scheduler"] {
|
||||
color: var(--accent-yellow);
|
||||
}
|
||||
.bgd-status-state[data-state="missing_bookmark"],
|
||||
@@ -3591,4 +3578,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
.bgd-add-row button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -17,6 +18,7 @@ use trx_frontend::{FrontendRuntimeContext, SharedSpectrum, VChanAudioCmd};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::server::bookmarks::{Bookmark, BookmarkStore};
|
||||
use crate::server::scheduler::SchedulerStatusMap;
|
||||
|
||||
const SUPPORTED_DECODER_KINDS: &[&str] = &["ft8", "wspr", "hf-aprs"];
|
||||
const CHANNEL_KIND_NAME: &str = "VirtualBackgroundDecodeChannel";
|
||||
@@ -119,6 +121,7 @@ pub struct BackgroundDecodeManager {
|
||||
store: Arc<BackgroundDecodeStore>,
|
||||
bookmarks: Arc<BookmarkStore>,
|
||||
context: Arc<FrontendRuntimeContext>,
|
||||
scheduler_status: SchedulerStatusMap,
|
||||
status: Arc<RwLock<HashMap<String, BackgroundDecodeStatus>>>,
|
||||
notify_tx: broadcast::Sender<()>,
|
||||
}
|
||||
@@ -128,12 +131,14 @@ impl BackgroundDecodeManager {
|
||||
store: Arc<BackgroundDecodeStore>,
|
||||
bookmarks: Arc<BookmarkStore>,
|
||||
context: Arc<FrontendRuntimeContext>,
|
||||
scheduler_status: SchedulerStatusMap,
|
||||
) -> Arc<Self> {
|
||||
let (notify_tx, _) = broadcast::channel(16);
|
||||
Arc::new(Self {
|
||||
store,
|
||||
bookmarks,
|
||||
context,
|
||||
scheduler_status,
|
||||
status: Arc::new(RwLock::new(HashMap::new())),
|
||||
notify_tx,
|
||||
})
|
||||
@@ -296,6 +301,12 @@ impl BackgroundDecodeManager {
|
||||
|
||||
let config = self.get_config(&rig_id);
|
||||
let selected = dedup_ids(&config.bookmark_ids);
|
||||
let users_connected = self.context.sse_clients.load(Ordering::Relaxed) > 0;
|
||||
let scheduled_bookmark_ids = if users_connected {
|
||||
Vec::new()
|
||||
} else {
|
||||
self.scheduler_bookmark_ids(&rig_id)
|
||||
};
|
||||
let selected_bookmarks: HashMap<String, Bookmark> = self
|
||||
.bookmarks
|
||||
.list()
|
||||
@@ -344,6 +355,18 @@ impl BackgroundDecodeManager {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !users_connected {
|
||||
status.state = "waiting_for_user".to_string();
|
||||
statuses.push(status);
|
||||
continue;
|
||||
}
|
||||
|
||||
if scheduled_bookmark_ids.iter().any(|id| id == &bookmark.id) {
|
||||
status.state = "handled_by_scheduler".to_string();
|
||||
statuses.push(status);
|
||||
continue;
|
||||
}
|
||||
|
||||
let (Some(center_hz), Some(half_span_hz)) = (center_hz, half_span_hz) else {
|
||||
status.state = "waiting_for_spectrum".to_string();
|
||||
statuses.push(status);
|
||||
@@ -409,6 +432,28 @@ impl BackgroundDecodeManager {
|
||||
}
|
||||
}
|
||||
|
||||
fn scheduler_bookmark_ids(&self, rig_id: &str) -> Vec<String> {
|
||||
let Ok(guard) = self.scheduler_status.read() else {
|
||||
return Vec::new();
|
||||
};
|
||||
let Some(status) = guard.get(rig_id) else {
|
||||
return Vec::new();
|
||||
};
|
||||
if !status.active {
|
||||
return Vec::new();
|
||||
}
|
||||
let mut out = Vec::new();
|
||||
if let Some(id) = status.last_bookmark_id.clone() {
|
||||
out.push(id);
|
||||
}
|
||||
for id in &status.last_bookmark_ids {
|
||||
if !out.iter().any(|existing| existing == id) {
|
||||
out.push(id.clone());
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
async fn run(self: Arc<Self>) {
|
||||
let mut runtime = BackgroundRuntimeState::default();
|
||||
let mut notify_rx = self.notify_tx.subscribe();
|
||||
|
||||
@@ -92,6 +92,7 @@ async fn serve(
|
||||
background_decode_store,
|
||||
bookmark_store.clone(),
|
||||
context.clone(),
|
||||
scheduler_status.clone(),
|
||||
);
|
||||
background_decode_mgr.spawn();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user