[feat](trx-client): add bandplan display config to client settings
Add bandplan_enabled (default: true) and bandplan_region (default: "iaru_r1") fields to [frontends.http] config section, allowing the operator to control the initial bandplan display setting from the server config rather than requiring each browser session to configure it manually. The server-provided default is applied on first connect only when the user has no existing localStorage override. https://claude.ai/code/session_01H7427hzbJepJzkoUJzoDmH Signed-off-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -289,6 +289,10 @@ pub struct HttpFrontendConfig {
|
||||
pub spectrum_usable_span_ratio: f32,
|
||||
/// Whether to expose the RF Gain control in the web UI.
|
||||
pub show_sdr_gain_control: bool,
|
||||
/// Whether the bandplan strip is shown by default in the spectrum display.
|
||||
pub bandplan_enabled: bool,
|
||||
/// Default bandplan region: "iaru_r1", "iaru_r2", or "iaru_r3".
|
||||
pub bandplan_region: String,
|
||||
/// Default decode history retention in minutes for the active rig.
|
||||
pub decode_history_retention_min: u64,
|
||||
/// Optional per-rig decode history retention overrides in minutes.
|
||||
@@ -308,6 +312,8 @@ impl Default for HttpFrontendConfig {
|
||||
spectrum_coverage_margin_hz: 50_000,
|
||||
spectrum_usable_span_ratio: 0.92,
|
||||
show_sdr_gain_control: true,
|
||||
bandplan_enabled: true,
|
||||
bandplan_region: "iaru_r1".to_string(),
|
||||
decode_history_retention_min: 24 * 60,
|
||||
decode_history_retention_min_by_rig: HashMap::new(),
|
||||
auth: HttpAuthConfig::default(),
|
||||
@@ -507,6 +513,15 @@ impl ClientConfig {
|
||||
"[frontends.http].spectrum_usable_span_ratio must be > 0.0 and <= 1.0".to_string(),
|
||||
);
|
||||
}
|
||||
match self.frontends.http.bandplan_region.as_str() {
|
||||
"iaru_r1" | "iaru_r2" | "iaru_r3" => {}
|
||||
other => {
|
||||
return Err(format!(
|
||||
"[frontends.http].bandplan_region must be \"iaru_r1\", \"iaru_r2\", or \"iaru_r3\", got \"{}\"",
|
||||
other
|
||||
));
|
||||
}
|
||||
}
|
||||
if self.frontends.http.decode_history_retention_min == 0 {
|
||||
return Err("[frontends.http].decode_history_retention_min must be > 0".to_string());
|
||||
}
|
||||
@@ -650,6 +665,8 @@ impl ClientConfig {
|
||||
spectrum_coverage_margin_hz: 50_000,
|
||||
spectrum_usable_span_ratio: 0.92,
|
||||
show_sdr_gain_control: true,
|
||||
bandplan_enabled: true,
|
||||
bandplan_region: "iaru_r1".to_string(),
|
||||
decode_history_retention_min: 24 * 60,
|
||||
decode_history_retention_min_by_rig: HashMap::new(),
|
||||
auth: HttpAuthConfig {
|
||||
@@ -731,6 +748,8 @@ mod tests {
|
||||
assert_eq!(config.frontends.http.initial_map_zoom, 10);
|
||||
assert_eq!(config.frontends.http.spectrum_coverage_margin_hz, 50_000);
|
||||
assert_eq!(config.frontends.http.spectrum_usable_span_ratio, 0.92);
|
||||
assert!(config.frontends.http.bandplan_enabled);
|
||||
assert_eq!(config.frontends.http.bandplan_region, "iaru_r1");
|
||||
assert_eq!(config.frontends.http.decode_history_retention_min, 1440);
|
||||
assert!(config
|
||||
.frontends
|
||||
@@ -807,6 +826,9 @@ uhf = 60
|
||||
assert_eq!(config.frontends.http.initial_map_zoom, 12);
|
||||
assert_eq!(config.frontends.http.spectrum_coverage_margin_hz, 40_000);
|
||||
assert_eq!(config.frontends.http.spectrum_usable_span_ratio, 0.9);
|
||||
// bandplan fields not set in TOML → defaults
|
||||
assert!(config.frontends.http.bandplan_enabled);
|
||||
assert_eq!(config.frontends.http.bandplan_region, "iaru_r1");
|
||||
assert_eq!(config.frontends.http.decode_history_retention_min, 720);
|
||||
assert_eq!(
|
||||
config
|
||||
@@ -1155,4 +1177,32 @@ url = "remote.example.com:4530"
|
||||
.unwrap_err()
|
||||
.contains("poll_interval_ms must be > 0"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_rejects_invalid_bandplan_region() {
|
||||
let mut config = ClientConfig::default();
|
||||
config.frontends.http.bandplan_region = "invalid".to_string();
|
||||
assert!(config.validate().is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_validate_accepts_all_bandplan_regions() {
|
||||
for region in &["iaru_r1", "iaru_r2", "iaru_r3"] {
|
||||
let mut config = ClientConfig::default();
|
||||
config.frontends.http.bandplan_region = region.to_string();
|
||||
assert!(config.validate().is_ok(), "region {} should be valid", region);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_bandplan_config_from_toml() {
|
||||
let toml_str = r#"
|
||||
[frontends.http]
|
||||
bandplan_enabled = false
|
||||
bandplan_region = "iaru_r2"
|
||||
"#;
|
||||
let config: ClientConfig = toml::from_str(toml_str).unwrap();
|
||||
assert!(!config.frontends.http.bandplan_enabled);
|
||||
assert_eq!(config.frontends.http.bandplan_region, "iaru_r2");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,6 +180,8 @@ async fn async_init() -> DynResult<AppState> {
|
||||
cfg.frontends.http.spectrum_coverage_margin_hz;
|
||||
frontend_runtime.http_ui.spectrum_usable_span_ratio =
|
||||
cfg.frontends.http.spectrum_usable_span_ratio;
|
||||
frontend_runtime.http_ui.bandplan_enabled = cfg.frontends.http.bandplan_enabled;
|
||||
frontend_runtime.http_ui.bandplan_region = cfg.frontends.http.bandplan_region.clone();
|
||||
frontend_runtime.http_ui.decode_history_retention_min =
|
||||
cfg.frontends.http.decode_history_retention_min;
|
||||
frontend_runtime.http_ui.decode_history_retention_min_by_rig = cfg
|
||||
|
||||
@@ -282,6 +282,8 @@ pub struct HttpUiConfig {
|
||||
pub initial_map_zoom: u8,
|
||||
pub spectrum_coverage_margin_hz: u32,
|
||||
pub spectrum_usable_span_ratio: f32,
|
||||
pub bandplan_enabled: bool,
|
||||
pub bandplan_region: String,
|
||||
pub decode_history_retention_min: u64,
|
||||
pub decode_history_retention_min_by_rig: HashMap<String, u64>,
|
||||
}
|
||||
@@ -293,6 +295,8 @@ impl Default for HttpUiConfig {
|
||||
initial_map_zoom: 10,
|
||||
spectrum_coverage_margin_hz: 50_000,
|
||||
spectrum_usable_span_ratio: 0.92,
|
||||
bandplan_enabled: true,
|
||||
bandplan_region: "iaru_r1".to_string(),
|
||||
decode_history_retention_min: 24 * 60,
|
||||
decode_history_retention_min_by_rig: HashMap::new(),
|
||||
}
|
||||
|
||||
@@ -3177,6 +3177,22 @@ function render(update) {
|
||||
if (typeof update.show_sdr_gain_control === "boolean") {
|
||||
if (sdrSettingsRowEl) sdrSettingsRowEl.style.display = update.show_sdr_gain_control ? "" : "none";
|
||||
}
|
||||
// Apply server-configured bandplan defaults once, only when the user has not
|
||||
// previously overridden the setting via the UI (localStorage).
|
||||
if (!_bandplanServerDefaultApplied && typeof update.bandplan_enabled === "boolean"
|
||||
&& typeof update.bandplan_region === "string") {
|
||||
_bandplanServerDefaultApplied = true;
|
||||
const hasUserOverride = localStorage.getItem(STORAGE_PREFIX + "bandplanRegion") !== null;
|
||||
if (!hasUserOverride) {
|
||||
const region = update.bandplan_enabled ? update.bandplan_region : "off";
|
||||
bandplanRegion = region;
|
||||
saveSetting("bandplanRegion", region);
|
||||
if (bandplanRegionSelect) bandplanRegionSelect.value = region;
|
||||
bandplanSegmentsCache = null;
|
||||
bandplanCacheKey = "";
|
||||
if (lastSpectrumData) scheduleSpectrumDraw();
|
||||
}
|
||||
}
|
||||
if (update.filter && sdrAgcEl && typeof update.filter.sdr_agc_enabled === "boolean") {
|
||||
sdrAgcEl.checked = update.filter.sdr_agc_enabled;
|
||||
updateSdrGainInputState();
|
||||
@@ -11279,6 +11295,7 @@ if (spectrumCenterRightBtn) {
|
||||
let bandplanData = null;
|
||||
let bandplanRegion = loadSetting("bandplanRegion", "off");
|
||||
let bandplanShowLabels = loadSetting("bandplanLabels", true);
|
||||
let _bandplanServerDefaultApplied = false;
|
||||
let bandplanSegmentsCache = null;
|
||||
let bandplanCacheKey = "";
|
||||
|
||||
|
||||
@@ -82,6 +82,8 @@ struct FrontendMeta {
|
||||
initial_map_zoom: u8,
|
||||
spectrum_coverage_margin_hz: u32,
|
||||
spectrum_usable_span_ratio: f32,
|
||||
bandplan_enabled: bool,
|
||||
bandplan_region: String,
|
||||
decode_history_retention_min: u64,
|
||||
server_connected: bool,
|
||||
}
|
||||
@@ -171,6 +173,8 @@ fn frontend_meta_from_context(
|
||||
initial_map_zoom: initial_map_zoom_from_context(context),
|
||||
spectrum_coverage_margin_hz: spectrum_coverage_margin_hz_from_context(context),
|
||||
spectrum_usable_span_ratio: spectrum_usable_span_ratio_from_context(context),
|
||||
bandplan_enabled: context.http_ui.bandplan_enabled,
|
||||
bandplan_region: context.http_ui.bandplan_region.clone(),
|
||||
decode_history_retention_min: decode_history_retention_min_from_context(context),
|
||||
server_connected,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user