Authenticated as: --
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/ais.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/ais.js
index 1359554..3b602f6 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/ais.js
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/ais.js
@@ -2,8 +2,6 @@
const aisStatus = document.getElementById("ais-status");
const aisMessagesEl = document.getElementById("ais-messages");
const aisFilterInput = document.getElementById("ais-filter");
-const aisPauseBtn = document.getElementById("ais-pause-btn");
-const aisClearBtn = document.getElementById("ais-clear-btn");
const aisBarOverlay = document.getElementById("ais-bar-overlay");
const aisChannelSummaryEl = document.getElementById("ais-channel-summary");
const aisVesselCountEl = document.getElementById("ais-vessel-count");
@@ -13,8 +11,6 @@ const AIS_DEFAULT_A_HZ = 161_975_000;
const AIS_CHANNEL_SPACING_HZ = 50_000;
let aisFilterText = "";
let aisMessageHistory = [];
-let aisPaused = false;
-let aisBufferedWhilePaused = 0;
function currentAisHistoryRetentionMs() {
return typeof window.getDecodeHistoryRetentionMs === "function"
@@ -161,11 +157,7 @@ function updateAisSummary() {
const vessels = aisLatestByVessel(aisMessageHistory);
if (aisVesselCountEl) {
const count = vessels.length;
- let text = `${count} vessel${count === 1 ? "" : "s"}`;
- if (aisPaused && aisBufferedWhilePaused > 0) {
- text += ` · ${aisBufferedWhilePaused} buffered`;
- }
- aisVesselCountEl.textContent = text;
+ aisVesselCountEl.textContent = `${count} vessel${count === 1 ? "" : "s"}`;
}
if (aisLatestSeenEl) {
@@ -177,10 +169,6 @@ function updateAisSummary() {
aisLatestSeenEl.textContent = `${channel.label} ${aisAgeText(latest._tsMs)}`;
}
}
- if (aisPauseBtn) {
- aisPauseBtn.textContent = aisPaused ? "Resume" : "Pause";
- aisPauseBtn.classList.toggle("active", aisPaused);
- }
}
function renderAisRow(msg) {
@@ -292,13 +280,12 @@ function updateAisBar() {
}
window.updateAisBar = updateAisBar;
window.clearAisBar = function() {
- document.getElementById("ais-clear-btn")?.click();
+ window.resetAisHistoryView();
};
window.resetAisHistoryView = function() {
if (aisMessagesEl) aisMessagesEl.innerHTML = "";
aisMessageHistory = [];
- aisBufferedWhilePaused = 0;
updateAisBar();
renderAisHistory();
if (window.clearMapMarkersByType) window.clearMapMarkersByType("ais");
@@ -306,7 +293,7 @@ window.resetAisHistoryView = function() {
function renderAisHistory() {
pruneAisMessageHistory();
- if (!aisMessagesEl || aisPaused) {
+ if (!aisMessagesEl) {
updateAisSummary();
return;
}
@@ -330,13 +317,7 @@ function addAisMessage(msg) {
aisMessageHistory.unshift(msg);
pruneAisMessageHistory();
scheduleAisBarUpdate();
-
- if (aisPaused) {
- aisBufferedWhilePaused += 1;
- updateAisSummary();
- } else {
- scheduleAisHistoryRender();
- }
+ scheduleAisHistoryRender();
if (msg.lat != null && msg.lon != null && window.aisMapAddVessel) {
window.aisMapAddVessel(msg);
@@ -362,7 +343,7 @@ function normalizeServerAisMessage(msg) {
window.onServerAisBatch = function(messages) {
if (!Array.isArray(messages) || messages.length === 0) return;
- if (aisStatus) aisStatus.textContent = aisPaused ? "Paused" : "Receiving";
+ if (aisStatus) aisStatus.textContent = "Receiving";
const normalized = [];
for (const msg of messages) {
const next = normalizeServerAisMessage(msg);
@@ -382,11 +363,6 @@ window.onServerAisBatch = function(messages) {
aisMessageHistory = normalized.concat(aisMessageHistory);
pruneAisMessageHistory();
scheduleAisBarUpdate();
- if (aisPaused) {
- aisBufferedWhilePaused += messages.length;
- updateAisSummary();
- return;
- }
scheduleAisHistoryRender();
};
@@ -400,28 +376,14 @@ window.pruneAisHistoryView = function() {
renderAisHistory();
};
-if (aisClearBtn) {
- aisClearBtn.addEventListener("click", async () => {
- try {
- await postPath("/clear_ais_decode");
- window.resetAisHistoryView();
- } catch (e) {
- console.error("AIS clear failed", e);
- }
- });
-}
-
-if (aisPauseBtn) {
- aisPauseBtn.addEventListener("click", () => {
- aisPaused = !aisPaused;
- if (!aisPaused) {
- aisBufferedWhilePaused = 0;
- renderAisHistory();
- } else {
- updateAisSummary();
- }
- });
-}
+document.getElementById("settings-clear-ais-history")?.addEventListener("click", async () => {
+ try {
+ await postPath("/clear_ais_decode");
+ window.resetAisHistoryView();
+ } catch (e) {
+ console.error("AIS history clear failed", e);
+ }
+});
if (aisFilterInput) {
aisFilterInput.addEventListener("input", () => {
@@ -431,7 +393,7 @@ if (aisFilterInput) {
}
window.onServerAis = function(msg) {
- if (aisStatus) aisStatus.textContent = aisPaused ? "Paused" : "Receiving";
+ if (aisStatus) aisStatus.textContent = "Receiving";
addAisMessage(normalizeServerAisMessage(msg));
};
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/aprs.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/aprs.js
index 0a2ba4a..125dd28 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/aprs.js
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/aprs.js
@@ -3,7 +3,6 @@ const aprsStatus = document.getElementById("aprs-status");
const aprsPacketsEl = document.getElementById("aprs-packets");
const aprsFilterInput = document.getElementById("aprs-filter");
const aprsBarOverlay = document.getElementById("aprs-bar-overlay");
-const aprsPauseBtn = document.getElementById("aprs-pause-btn");
const aprsOnlyPosBtn = document.getElementById("aprs-only-pos-btn");
const aprsHideCrcBtn = document.getElementById("aprs-hide-crc-btn");
const aprsCollapseDupBtn = document.getElementById("aprs-collapse-dup-btn");
@@ -13,8 +12,7 @@ const aprsLatestSeenEl = document.getElementById("aprs-latest-seen");
const APRS_BAR_WINDOW_MS = 15 * 60 * 1000;
let aprsFilterText = "";
let aprsPacketHistory = [];
-let aprsPaused = false;
-let aprsBufferedWhilePaused = 0;
+let aprsBarDismissedAtMs = 0;
let aprsOnlyPos = false;
let aprsHideCrc = false;
let aprsCollapseDup = false;
@@ -187,11 +185,7 @@ function updateAprsSummary() {
aprsTotalCountEl.textContent = `${aprsPacketHistory.length} total`;
}
if (aprsVisibleCountEl) {
- let text = `${visible.length} shown`;
- if (aprsPaused && aprsBufferedWhilePaused > 0) {
- text += ` · ${aprsBufferedWhilePaused} buffered`;
- }
- aprsVisibleCountEl.textContent = text;
+ aprsVisibleCountEl.textContent = `${visible.length} shown`;
}
if (aprsLatestSeenEl) {
const latest = aprsPacketHistory[0];
@@ -210,10 +204,6 @@ function updateAprsChipState() {
aprsOnlyPosBtn?.classList.toggle("active", aprsOnlyPos);
aprsHideCrcBtn?.classList.toggle("active", aprsHideCrc);
aprsCollapseDupBtn?.classList.toggle("active", aprsCollapseDup);
- if (aprsPauseBtn) {
- aprsPauseBtn.textContent = aprsPaused ? "Resume" : "Pause";
- aprsPauseBtn.classList.toggle("active", aprsPaused);
- }
}
function renderAprsRow(pkt, isFresh) {
@@ -315,7 +305,7 @@ function renderAprsRow(pkt, isFresh) {
function renderAprsHistory() {
pruneAprsPacketHistory();
- if (!aprsPacketsEl || aprsPaused) {
+ if (!aprsPacketsEl) {
updateAprsSummary();
updateAprsChipState();
return;
@@ -336,11 +326,13 @@ function updateAprsBar() {
const cutoffMs = Date.now() - APRS_BAR_WINDOW_MS;
const okFrames = aprsPacketHistory.filter((p) => p.crcOk && p._tsMs >= cutoffMs);
const frames = collapseAprsDuplicates(okFrames).slice(0, 8);
- if (!isPkt || frames.length === 0) {
+ const newestTsMs = frames.reduce((latest, pkt) => Math.max(latest, Number(pkt._tsMs) || 0), 0);
+ if (!isPkt || frames.length === 0 || newestTsMs <= aprsBarDismissedAtMs) {
aprsBarOverlay.style.display = "none";
+ aprsBarOverlay.innerHTML = "";
return;
}
- let html = '';
+ let html = '';
for (const pkt of frames) {
const ts = pkt._ts ? `
${pkt._ts}` : "";
const call = `
${escapeMapHtml(pkt.srcCall)}`;
@@ -358,13 +350,19 @@ function updateAprsBar() {
}
window.updateAprsBar = updateAprsBar;
window.clearAprsBar = function() {
- document.getElementById("aprs-clear-btn")?.click();
+ window.resetAprsHistoryView();
+};
+window.closeAprsBar = function() {
+ aprsBarDismissedAtMs = Date.now();
+ if (aprsBarOverlay) {
+ aprsBarOverlay.style.display = "none";
+ aprsBarOverlay.innerHTML = "";
+ }
};
window.resetAprsHistoryView = function() {
if (aprsPacketsEl) aprsPacketsEl.innerHTML = "";
aprsPacketHistory = [];
- aprsBufferedWhilePaused = 0;
updateAprsBar();
renderAprsHistory();
if (window.clearMapMarkersByType) window.clearMapMarkersByType("aprs");
@@ -390,13 +388,6 @@ function addAprsPacket(pkt) {
if (pkt.crcOk) scheduleAprsBarUpdate();
- if (aprsPaused) {
- aprsBufferedWhilePaused += 1;
- updateAprsSummary();
- updateAprsChipState();
- return;
- }
-
scheduleAprsHistoryRender();
}
@@ -420,7 +411,7 @@ function normalizeServerAprsPacket(pkt) {
window.onServerAprsBatch = function(packets) {
if (!Array.isArray(packets) || packets.length === 0) return;
- aprsStatus.textContent = aprsPaused ? "Paused" : "Receiving";
+ aprsStatus.textContent = "Receiving";
const normalized = [];
let hasCrcOk = false;
for (const pkt of packets) {
@@ -438,12 +429,6 @@ window.onServerAprsBatch = function(packets) {
aprsPacketHistory = normalized.concat(aprsPacketHistory);
pruneAprsPacketHistory();
if (hasCrcOk) scheduleAprsBarUpdate();
- if (aprsPaused) {
- aprsBufferedWhilePaused += packets.length;
- updateAprsSummary();
- updateAprsChipState();
- return;
- }
scheduleAprsHistoryRender();
};
@@ -451,28 +436,15 @@ window.restoreAprsHistory = function(packets) {
window.onServerAprsBatch(packets);
};
-document.getElementById("aprs-clear-btn").addEventListener("click", async () => {
+document.getElementById("settings-clear-aprs-history")?.addEventListener("click", async () => {
try {
await postPath("/clear_aprs_decode");
window.resetAprsHistoryView();
} catch (e) {
- console.error("APRS clear failed", e);
+ console.error("APRS history clear failed", e);
}
});
-if (aprsPauseBtn) {
- aprsPauseBtn.addEventListener("click", () => {
- aprsPaused = !aprsPaused;
- if (!aprsPaused) {
- aprsBufferedWhilePaused = 0;
- renderAprsHistory();
- } else {
- updateAprsSummary();
- updateAprsChipState();
- }
- });
-}
-
if (aprsOnlyPosBtn) {
aprsOnlyPosBtn.addEventListener("click", () => {
aprsOnlyPos = !aprsOnlyPos;
@@ -512,7 +484,7 @@ if (aprsFilterInput) {
// --- Server-side APRS decode handler ---
window.onServerAprs = function(pkt) {
- aprsStatus.textContent = aprsPaused ? "Paused" : "Receiving";
+ aprsStatus.textContent = "Receiving";
addAprsPacket(normalizeServerAprsPacket(pkt));
};
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/cw.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/cw.js
index e407439..7ab89ec 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/cw.js
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/cw.js
@@ -1,7 +1,6 @@
// --- CW (Morse) Decoder Plugin (server-side decode) ---
const cwStatusEl = document.getElementById("cw-status");
const cwOutputEl = document.getElementById("cw-output");
-const cwPauseBtn = document.getElementById("cw-pause-btn");
const cwAutoInput = document.getElementById("cw-auto");
const cwWpmInput = document.getElementById("cw-wpm");
const cwToneInput = document.getElementById("cw-tone");
@@ -22,10 +21,9 @@ const CW_BAR_WINDOW_MS = 15 * 60 * 1000;
const CW_BAR_LINE_GAP_MS = 5000;
let cwLastAppendTime = 0;
let cwTonePickerRaf = null;
-let cwPaused = false;
-let cwBufferedWhilePaused = 0;
let cwBarHistory = []; // [{tsMs, ts, text, wpm, tone_hz}]
let cwBarCurrentLine = null; // accumulates chars until gap/newline
+let cwBarDismissedAtMs = 0;
// Tracks a user-initiated auto toggle that is in-flight (POST not yet
// acknowledged). While set, server-state updates must not override the
// checkbox so that a concurrent SSE event carrying the *old* cw_auto value
@@ -71,18 +69,23 @@ function updateCwBar() {
const recent = cwBarHistory.filter((l) => l.tsMs >= cutoffMs);
// Prepend the in-progress line so characters appear immediately
const liveLines = cwBarCurrentLine && cwBarCurrentLine.text ? [cwBarCurrentLine, ...recent] : recent;
- if (!isCw || liveLines.length === 0) {
+ const newestTsMs = liveLines.reduce((latest, line) => Math.max(latest, Number(line.tsMs) || 0), 0);
+ if (!isCw || liveLines.length === 0 || newestTsMs <= cwBarDismissedAtMs) {
cwBarOverlay.style.display = "none";
+ cwBarOverlay.innerHTML = "";
return;
}
let html =
'';
for (const line of liveLines.slice(0, 8)) {
const ts = line.ts ? `
${line.ts}` : "";
@@ -100,7 +103,14 @@ function updateCwBar() {
}
window.updateCwBar = updateCwBar;
window.clearCwBar = function() {
- document.getElementById("cw-clear-btn")?.click();
+ window.resetCwHistoryView();
+};
+window.closeCwBar = function() {
+ cwBarDismissedAtMs = Date.now();
+ if (cwBarOverlay) {
+ cwBarOverlay.style.display = "none";
+ cwBarOverlay.innerHTML = "";
+ }
};
function clampCwWpm(wpm) {
@@ -343,33 +353,25 @@ if (cwToneCanvas) {
window.resetCwHistoryView = function() {
if (cwOutputEl) cwOutputEl.innerHTML = "";
cwLastAppendTime = 0;
- cwBufferedWhilePaused = 0;
cwBarHistory = [];
cwBarCurrentLine = null;
- updateCwPauseUi();
updateCwBar();
drawCwTonePicker();
};
-function updateCwPauseUi() {
- if (!cwPauseBtn) return;
- cwPauseBtn.textContent = cwPaused ? "Resume" : "Pause";
- cwPauseBtn.classList.toggle("active", cwPaused);
-}
-
-document.getElementById("cw-clear-btn").addEventListener("click", async () => {
+document.getElementById("settings-clear-cw-history")?.addEventListener("click", async () => {
try {
await postPath("/clear_cw_decode");
window.resetCwHistoryView();
} catch (e) {
- console.error("CW clear failed", e);
+ console.error("CW history clear failed", e);
}
});
// --- Server-side CW decode handler ---
window.onServerCw = function(evt) {
- if (cwStatusEl) cwStatusEl.textContent = cwPaused ? "Paused" : "Receiving";
- if (evt.text && cwOutputEl && !cwPaused) {
+ if (cwStatusEl) cwStatusEl.textContent = "Receiving";
+ if (evt.text && cwOutputEl) {
// Append decoded text to output
const now = Date.now();
if (!cwOutputEl.lastElementChild || now - cwLastAppendTime > 10000 || evt.text === "\n") {
@@ -408,9 +410,6 @@ window.onServerCw = function(evt) {
if (cwSignalIndicator) {
cwSignalIndicator.className = evt.signal_on ? "cw-signal-on" : "cw-signal-off";
}
- if (cwPaused && evt.text) {
- cwBufferedWhilePaused += 1;
- }
if (!cwAutoInput || cwAutoInput.checked) {
if (cwWpmInput && Number.isFinite(Number(evt.wpm))) {
cwWpmInput.value = clampCwWpm(evt.wpm);
@@ -428,22 +427,12 @@ window.onServerCw = function(evt) {
window.restoreCwHistory = function(events) {
if (!Array.isArray(events) || events.length === 0) return;
- if (cwStatusEl) cwStatusEl.textContent = cwPaused ? "Paused" : "Receiving";
+ if (cwStatusEl) cwStatusEl.textContent = "Receiving";
for (const evt of events) {
window.onServerCw(evt);
}
};
-if (cwPauseBtn) {
- cwPauseBtn.addEventListener("click", () => {
- cwPaused = !cwPaused;
- if (!cwPaused) {
- cwBufferedWhilePaused = 0;
- }
- updateCwPauseUi();
- });
-}
-
window.refreshCwTonePicker = function refreshCwTonePicker() {
ensureCwToneCanvasResolution();
drawCwTonePicker();
@@ -452,7 +441,6 @@ window.addEventListener("resize", () => {
if (ensureCwToneCanvasResolution()) drawCwTonePicker();
});
applyCwAutoUi(!!cwAutoInput?.checked);
-updateCwPauseUi();
updateCwBar();
ensureCwToneCanvasResolution();
drawCwTonePicker();
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/ft2.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/ft2.js
index da7c0f0..0293fc7 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/ft2.js
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/ft2.js
@@ -12,12 +12,9 @@ const ft2Status = document.getElementById("ft2-status");
const ft2PeriodEl = document.getElementById("ft2-period");
const ft2MessagesEl = document.getElementById("ft2-messages");
const ft2FilterInput = document.getElementById("ft2-filter");
-const ft2PauseBtn = document.getElementById("ft2-pause-btn");
const FT2_PERIOD_MS = 3750;
let ft2FilterText = "";
let ft2MessageHistory = [];
-let ft2Paused = false;
-let ft2BufferedWhilePaused = 0;
function currentFt2HistoryRetentionMs() {
return typeof window.getDecodeHistoryRetentionMs === "function"
@@ -78,15 +75,9 @@ function renderFt2Row(msg) {
return row;
}
-function updateFt2PauseUi() {
- if (!ft2PauseBtn) return;
- ft2PauseBtn.textContent = ft2Paused ? "Resume" : "Pause";
- ft2PauseBtn.classList.toggle("active", ft2Paused);
-}
-
function renderFt2History() {
pruneFt2MessageHistory();
- if (!ft2MessagesEl || ft2Paused) { updateFt2PauseUi(); return; }
+ if (!ft2MessagesEl) return;
const filter = ft2FilterText;
const fragment = document.createDocumentFragment();
for (let i = 0; i < ft2MessageHistory.length; i++) {
@@ -95,14 +86,14 @@ function renderFt2History() {
fragment.appendChild(renderFt2Row(msg));
}
ft2MessagesEl.replaceChildren(fragment);
- updateFt2PauseUi();
}
function addFt2Message(msg) {
msg._tsMs = Number.isFinite(msg?.ts_ms) ? Number(msg.ts_ms) : Date.now();
ft2MessageHistory.unshift(msg);
pruneFt2MessageHistory();
- if (ft2Paused) { ft2BufferedWhilePaused += 1; updateFt2PauseUi(); return; }
+ window.setFt8FamilyBarDecoder?.("ft2");
+ window.updateFt8Bar?.();
scheduleFt2HistoryRender();
}
@@ -127,7 +118,7 @@ function normalizeServerFt2Message(msg) {
window.onServerFt2Batch = function(messages) {
if (!Array.isArray(messages) || messages.length === 0) return;
- if (ft2Status) ft2Status.textContent = ft2Paused ? "Paused" : "Receiving";
+ if (ft2Status) ft2Status.textContent = "Receiving";
const normalized = [];
for (const msg of messages) {
const next = normalizeServerFt2Message(msg);
@@ -140,7 +131,8 @@ window.onServerFt2Batch = function(messages) {
normalized.reverse();
ft2MessageHistory = normalized.concat(ft2MessageHistory);
pruneFt2MessageHistory();
- if (ft2Paused) { ft2BufferedWhilePaused += messages.length; updateFt2PauseUi(); return; }
+ window.setFt8FamilyBarDecoder?.("ft2");
+ window.updateFt8Bar?.();
scheduleFt2HistoryRender();
};
@@ -150,10 +142,33 @@ window.pruneFt2HistoryView = function() { pruneFt2MessageHistory(); renderFt2His
window.resetFt2HistoryView = function() {
if (ft2MessagesEl) ft2MessagesEl.innerHTML = "";
ft2MessageHistory = [];
- ft2BufferedWhilePaused = 0;
+ window.updateFt8Bar?.();
renderFt2History();
};
+function buildFt2BarFrames() {
+ const cutoffMs = Date.now() - 15 * 60 * 1000;
+ const messages = ft2MessageHistory.filter((msg) => Number(msg._tsMs ?? msg.ts_ms) >= cutoffMs).slice(0, 8);
+ const newestTsMs = messages.reduce((latest, msg) => Math.max(latest, Number(msg._tsMs ?? msg.ts_ms) || 0), 0);
+ if (messages.length === 0) {
+ return { count: 0, newestTsMs: 0, html: "" };
+ }
+ let html = "";
+ for (const msg of messages) {
+ const tsMs = msg._tsMs ?? msg.ts_ms;
+ const ts = tsMs ? `
${fmtTime(tsMs)}` : "";
+ const snr = Number.isFinite(msg.snr_db) ? `${msg.snr_db.toFixed(1)} dB` : "-- dB";
+ const dt = Number.isFinite(msg.dt_s) ? `dt ${msg.dt_s.toFixed(2)}` : null;
+ const displayFreqHz = normalizeFt2DisplayFreqHz(msg.freq_hz);
+ const rf = Number.isFinite(displayFreqHz) ? `${displayFreqHz.toFixed(0)} Hz` : null;
+ const detail = [snr, dt, rf].filter(Boolean).join(" · ");
+ const text = ft8RenderMessageFt2((msg.message || "").toString());
+ html += `
${ts}${text}${detail ? ` · ${detail}` : ""}
`;
+ }
+ return { count: messages.length, newestTsMs, html };
+}
+window.registerFt8FamilyBarRenderer?.("ft2", buildFt2BarFrames);
+
if (ft2FilterInput) {
ft2FilterInput.addEventListener("input", () => {
ft2FilterText = ft2FilterInput.value.trim().toUpperCase();
@@ -161,31 +176,22 @@ if (ft2FilterInput) {
});
}
-if (ft2PauseBtn) {
- ft2PauseBtn.addEventListener("click", () => {
- ft2Paused = !ft2Paused;
- if (!ft2Paused) { ft2BufferedWhilePaused = 0; renderFt2History(); } else { updateFt2PauseUi(); }
- });
-}
-
document.getElementById("ft2-decode-toggle-btn")?.addEventListener("click", async () => {
try { await postPath("/toggle_ft2_decode"); } catch (e) { console.error("FT2 toggle failed", e); }
});
-document.getElementById("ft2-clear-btn")?.addEventListener("click", async () => {
+document.getElementById("settings-clear-ft2-history")?.addEventListener("click", async () => {
try {
await postPath("/clear_ft2_decode");
window.resetFt2HistoryView();
- } catch (e) { console.error("FT2 clear failed", e); }
+ } catch (e) { console.error("FT2 history clear failed", e); }
});
window.onServerFt2 = function(msg) {
- if (ft2Status) ft2Status.textContent = ft2Paused ? "Paused" : "Receiving";
+ if (ft2Status) ft2Status.textContent = "Receiving";
const next = normalizeServerFt2Message(msg);
if (next.grids.length > 0 && window.mapAddLocator) {
window.mapAddLocator(next.raw, next.grids, "ft2", next.station, { ...msg, freq_hz: next.rfHz, locator_details: next.locatorDetails });
}
addFt2Message(next.history);
};
-
-updateFt2PauseUi();
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/ft4.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/ft4.js
index 372a49c..87eeede 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/ft4.js
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/ft4.js
@@ -12,12 +12,9 @@ const ft4Status = document.getElementById("ft4-status");
const ft4PeriodEl = document.getElementById("ft4-period");
const ft4MessagesEl = document.getElementById("ft4-messages");
const ft4FilterInput = document.getElementById("ft4-filter");
-const ft4PauseBtn = document.getElementById("ft4-pause-btn");
const FT4_PERIOD_MS = 7500;
let ft4FilterText = "";
let ft4MessageHistory = [];
-let ft4Paused = false;
-let ft4BufferedWhilePaused = 0;
function currentFt4HistoryRetentionMs() {
return typeof window.getDecodeHistoryRetentionMs === "function"
@@ -78,15 +75,9 @@ function renderFt4Row(msg) {
return row;
}
-function updateFt4PauseUi() {
- if (!ft4PauseBtn) return;
- ft4PauseBtn.textContent = ft4Paused ? "Resume" : "Pause";
- ft4PauseBtn.classList.toggle("active", ft4Paused);
-}
-
function renderFt4History() {
pruneFt4MessageHistory();
- if (!ft4MessagesEl || ft4Paused) { updateFt4PauseUi(); return; }
+ if (!ft4MessagesEl) return;
const filter = ft4FilterText;
const fragment = document.createDocumentFragment();
for (let i = 0; i < ft4MessageHistory.length; i++) {
@@ -95,14 +86,14 @@ function renderFt4History() {
fragment.appendChild(renderFt4Row(msg));
}
ft4MessagesEl.replaceChildren(fragment);
- updateFt4PauseUi();
}
function addFt4Message(msg) {
msg._tsMs = Number.isFinite(msg?.ts_ms) ? Number(msg.ts_ms) : Date.now();
ft4MessageHistory.unshift(msg);
pruneFt4MessageHistory();
- if (ft4Paused) { ft4BufferedWhilePaused += 1; updateFt4PauseUi(); return; }
+ window.setFt8FamilyBarDecoder?.("ft4");
+ window.updateFt8Bar?.();
scheduleFt4HistoryRender();
}
@@ -127,7 +118,7 @@ function normalizeServerFt4Message(msg) {
window.onServerFt4Batch = function(messages) {
if (!Array.isArray(messages) || messages.length === 0) return;
- if (ft4Status) ft4Status.textContent = ft4Paused ? "Paused" : "Receiving";
+ if (ft4Status) ft4Status.textContent = "Receiving";
const normalized = [];
for (const msg of messages) {
const next = normalizeServerFt4Message(msg);
@@ -140,7 +131,8 @@ window.onServerFt4Batch = function(messages) {
normalized.reverse();
ft4MessageHistory = normalized.concat(ft4MessageHistory);
pruneFt4MessageHistory();
- if (ft4Paused) { ft4BufferedWhilePaused += messages.length; updateFt4PauseUi(); return; }
+ window.setFt8FamilyBarDecoder?.("ft4");
+ window.updateFt8Bar?.();
scheduleFt4HistoryRender();
};
@@ -150,10 +142,33 @@ window.pruneFt4HistoryView = function() { pruneFt4MessageHistory(); renderFt4His
window.resetFt4HistoryView = function() {
if (ft4MessagesEl) ft4MessagesEl.innerHTML = "";
ft4MessageHistory = [];
- ft4BufferedWhilePaused = 0;
+ window.updateFt8Bar?.();
renderFt4History();
};
+function buildFt4BarFrames() {
+ const cutoffMs = Date.now() - 15 * 60 * 1000;
+ const messages = ft4MessageHistory.filter((msg) => Number(msg._tsMs ?? msg.ts_ms) >= cutoffMs).slice(0, 8);
+ const newestTsMs = messages.reduce((latest, msg) => Math.max(latest, Number(msg._tsMs ?? msg.ts_ms) || 0), 0);
+ if (messages.length === 0) {
+ return { count: 0, newestTsMs: 0, html: "" };
+ }
+ let html = "";
+ for (const msg of messages) {
+ const tsMs = msg._tsMs ?? msg.ts_ms;
+ const ts = tsMs ? `
${fmtTime(tsMs)}` : "";
+ const snr = Number.isFinite(msg.snr_db) ? `${msg.snr_db.toFixed(1)} dB` : "-- dB";
+ const dt = Number.isFinite(msg.dt_s) ? `dt ${msg.dt_s.toFixed(2)}` : null;
+ const displayFreqHz = normalizeFt4DisplayFreqHz(msg.freq_hz);
+ const rf = Number.isFinite(displayFreqHz) ? `${displayFreqHz.toFixed(0)} Hz` : null;
+ const detail = [snr, dt, rf].filter(Boolean).join(" · ");
+ const text = ft8RenderMessage((msg.message || "").toString());
+ html += `
${ts}${text}${detail ? ` · ${detail}` : ""}
`;
+ }
+ return { count: messages.length, newestTsMs, html };
+}
+window.registerFt8FamilyBarRenderer?.("ft4", buildFt4BarFrames);
+
if (ft4FilterInput) {
ft4FilterInput.addEventListener("input", () => {
ft4FilterText = ft4FilterInput.value.trim().toUpperCase();
@@ -161,31 +176,22 @@ if (ft4FilterInput) {
});
}
-if (ft4PauseBtn) {
- ft4PauseBtn.addEventListener("click", () => {
- ft4Paused = !ft4Paused;
- if (!ft4Paused) { ft4BufferedWhilePaused = 0; renderFt4History(); } else { updateFt4PauseUi(); }
- });
-}
-
document.getElementById("ft4-decode-toggle-btn")?.addEventListener("click", async () => {
try { await postPath("/toggle_ft4_decode"); } catch (e) { console.error("FT4 toggle failed", e); }
});
-document.getElementById("ft4-clear-btn")?.addEventListener("click", async () => {
+document.getElementById("settings-clear-ft4-history")?.addEventListener("click", async () => {
try {
await postPath("/clear_ft4_decode");
window.resetFt4HistoryView();
- } catch (e) { console.error("FT4 clear failed", e); }
+ } catch (e) { console.error("FT4 history clear failed", e); }
});
window.onServerFt4 = function(msg) {
- if (ft4Status) ft4Status.textContent = ft4Paused ? "Paused" : "Receiving";
+ if (ft4Status) ft4Status.textContent = "Receiving";
const next = normalizeServerFt4Message(msg);
if (next.grids.length > 0 && window.mapAddLocator) {
window.mapAddLocator(next.raw, next.grids, "ft4", next.station, { ...msg, freq_hz: next.rfHz, locator_details: next.locatorDetails });
}
addFt4Message(next.history);
};
-
-updateFt4PauseUi();
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/ft8.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/ft8.js
index 6d1292c..69e26aa 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/ft8.js
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/ft8.js
@@ -3,14 +3,23 @@ const ft8Status = document.getElementById("ft8-status");
const ft8PeriodEl = document.getElementById("ft8-period");
const ft8MessagesEl = document.getElementById("ft8-messages");
const ft8FilterInput = document.getElementById("ft8-filter");
-const ft8PauseBtn = document.getElementById("ft8-pause-btn");
const ft8BarOverlay = document.getElementById("ft8-bar-overlay");
const FT8_BAR_WINDOW_MS = 15 * 60 * 1000;
const FT8_PERIOD_SECONDS = 15;
+const FT8_BAR_DECODER_LABELS = {
+ ft8: "FT8",
+ ft4: "FT4",
+ ft2: "FT2",
+};
let ft8FilterText = "";
let ft8MessageHistory = [];
-let ft8Paused = false;
-let ft8BufferedWhilePaused = 0;
+let ft8BarActiveDecoder = "ft8";
+const ft8BarBuilders = {};
+const ft8BarDismissedAtMsByDecoder = {
+ ft8: 0,
+ ft4: 0,
+ ft2: 0,
+};
function currentFt8HistoryRetentionMs() {
return typeof window.getDecodeHistoryRetentionMs === "function"
@@ -39,6 +48,17 @@ function scheduleFt8BarUpdate() {
scheduleFt8Ui("ft8-bar", () => updateFt8Bar());
}
+window.registerFt8FamilyBarRenderer = function(decoder, builder) {
+ if (!FT8_BAR_DECODER_LABELS[decoder] || typeof builder !== "function") return;
+ ft8BarBuilders[decoder] = builder;
+};
+
+window.setFt8FamilyBarDecoder = function(decoder) {
+ if (!FT8_BAR_DECODER_LABELS[decoder]) return;
+ ft8BarActiveDecoder = decoder;
+ scheduleFt8BarUpdate();
+};
+
function normalizeFt8DisplayFreqHz(freqHz) {
const rawHz = Number(freqHz);
if (!Number.isFinite(rawHz)) return null;
@@ -81,36 +101,22 @@ function renderFt8Row(msg) {
return row;
}
-function updateFt8PauseUi() {
- if (!ft8PauseBtn) return;
- ft8PauseBtn.textContent = ft8Paused ? "Resume" : "Pause";
- ft8PauseBtn.classList.toggle("active", ft8Paused);
-}
-
function renderFt8History() {
pruneFt8MessageHistory();
- if (!ft8MessagesEl || ft8Paused) {
- updateFt8PauseUi();
- return;
- }
+ if (!ft8MessagesEl) return;
const fragment = document.createDocumentFragment();
for (let i = 0; i < ft8MessageHistory.length; i += 1) {
fragment.appendChild(renderFt8Row(ft8MessageHistory[i]));
}
ft8MessagesEl.replaceChildren(fragment);
- updateFt8PauseUi();
}
function addFt8Message(msg) {
msg._tsMs = Number.isFinite(msg?.ts_ms) ? Number(msg.ts_ms) : Date.now();
ft8MessageHistory.unshift(msg);
pruneFt8MessageHistory();
+ ft8BarActiveDecoder = "ft8";
scheduleFt8BarUpdate();
- if (ft8Paused) {
- ft8BufferedWhilePaused += 1;
- updateFt8PauseUi();
- return;
- }
scheduleFt8HistoryRender();
}
@@ -141,7 +147,7 @@ function normalizeServerFt8Message(msg) {
window.onServerFt8Batch = function(messages) {
if (!Array.isArray(messages) || messages.length === 0) return;
- ft8Status.textContent = ft8Paused ? "Paused" : "Receiving";
+ ft8Status.textContent = "Receiving";
const normalized = [];
for (const msg of messages) {
const next = normalizeServerFt8Message(msg);
@@ -158,12 +164,8 @@ window.onServerFt8Batch = function(messages) {
normalized.reverse();
ft8MessageHistory = normalized.concat(ft8MessageHistory);
pruneFt8MessageHistory();
+ ft8BarActiveDecoder = "ft8";
scheduleFt8BarUpdate();
- if (ft8Paused) {
- ft8BufferedWhilePaused += messages.length;
- updateFt8PauseUi();
- return;
- }
scheduleFt8HistoryRender();
};
@@ -183,19 +185,14 @@ function ft8BarRfText(msg) {
return `${displayFreqHz.toFixed(0)} Hz`;
}
-function updateFt8Bar() {
- if (!ft8BarOverlay) return;
- const modeUpper = (document.getElementById("mode")?.value || "").toUpperCase();
- const isFt8Mode = modeUpper === "DIG" || modeUpper === "USB";
+function buildFt8BarFrames() {
const cutoffMs = Date.now() - FT8_BAR_WINDOW_MS;
const messages = ft8MessageHistory.filter((msg) => Number(msg.ts_ms) >= cutoffMs).slice(0, 8);
- if (!isFt8Mode || messages.length === 0) {
- ft8BarOverlay.style.display = "none";
- ft8BarOverlay.innerHTML = "";
- return;
+ const newestTsMs = messages.reduce((latest, msg) => Math.max(latest, Number(msg.ts_ms) || 0), 0);
+ if (messages.length === 0) {
+ return { count: 0, newestTsMs: 0, html: "" };
}
-
- let html = '';
+ let html = "";
for (const msg of messages) {
const ts = msg.ts_ms ? `
${fmtTime(msg.ts_ms)}` : "";
const snr = Number.isFinite(msg.snr_db) ? `${msg.snr_db.toFixed(1)} dB` : "-- dB";
@@ -205,13 +202,48 @@ function updateFt8Bar() {
const text = ft8EscapeHtml((msg.message || "").toString());
html += `
${ts}${text}${detail ? ` · ${detail}` : ""}
`;
}
- ft8BarOverlay.innerHTML = html;
+ return { count: messages.length, newestTsMs, html };
+}
+
+function updateFt8Bar() {
+ if (!ft8BarOverlay) return;
+ const modeUpper = (document.getElementById("mode")?.value || "").toUpperCase();
+ const isFt8Mode = modeUpper === "DIG" || modeUpper === "USB";
+ const decoder = ft8BarActiveDecoder;
+ const builder = ft8BarBuilders[decoder];
+ const label = FT8_BAR_DECODER_LABELS[decoder] || "FT8";
+ const result = typeof builder === "function" ? builder() : null;
+ const newestTsMs = Number(result?.newestTsMs) || 0;
+ if (!isFt8Mode || !result || result.count === 0 || newestTsMs <= (ft8BarDismissedAtMsByDecoder[decoder] || 0)) {
+ ft8BarOverlay.style.display = "none";
+ ft8BarOverlay.innerHTML = "";
+ return;
+ }
+
+ ft8BarOverlay.innerHTML = `${result.html}`;
ft8BarOverlay.style.display = "flex";
}
window.updateFt8Bar = updateFt8Bar;
window.clearFt8Bar = function() {
- document.getElementById("ft8-clear-btn")?.click();
+ const decoder = ft8BarActiveDecoder;
+ if (decoder === "ft4") {
+ window.resetFt4HistoryView?.();
+ return;
+ }
+ if (decoder === "ft2") {
+ window.resetFt2HistoryView?.();
+ return;
+ }
+ window.resetFt8HistoryView?.();
};
+window.closeFt8Bar = function() {
+ ft8BarDismissedAtMsByDecoder[ft8BarActiveDecoder] = Date.now();
+ if (ft8BarOverlay) {
+ ft8BarOverlay.style.display = "none";
+ ft8BarOverlay.innerHTML = "";
+ }
+};
+window.registerFt8FamilyBarRenderer("ft8", buildFt8BarFrames);
function renderFt8Message(message) {
let out = "";
@@ -387,7 +419,6 @@ window.updateFt8RfDisplay = function() {
window.resetFt8HistoryView = function() {
ft8MessagesEl.innerHTML = "";
ft8MessageHistory = [];
- ft8BufferedWhilePaused = 0;
updateFt8Bar();
renderFt8History();
if (window.clearMapMarkersByType) window.clearMapMarkersByType("ft8");
@@ -414,34 +445,22 @@ if (ft8MessagesEl) {
});
}
-if (ft8PauseBtn) {
- ft8PauseBtn.addEventListener("click", () => {
- ft8Paused = !ft8Paused;
- if (!ft8Paused) {
- ft8BufferedWhilePaused = 0;
- renderFt8History();
- } else {
- updateFt8PauseUi();
- }
- });
-}
-
document.getElementById("ft8-decode-toggle-btn").addEventListener("click", async () => {
try { await postPath("/toggle_ft8_decode"); } catch (e) { console.error("FT8 toggle failed", e); }
});
-document.getElementById("ft8-clear-btn").addEventListener("click", async () => {
+document.getElementById("settings-clear-ft8-history")?.addEventListener("click", async () => {
try {
await postPath("/clear_ft8_decode");
window.resetFt8HistoryView();
} catch (e) {
- console.error("FT8 clear failed", e);
+ console.error("FT8 history clear failed", e);
}
});
// --- Server-side FT8 decode handler ---
window.onServerFt8 = function(msg) {
- ft8Status.textContent = ft8Paused ? "Paused" : "Receiving";
+ ft8Status.textContent = "Receiving";
const next = normalizeServerFt8Message(msg);
if (next.grids.length > 0 && window.mapAddLocator) {
window.mapAddLocator(next.raw, next.grids, "ft8", next.station, {
@@ -452,5 +471,3 @@ window.onServerFt8 = function(msg) {
}
addFt8Message(next.history);
};
-
-updateFt8PauseUi();
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/hf-aprs.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/hf-aprs.js
index bda1e92..32eee1f 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/hf-aprs.js
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/hf-aprs.js
@@ -2,7 +2,6 @@
const hfAprsStatus = document.getElementById("hf-aprs-status");
const hfAprsPacketsEl = document.getElementById("hf-aprs-packets");
const hfAprsFilterInput = document.getElementById("hf-aprs-filter");
-const hfAprsPauseBtn = document.getElementById("hf-aprs-pause-btn");
const hfAprsOnlyPosBtn = document.getElementById("hf-aprs-only-pos-btn");
const hfAprsHideCrcBtn = document.getElementById("hf-aprs-hide-crc-btn");
const hfAprsCollapseDupBtn = document.getElementById("hf-aprs-collapse-dup-btn");
@@ -11,8 +10,6 @@ const hfAprsVisibleCountEl = document.getElementById("hf-aprs-visible-count");
const hfAprsLatestSeenEl = document.getElementById("hf-aprs-latest-seen");
let hfAprsFilterText = "";
let hfAprsPacketHistory = [];
-let hfAprsPaused = false;
-let hfAprsBufferedWhilePaused = 0;
let hfAprsOnlyPos = false;
let hfAprsHideCrc = false;
let hfAprsCollapseDup = false;
@@ -138,11 +135,7 @@ function updateHfAprsSummary() {
hfAprsTotalCountEl.textContent = `${hfAprsPacketHistory.length} total`;
}
if (hfAprsVisibleCountEl) {
- let text = `${visible.length} shown`;
- if (hfAprsPaused && hfAprsBufferedWhilePaused > 0) {
- text += ` · ${hfAprsBufferedWhilePaused} buffered`;
- }
- hfAprsVisibleCountEl.textContent = text;
+ hfAprsVisibleCountEl.textContent = `${visible.length} shown`;
}
if (hfAprsLatestSeenEl) {
const latest = hfAprsPacketHistory[0];
@@ -161,10 +154,6 @@ function updateHfAprsChipState() {
hfAprsOnlyPosBtn?.classList.toggle("active", hfAprsOnlyPos);
hfAprsHideCrcBtn?.classList.toggle("active", hfAprsHideCrc);
hfAprsCollapseDupBtn?.classList.toggle("active", hfAprsCollapseDup);
- if (hfAprsPauseBtn) {
- hfAprsPauseBtn.textContent = hfAprsPaused ? "Resume" : "Pause";
- hfAprsPauseBtn.classList.toggle("active", hfAprsPaused);
- }
}
function renderHfAprsInfo(pkt) {
@@ -307,7 +296,7 @@ function renderHfAprsRow(pkt, isFresh) {
function renderHfAprsHistory() {
pruneHfAprsPacketHistory();
- if (!hfAprsPacketsEl || hfAprsPaused) {
+ if (!hfAprsPacketsEl) {
updateHfAprsSummary();
updateHfAprsChipState();
return;
@@ -325,7 +314,6 @@ function renderHfAprsHistory() {
window.resetHfAprsHistoryView = function() {
if (hfAprsPacketsEl) hfAprsPacketsEl.innerHTML = "";
hfAprsPacketHistory = [];
- hfAprsBufferedWhilePaused = 0;
renderHfAprsHistory();
};
@@ -342,13 +330,6 @@ function addHfAprsPacket(pkt) {
hfAprsPacketHistory.unshift(pkt);
pruneHfAprsPacketHistory();
- if (hfAprsPaused) {
- hfAprsBufferedWhilePaused += 1;
- updateHfAprsSummary();
- updateHfAprsChipState();
- return;
- }
-
scheduleHfAprsHistoryRender();
}
@@ -372,7 +353,7 @@ function normalizeServerHfAprsPacket(pkt) {
window.onServerHfAprsBatch = function(packets) {
if (!Array.isArray(packets) || packets.length === 0) return;
- if (hfAprsStatus) hfAprsStatus.textContent = hfAprsPaused ? "Paused" : "Receiving";
+ if (hfAprsStatus) hfAprsStatus.textContent = "Receiving";
const normalized = [];
for (const pkt of packets) {
const next = normalizeServerHfAprsPacket(pkt);
@@ -384,12 +365,6 @@ window.onServerHfAprsBatch = function(packets) {
normalized.reverse();
hfAprsPacketHistory = normalized.concat(hfAprsPacketHistory);
pruneHfAprsPacketHistory();
- if (hfAprsPaused) {
- hfAprsBufferedWhilePaused += packets.length;
- updateHfAprsSummary();
- updateHfAprsChipState();
- return;
- }
scheduleHfAprsHistoryRender();
};
@@ -401,28 +376,15 @@ document.getElementById("hf-aprs-decode-toggle-btn")?.addEventListener("click",
try { await postPath("/toggle_hf_aprs_decode"); } catch (e) { console.error("HF APRS toggle failed", e); }
});
-document.getElementById("hf-aprs-clear-btn")?.addEventListener("click", async () => {
+document.getElementById("settings-clear-hf-aprs-history")?.addEventListener("click", async () => {
try {
await postPath("/clear_hf_aprs_decode");
window.resetHfAprsHistoryView();
} catch (e) {
- console.error("HF APRS clear failed", e);
+ console.error("HF APRS history clear failed", e);
}
});
-if (hfAprsPauseBtn) {
- hfAprsPauseBtn.addEventListener("click", () => {
- hfAprsPaused = !hfAprsPaused;
- if (!hfAprsPaused) {
- hfAprsBufferedWhilePaused = 0;
- renderHfAprsHistory();
- } else {
- updateHfAprsSummary();
- updateHfAprsChipState();
- }
- });
-}
-
if (hfAprsOnlyPosBtn) {
hfAprsOnlyPosBtn.addEventListener("click", () => {
hfAprsOnlyPos = !hfAprsOnlyPos;
@@ -462,7 +424,7 @@ if (hfAprsFilterInput) {
// --- Server-side HF APRS decode handler ---
window.onServerHfAprs = function(pkt) {
- if (hfAprsStatus) hfAprsStatus.textContent = hfAprsPaused ? "Paused" : "Receiving";
+ if (hfAprsStatus) hfAprsStatus.textContent = "Receiving";
addHfAprsPacket(normalizeServerHfAprsPacket(pkt));
};
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/vdes.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/vdes.js
index 7c08851..767531d 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/vdes.js
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/vdes.js
@@ -2,8 +2,6 @@
const vdesStatus = document.getElementById("vdes-status");
const vdesMessagesEl = document.getElementById("vdes-messages");
const vdesFilterInput = document.getElementById("vdes-filter");
-const vdesPauseBtn = document.getElementById("vdes-pause-btn");
-const vdesClearBtn = document.getElementById("vdes-clear-btn");
const vdesBarOverlay = document.getElementById("vdes-bar-overlay");
const vdesChannelSummaryEl = document.getElementById("vdes-channel-summary");
const vdesFrameCountEl = document.getElementById("vdes-frame-count");
@@ -11,8 +9,6 @@ const vdesLatestSeenEl = document.getElementById("vdes-latest-seen");
const VDES_BAR_WINDOW_MS = 15 * 60 * 1000;
let vdesFilterText = "";
let vdesMessageHistory = [];
-let vdesPaused = false;
-let vdesBufferedWhilePaused = 0;
function currentVdesHistoryRetentionMs() {
return typeof window.getDecodeHistoryRetentionMs === "function"
@@ -76,20 +72,12 @@ function updateVdesSummary() {
}
if (vdesFrameCountEl) {
const count = vdesMessageHistory.length;
- let text = `${count} burst${count === 1 ? "" : "s"}`;
- if (vdesPaused && vdesBufferedWhilePaused > 0) {
- text += ` · ${vdesBufferedWhilePaused} buffered`;
- }
- vdesFrameCountEl.textContent = text;
+ vdesFrameCountEl.textContent = `${count} burst${count === 1 ? "" : "s"}`;
}
if (vdesLatestSeenEl) {
const latest = vdesMessageHistory[0];
vdesLatestSeenEl.textContent = latest ? vdesAgeText(latest._tsMs) : "No traffic yet";
}
- if (vdesPauseBtn) {
- vdesPauseBtn.textContent = vdesPaused ? "Resume" : "Pause";
- vdesPauseBtn.classList.toggle("active", vdesPaused);
- }
}
function applyVdesFilterToRow(row) {
@@ -227,20 +215,19 @@ function updateVdesBar() {
}
window.updateVdesBar = updateVdesBar;
window.clearVdesBar = function() {
- document.getElementById("vdes-clear-btn")?.click();
+ window.resetVdesHistoryView();
};
window.resetVdesHistoryView = function() {
if (vdesMessagesEl) vdesMessagesEl.innerHTML = "";
vdesMessageHistory = [];
- vdesBufferedWhilePaused = 0;
updateVdesBar();
renderVdesHistory();
};
function renderVdesHistory() {
pruneVdesMessageHistory();
- if (!vdesMessagesEl || vdesPaused) {
+ if (!vdesMessagesEl) {
updateVdesSummary();
return;
}
@@ -264,13 +251,7 @@ function addVdesMessage(msg) {
vdesMessageHistory.unshift(msg);
pruneVdesMessageHistory();
scheduleVdesBarUpdate();
-
- if (vdesPaused) {
- vdesBufferedWhilePaused += 1;
- updateVdesSummary();
- } else {
- scheduleVdesHistoryRender();
- }
+ scheduleVdesHistoryRender();
}
function normalizeServerVdesMessage(msg) {
@@ -303,7 +284,7 @@ function normalizeServerVdesMessage(msg) {
window.onServerVdesBatch = function(messages) {
if (!Array.isArray(messages) || messages.length === 0) return;
- if (vdesStatus) vdesStatus.textContent = vdesPaused ? "Paused" : "Receiving";
+ if (vdesStatus) vdesStatus.textContent = "Receiving";
const normalized = [];
for (const msg of messages) {
const next = normalizeServerVdesMessage(msg);
@@ -323,11 +304,6 @@ window.onServerVdesBatch = function(messages) {
vdesMessageHistory = normalized.concat(vdesMessageHistory);
pruneVdesMessageHistory();
scheduleVdesBarUpdate();
- if (vdesPaused) {
- vdesBufferedWhilePaused += messages.length;
- updateVdesSummary();
- return;
- }
scheduleVdesHistoryRender();
};
@@ -335,28 +311,14 @@ window.restoreVdesHistory = function(messages) {
window.onServerVdesBatch(messages);
};
-if (vdesClearBtn) {
- vdesClearBtn.addEventListener("click", async () => {
- try {
- await postPath("/clear_vdes_decode");
- window.resetVdesHistoryView();
- } catch (e) {
- console.error("VDES clear failed", e);
- }
- });
-}
-
-if (vdesPauseBtn) {
- vdesPauseBtn.addEventListener("click", () => {
- vdesPaused = !vdesPaused;
- if (!vdesPaused) {
- vdesBufferedWhilePaused = 0;
- renderVdesHistory();
- } else {
- updateVdesSummary();
- }
- });
-}
+document.getElementById("settings-clear-vdes-history")?.addEventListener("click", async () => {
+ try {
+ await postPath("/clear_vdes_decode");
+ window.resetVdesHistoryView();
+ } catch (e) {
+ console.error("VDES history clear failed", e);
+ }
+});
if (vdesFilterInput) {
vdesFilterInput.addEventListener("input", () => {
@@ -366,7 +328,7 @@ if (vdesFilterInput) {
}
window.onServerVdes = function(msg) {
- if (vdesStatus) vdesStatus.textContent = vdesPaused ? "Paused" : "Receiving";
+ if (vdesStatus) vdesStatus.textContent = "Receiving";
const next = normalizeServerVdesMessage(msg);
addVdesMessage(next);
if (next.lat != null && next.lon != null && window.vdesMapAddPoint) {
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/wspr.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/wspr.js
index 427ffc4..84da470 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/wspr.js
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/plugins/wspr.js
@@ -3,12 +3,9 @@ const wsprStatus = document.getElementById("wspr-status");
const wsprPeriodEl = document.getElementById("wspr-period");
const wsprMessagesEl = document.getElementById("wspr-messages");
const wsprFilterInput = document.getElementById("wspr-filter");
-const wsprPauseBtn = document.getElementById("wspr-pause-btn");
const WSPR_PERIOD_SECONDS = 120;
let wsprFilterText = "";
let wsprMessageHistory = [];
-let wsprPaused = false;
-let wsprBufferedWhilePaused = 0;
function currentWsprHistoryRetentionMs() {
return typeof window.getDecodeHistoryRetentionMs === "function"
@@ -62,35 +59,20 @@ function renderWsprRow(msg) {
return row;
}
-function updateWsprPauseUi() {
- if (!wsprPauseBtn) return;
- wsprPauseBtn.textContent = wsprPaused ? "Resume" : "Pause";
- wsprPauseBtn.classList.toggle("active", wsprPaused);
-}
-
function renderWsprHistory() {
pruneWsprMessageHistory();
- if (!wsprMessagesEl || wsprPaused) {
- updateWsprPauseUi();
- return;
- }
+ if (!wsprMessagesEl) return;
const fragment = document.createDocumentFragment();
for (let i = 0; i < wsprMessageHistory.length; i += 1) {
fragment.appendChild(renderWsprRow(wsprMessageHistory[i]));
}
wsprMessagesEl.replaceChildren(fragment);
- updateWsprPauseUi();
}
function addWsprMessage(msg) {
msg._tsMs = Number.isFinite(msg?.ts_ms) ? Number(msg.ts_ms) : Date.now();
wsprMessageHistory.unshift(msg);
pruneWsprMessageHistory();
- if (wsprPaused) {
- wsprBufferedWhilePaused += 1;
- updateWsprPauseUi();
- return;
- }
scheduleWsprHistoryRender();
}
@@ -120,7 +102,7 @@ function normalizeServerWsprMessage(msg) {
window.onServerWsprBatch = function(messages) {
if (!Array.isArray(messages) || messages.length === 0) return;
- wsprStatus.textContent = wsprPaused ? "Paused" : "Receiving";
+ wsprStatus.textContent = "Receiving";
const normalized = [];
for (const msg of messages) {
const next = normalizeServerWsprMessage(msg);
@@ -136,11 +118,6 @@ window.onServerWsprBatch = function(messages) {
normalized.reverse();
wsprMessageHistory = normalized.concat(wsprMessageHistory);
pruneWsprMessageHistory();
- if (wsprPaused) {
- wsprBufferedWhilePaused += messages.length;
- updateWsprPauseUi();
- return;
- }
scheduleWsprHistoryRender();
};
@@ -253,7 +230,6 @@ function applyWsprFilterToAll() {
window.resetWsprHistoryView = function() {
wsprMessagesEl.innerHTML = "";
wsprMessageHistory = [];
- wsprBufferedWhilePaused = 0;
renderWsprHistory();
if (window.clearMapMarkersByType) window.clearMapMarkersByType("wspr");
};
@@ -279,33 +255,21 @@ if (wsprMessagesEl) {
});
}
-if (wsprPauseBtn) {
- wsprPauseBtn.addEventListener("click", () => {
- wsprPaused = !wsprPaused;
- if (!wsprPaused) {
- wsprBufferedWhilePaused = 0;
- renderWsprHistory();
- } else {
- updateWsprPauseUi();
- }
- });
-}
-
document.getElementById("wspr-decode-toggle-btn").addEventListener("click", async () => {
try { await postPath("/toggle_wspr_decode"); } catch (e) { console.error("WSPR toggle failed", e); }
});
-document.getElementById("wspr-clear-btn").addEventListener("click", async () => {
+document.getElementById("settings-clear-wspr-history")?.addEventListener("click", async () => {
try {
await postPath("/clear_wspr_decode");
window.resetWsprHistoryView();
} catch (e) {
- console.error("WSPR clear failed", e);
+ console.error("WSPR history clear failed", e);
}
});
window.onServerWspr = function(msg) {
- wsprStatus.textContent = wsprPaused ? "Paused" : "Receiving";
+ wsprStatus.textContent = "Receiving";
const next = normalizeServerWsprMessage(msg);
if (next.grids.length > 0 && window.mapAddLocator) {
window.mapAddLocator(next.raw, next.grids, "wspr", next.station, {
@@ -315,5 +279,3 @@ window.onServerWspr = function(msg) {
}
addWsprMessage(next.history);
};
-
-updateWsprPauseUi();
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css
index 6bd45e8..8d6b144 100644
--- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css
+++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/style.css
@@ -821,7 +821,6 @@ small { color: var(--text-muted); }
display: inline-block;
}
.aprs-bar-window {
- margin-left: auto;
display: inline-flex;
align-items: center;
color: var(--text-muted);
@@ -831,6 +830,13 @@ small { color: var(--text-muted); }
text-transform: none;
white-space: nowrap;
}
+.aprs-bar-actions {
+ margin-left: auto;
+ display: inline-flex;
+ align-items: center;
+ gap: 0.38rem;
+ flex: 0 0 auto;
+}
.aprs-bar-clear-wrap {
display: inline-flex;
align-items: center;
@@ -864,6 +870,30 @@ small { color: var(--text-muted); }
.aprs-bar-clear-wrap:hover {
color: inherit;
}
+.aprs-bar-close {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 1.05rem;
+ height: 1.05rem;
+ padding: 0;
+ border: none;
+ border-radius: 999px;
+ background: transparent;
+ color: var(--text-muted);
+ font-family: inherit;
+ font-size: 0.95em;
+ font-weight: 700;
+ line-height: 1;
+ cursor: pointer;
+ opacity: 0.82;
+ transition: opacity 120ms, color 120ms, background-color 120ms;
+}
+.aprs-bar-close:hover {
+ opacity: 1;
+ color: var(--accent-green);
+ background: color-mix(in srgb, var(--btn-bg) 70%, transparent);
+}
.aprs-bar-frame {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: clamp(0.56rem, 0.92vw, 0.7rem);