feat(ui): improve radio operator experience
CI / lint (pull_request) Failing after 1s
CI / test (pull_request) Failing after 1s
CI / reuse (pull_request) Failing after 1s
CI / lint (push) Failing after 1s
CI / test (push) Failing after 1s
CI / reuse (push) Failing after 0s

This commit was merged in pull request #15.
This commit is contained in:
sjg
2026-08-01 02:24:47 +02:00
parent 6676b66993
commit a0bdaa2c4b
21 changed files with 528 additions and 65 deletions
@@ -382,7 +382,7 @@ window.pruneAisHistoryView = function() {
};
document.getElementById("settings-clear-ais-history")?.addEventListener("click", async () => {
if (!confirm("Clear all AIS decode history? This cannot be undone.")) return;
if (!await window.trxUi.confirm({ title: "Clear AIS history?", message: "All stored AIS messages will be permanently removed.", confirmLabel: "Clear history" })) return;
try {
await postPath("/clear_ais_decode");
window.resetAisHistoryView();
@@ -442,7 +442,7 @@ window.restoreAprsHistory = function(packets) {
};
document.getElementById("settings-clear-aprs-history")?.addEventListener("click", async () => {
if (!confirm("Clear all APRS decode history? This cannot be undone.")) return;
if (!await window.trxUi.confirm({ title: "Clear APRS history?", message: "All stored APRS packets will be permanently removed.", confirmLabel: "Clear history" })) return;
try {
await postPath("/clear_aprs_decode");
window.resetAprsHistoryView();
@@ -215,10 +215,10 @@
});
}
function resetBackgroundDecode() {
async function resetBackgroundDecode() {
const rigId = currentRigId;
if (!rigId) return;
if (!confirm("Reset background decode configuration? This cannot be undone.")) return;
if (!await window.trxUi.confirm({ title: "Reset background decoding?", message: "The current background decode configuration will be permanently reset.", confirmLabel: "Reset" })) return;
apiResetConfig(rigId)
.then(function (saved) {
currentConfig = saved;
@@ -331,8 +331,13 @@ async function bmSave(e) {
const comment = document.getElementById("bm-comment").value.trim();
const decoders = bmReadDecoders();
const formError = document.getElementById("bm-form-error");
if (formError) formError.textContent = "";
if (!name || !Number.isFinite(freq_hz) || !mode) {
alert("Name, Frequency, and Mode are required.");
if (formError) formError.textContent = "Enter a name, a valid frequency, and a mode.";
const invalid = !name ? document.getElementById("bm-name")
: !Number.isFinite(freq_hz) ? document.getElementById("bm-freq") : document.getElementById("bm-mode");
invalid?.focus();
return;
}
@@ -373,12 +378,13 @@ async function bmSave(e) {
await bmFetch(document.getElementById("bm-category-filter").value);
} catch (err) {
console.error("Failed to save bookmark:", err);
alert("Failed to save bookmark: " + err.message);
if (formError) formError.textContent = "Failed to save bookmark: " + err.message;
window.trxUi?.notify("Bookmark could not be saved", { kind: "error" });
}
}
async function bmDelete(id) {
if (!confirm("Delete this bookmark?")) return;
if (!await window.trxUi.confirm({ title: "Delete bookmark?", message: "This bookmark will be permanently removed.", confirmLabel: "Delete" })) return;
const bm = bmList.find((b) => b.id === id);
const scope = bm ? bm.scope : undefined;
try {
@@ -389,7 +395,7 @@ async function bmDelete(id) {
await bmFetch(document.getElementById("bm-category-filter").value);
} catch (err) {
console.error("Failed to delete bookmark:", err);
alert("Failed to delete bookmark: " + err.message);
window.trxUi?.notify("Failed to delete bookmark: " + err.message, { kind: "error" });
}
}
@@ -555,7 +561,12 @@ async function bmMoveSelected() {
const target = document.getElementById("bm-move-target")?.value;
if (!target) return;
const targetLabel = document.getElementById("bm-move-target")?.selectedOptions[0]?.textContent || target;
if (!confirm(`Move ${ids.length} bookmark${ids.length > 1 ? "s" : ""} to "${targetLabel}"?`)) return;
if (!await window.trxUi.confirm({
title: "Move selected bookmarks?",
message: `${ids.length} bookmark${ids.length > 1 ? "s" : ""} will move to “${targetLabel}”.`,
confirmLabel: "Move",
danger: false,
})) return;
try {
// Group selected IDs by their owning scope (skip if already in target).
const byScope = {};
@@ -577,7 +588,7 @@ async function bmMoveSelected() {
await bmFetch(document.getElementById("bm-category-filter").value);
} catch (err) {
console.error("Failed to move bookmarks:", err);
alert("Failed to move bookmarks: " + err.message);
window.trxUi?.notify("Failed to move bookmarks: " + err.message, { kind: "error" });
}
}
@@ -598,7 +609,11 @@ function bmSyncSelectAllCheckbox() {
async function bmDeleteSelected() {
const ids = Array.from(bmSelected);
if (ids.length === 0) return;
if (!confirm(`Delete ${ids.length} selected bookmark${ids.length > 1 ? "s" : ""}?`)) return;
if (!await window.trxUi.confirm({
title: "Delete selected bookmarks?",
message: `${ids.length} bookmark${ids.length > 1 ? "s" : ""} will be permanently removed.`,
confirmLabel: "Delete",
})) return;
try {
// Group selected IDs by their owning scope.
const byScope = {};
@@ -619,7 +634,7 @@ async function bmDeleteSelected() {
await bmFetch(document.getElementById("bm-category-filter").value);
} catch (err) {
console.error("Failed to delete bookmarks:", err);
alert("Failed to delete bookmarks: " + err.message);
window.trxUi?.notify("Failed to delete bookmarks: " + err.message, { kind: "error" });
}
}
@@ -364,7 +364,7 @@ window.resetCwHistoryView = function() {
};
document.getElementById("settings-clear-cw-history")?.addEventListener("click", async () => {
if (!confirm("Clear all CW decode history? This cannot be undone.")) return;
if (!await window.trxUi.confirm({ title: "Clear CW history?", message: "All stored CW decodes will be permanently removed.", confirmLabel: "Clear history" })) return;
try {
await postPath("/clear_cw_decode");
window.resetCwHistoryView();
@@ -190,7 +190,7 @@ ft2DecodeToggleBtn?.addEventListener("click", async () => {
});
document.getElementById("settings-clear-ft2-history")?.addEventListener("click", async () => {
if (!confirm("Clear all FT2 decode history? This cannot be undone.")) return;
if (!await window.trxUi.confirm({ title: "Clear FT2 history?", message: "All stored FT2 decodes will be permanently removed.", confirmLabel: "Clear history" })) return;
try {
await postPath("/clear_ft2_decode");
window.resetFt2HistoryView();
@@ -190,7 +190,7 @@ ft4DecodeToggleBtn?.addEventListener("click", async () => {
});
document.getElementById("settings-clear-ft4-history")?.addEventListener("click", async () => {
if (!confirm("Clear all FT4 decode history? This cannot be undone.")) return;
if (!await window.trxUi.confirm({ title: "Clear FT4 history?", message: "All stored FT4 decodes will be permanently removed.", confirmLabel: "Clear history" })) return;
try {
await postPath("/clear_ft4_decode");
window.resetFt4HistoryView();
@@ -462,7 +462,7 @@ ft8DecodeToggleBtn?.addEventListener("click", async () => {
});
document.getElementById("settings-clear-ft8-history")?.addEventListener("click", async () => {
if (!confirm("Clear all FT8 decode history? This cannot be undone.")) return;
if (!await window.trxUi.confirm({ title: "Clear FT8 history?", message: "All stored FT8 decodes will be permanently removed.", confirmLabel: "Clear history" })) return;
try {
await postPath("/clear_ft8_decode");
window.resetFt8HistoryView();
@@ -388,7 +388,7 @@ hfAprsDecodeToggleBtn?.addEventListener("click", async () => {
});
document.getElementById("settings-clear-hf-aprs-history")?.addEventListener("click", async () => {
if (!confirm("Clear all HF APRS decode history? This cannot be undone.")) return;
if (!await window.trxUi.confirm({ title: "Clear HF APRS history?", message: "All stored HF APRS packets will be permanently removed.", confirmLabel: "Clear history" })) return;
try {
await postPath("/clear_hf_aprs_decode");
window.resetHfAprsHistoryView();
@@ -250,9 +250,9 @@
var noradId = dom.norad ? parseInt(dom.norad.value, 10) : NaN;
var bmId = dom.bookmark ? dom.bookmark.value : "";
if (!satellite) { alert("Please enter a satellite name."); return; }
if (isNaN(noradId) || noradId <= 0) { alert("Please enter a valid NORAD catalog number."); return; }
if (!bmId) { alert("Please select a bookmark."); return; }
if (!satellite) { window.trxUi?.notify("Enter a satellite name.", { kind: "error" }); document.getElementById("scheduler-sat-name")?.focus(); return; }
if (isNaN(noradId) || noradId <= 0) { window.trxUi?.notify("Enter a valid NORAD catalog number.", { kind: "error" }); document.getElementById("scheduler-sat-norad")?.focus(); return; }
if (!bmId) { window.trxUi?.notify("Select a bookmark.", { kind: "error" }); document.getElementById("scheduler-sat-bookmark")?.focus(); return; }
var minEl = dom.minEl ? parseFloat(dom.minEl.value) : 5;
var prio = dom.priority ? parseInt(dom.priority.value, 10) : 0;
@@ -295,7 +295,7 @@ satDom.typeFilter?.addEventListener("change", () => renderSatHistoryTable());
document
.getElementById("settings-clear-sat-history")
?.addEventListener("click", async () => {
if (!confirm("Clear all satellite decode history? This cannot be undone.")) return;
if (!await window.trxUi.confirm({ title: "Clear satellite history?", message: "All stored satellite decodes will be permanently removed.", confirmLabel: "Clear history" })) return;
try {
await postPath("/clear_lrpt_decode");
window.resetSatHistoryView();
@@ -599,7 +599,7 @@
const bmId = bmEl.value;
if (!bmId) {
alert("Please select a primary bookmark.");
window.trxUi?.notify("Select a primary bookmark before saving.", { kind: "error" });
return;
}
@@ -887,7 +887,7 @@
var recEl = tr.querySelector('[data-field="record"]');
var exEl = tr.querySelector('[data-field="exclusive"]');
if (bmEl && !bmEl.value) { alert('Please select a bookmark.'); return; }
if (bmEl && !bmEl.value) { window.trxUi?.notify("Select a bookmark before saving.", { kind: "error" }); bmEl.focus(); return; }
entry.start_min = hhmmToMin(startEl.value);
entry.end_min = hhmmToMin(endEl.value);
@@ -1236,10 +1236,10 @@
return el ? el.value : "";
}
function resetScheduler() {
async function resetScheduler() {
const rig = currentRigId;
if (!rig) return;
if (!confirm("Reset scheduler for this rig to Disabled?")) return;
if (!await window.trxUi.confirm({ title: "Reset scheduler?", message: "This rig's scheduler configuration will be reset to Disabled.", confirmLabel: "Reset" })) return;
apiDeleteScheduler(rig)
.then(function () {
@@ -317,7 +317,7 @@ window.restoreVdesHistory = function(messages) {
};
document.getElementById("settings-clear-vdes-history")?.addEventListener("click", async () => {
if (!confirm("Clear all VDES decode history? This cannot be undone.")) return;
if (!await window.trxUi.confirm({ title: "Clear VDES history?", message: "All stored VDES decodes will be permanently removed.", confirmLabel: "Clear history" })) return;
try {
await postPath("/clear_vdes_decode");
window.resetVdesHistoryView();
@@ -270,7 +270,7 @@ wsprDecodeToggleBtn?.addEventListener("click", async () => {
});
document.getElementById("settings-clear-wspr-history")?.addEventListener("click", async () => {
if (!confirm("Clear all WSPR decode history? This cannot be undone.")) return;
if (!await window.trxUi.confirm({ title: "Clear WSPR history?", message: "All stored WSPR decodes will be permanently removed.", confirmLabel: "Clear history" })) return;
try {
await postPath("/clear_wspr_decode");
window.resetWsprHistoryView();