[feat](trx-client): add configurable initial map zoom
Add an HTTP frontend config option for the initial APRS map zoom, expose it through frontend metadata, and apply it in the web UI. Co-authored-by: OpenAI Codex <codex@openai.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -230,6 +230,8 @@ pub struct HttpFrontendConfig {
|
|||||||
pub port: u16,
|
pub port: u16,
|
||||||
/// Default rig selected in the web UI on startup.
|
/// Default rig selected in the web UI on startup.
|
||||||
pub default_rig_id: Option<String>,
|
pub default_rig_id: Option<String>,
|
||||||
|
/// Initial zoom level for the APRS map when receiver coordinates are known.
|
||||||
|
pub initial_map_zoom: u8,
|
||||||
/// Whether to expose the RF Gain control in the web UI.
|
/// Whether to expose the RF Gain control in the web UI.
|
||||||
pub show_sdr_gain_control: bool,
|
pub show_sdr_gain_control: bool,
|
||||||
/// Authentication settings
|
/// Authentication settings
|
||||||
@@ -243,6 +245,7 @@ impl Default for HttpFrontendConfig {
|
|||||||
listen: IpAddr::from([127, 0, 0, 1]),
|
listen: IpAddr::from([127, 0, 0, 1]),
|
||||||
port: 8080,
|
port: 8080,
|
||||||
default_rig_id: None,
|
default_rig_id: None,
|
||||||
|
initial_map_zoom: 10,
|
||||||
show_sdr_gain_control: true,
|
show_sdr_gain_control: true,
|
||||||
auth: HttpAuthConfig::default(),
|
auth: HttpAuthConfig::default(),
|
||||||
}
|
}
|
||||||
@@ -342,6 +345,9 @@ impl ClientConfig {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if self.frontends.http.initial_map_zoom == 0 {
|
||||||
|
return Err("[frontends.http].initial_map_zoom must be > 0".to_string());
|
||||||
|
}
|
||||||
if self.frontends.rigctl.enabled && self.frontends.rigctl.rig_ports.is_empty() {
|
if self.frontends.rigctl.enabled && self.frontends.rigctl.rig_ports.is_empty() {
|
||||||
return Err(
|
return Err(
|
||||||
"[frontends.rigctl].rig_ports must contain at least one rig when enabled"
|
"[frontends.rigctl].rig_ports must contain at least one rig when enabled"
|
||||||
@@ -434,6 +440,7 @@ impl ClientConfig {
|
|||||||
listen: IpAddr::from([127, 0, 0, 1]),
|
listen: IpAddr::from([127, 0, 0, 1]),
|
||||||
port: 8080,
|
port: 8080,
|
||||||
default_rig_id: Some("hf".to_string()),
|
default_rig_id: Some("hf".to_string()),
|
||||||
|
initial_map_zoom: 10,
|
||||||
show_sdr_gain_control: true,
|
show_sdr_gain_control: true,
|
||||||
auth: HttpAuthConfig {
|
auth: HttpAuthConfig {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
@@ -533,6 +540,7 @@ mod tests {
|
|||||||
assert!(config.frontends.http.enabled);
|
assert!(config.frontends.http.enabled);
|
||||||
assert!(!config.frontends.rigctl.enabled);
|
assert!(!config.frontends.rigctl.enabled);
|
||||||
assert_eq!(config.frontends.http.port, 8080);
|
assert_eq!(config.frontends.http.port, 8080);
|
||||||
|
assert_eq!(config.frontends.http.initial_map_zoom, 10);
|
||||||
assert_eq!(config.frontends.rigctl.port, 4532);
|
assert_eq!(config.frontends.rigctl.port, 4532);
|
||||||
assert!(config.frontends.http_json.enabled);
|
assert!(config.frontends.http_json.enabled);
|
||||||
assert_eq!(config.frontends.http_json.port, 0);
|
assert_eq!(config.frontends.http_json.port, 0);
|
||||||
@@ -562,6 +570,7 @@ poll_interval_ms = 500
|
|||||||
enabled = true
|
enabled = true
|
||||||
listen = "127.0.0.1"
|
listen = "127.0.0.1"
|
||||||
port = 8080
|
port = 8080
|
||||||
|
initial_map_zoom = 12
|
||||||
|
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
@@ -572,6 +581,7 @@ port = 8080
|
|||||||
assert_eq!(config.remote.auth.token, Some("my-token".to_string()));
|
assert_eq!(config.remote.auth.token, Some("my-token".to_string()));
|
||||||
assert_eq!(config.remote.poll_interval_ms, 500);
|
assert_eq!(config.remote.poll_interval_ms, 500);
|
||||||
assert!(config.frontends.http.enabled);
|
assert!(config.frontends.http.enabled);
|
||||||
|
assert_eq!(config.frontends.http.initial_map_zoom, 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ async fn async_init() -> DynResult<AppState> {
|
|||||||
config::CookieSameSite::None => "None".to_string(),
|
config::CookieSameSite::None => "None".to_string(),
|
||||||
};
|
};
|
||||||
frontend_runtime.http_show_sdr_gain_control = cfg.frontends.http.show_sdr_gain_control;
|
frontend_runtime.http_show_sdr_gain_control = cfg.frontends.http.show_sdr_gain_control;
|
||||||
|
frontend_runtime.http_initial_map_zoom = cfg.frontends.http.initial_map_zoom;
|
||||||
|
|
||||||
// Resolve remote URL: CLI > config [remote] section > error
|
// Resolve remote URL: CLI > config [remote] section > error
|
||||||
let remote_url = cli
|
let remote_url = cli
|
||||||
|
|||||||
@@ -168,6 +168,8 @@ pub struct FrontendRuntimeContext {
|
|||||||
pub http_auth_cookie_same_site: String,
|
pub http_auth_cookie_same_site: String,
|
||||||
/// Whether the HTTP UI should expose the RF Gain control.
|
/// Whether the HTTP UI should expose the RF Gain control.
|
||||||
pub http_show_sdr_gain_control: bool,
|
pub http_show_sdr_gain_control: bool,
|
||||||
|
/// Initial APRS map zoom level when receiver coordinates are available.
|
||||||
|
pub http_initial_map_zoom: u8,
|
||||||
/// Currently selected remote rig id (used by remote client routing).
|
/// Currently selected remote rig id (used by remote client routing).
|
||||||
pub remote_active_rig_id: Arc<Mutex<Option<String>>>,
|
pub remote_active_rig_id: Arc<Mutex<Option<String>>>,
|
||||||
/// Cached remote rig list from GetRigs polling.
|
/// Cached remote rig list from GetRigs polling.
|
||||||
@@ -202,6 +204,7 @@ impl FrontendRuntimeContext {
|
|||||||
http_auth_cookie_secure: false,
|
http_auth_cookie_secure: false,
|
||||||
http_auth_cookie_same_site: "Lax".to_string(),
|
http_auth_cookie_same_site: "Lax".to_string(),
|
||||||
http_show_sdr_gain_control: true,
|
http_show_sdr_gain_control: true,
|
||||||
|
http_initial_map_zoom: 10,
|
||||||
remote_active_rig_id: Arc::new(Mutex::new(None)),
|
remote_active_rig_id: Arc::new(Mutex::new(None)),
|
||||||
remote_rigs: Arc::new(Mutex::new(Vec::new())),
|
remote_rigs: Arc::new(Mutex::new(Vec::new())),
|
||||||
owner_callsign: None,
|
owner_callsign: None,
|
||||||
|
|||||||
@@ -1247,6 +1247,7 @@ let serverCallsign = null;
|
|||||||
let ownerCallsign = null;
|
let ownerCallsign = null;
|
||||||
let serverLat = null;
|
let serverLat = null;
|
||||||
let serverLon = null;
|
let serverLon = null;
|
||||||
|
let initialMapZoom = 10;
|
||||||
|
|
||||||
function updateFooterBuildInfo() {
|
function updateFooterBuildInfo() {
|
||||||
const serverEl = document.getElementById("footer-server-build");
|
const serverEl = document.getElementById("footer-server-build");
|
||||||
@@ -1274,6 +1275,9 @@ function render(update) {
|
|||||||
}
|
}
|
||||||
if (update.server_latitude != null) serverLat = update.server_latitude;
|
if (update.server_latitude != null) serverLat = update.server_latitude;
|
||||||
if (update.server_longitude != null) serverLon = update.server_longitude;
|
if (update.server_longitude != null) serverLon = update.server_longitude;
|
||||||
|
if (typeof update.initial_map_zoom === "number" && Number.isFinite(update.initial_map_zoom)) {
|
||||||
|
initialMapZoom = Math.max(1, Math.round(update.initial_map_zoom));
|
||||||
|
}
|
||||||
updateTitle();
|
updateTitle();
|
||||||
updateFooterBuildInfo();
|
updateFooterBuildInfo();
|
||||||
|
|
||||||
@@ -2406,7 +2410,7 @@ function initAprsMap() {
|
|||||||
|
|
||||||
const hasLocation = serverLat != null && serverLon != null;
|
const hasLocation = serverLat != null && serverLon != null;
|
||||||
const center = hasLocation ? [serverLat, serverLon] : [20, 0];
|
const center = hasLocation ? [serverLat, serverLon] : [20, 0];
|
||||||
const zoom = hasLocation ? 10 : 2;
|
const zoom = hasLocation ? initialMapZoom : 2;
|
||||||
|
|
||||||
aprsMap = L.map("aprs-map").setView(center, zoom);
|
aprsMap = L.map("aprs-map").setView(center, zoom);
|
||||||
updateMapBaseLayerForTheme(currentTheme());
|
updateMapBaseLayerForTheme(currentTheme());
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ struct FrontendMeta {
|
|||||||
rig_ids: Vec<String>,
|
rig_ids: Vec<String>,
|
||||||
owner_callsign: Option<String>,
|
owner_callsign: Option<String>,
|
||||||
show_sdr_gain_control: bool,
|
show_sdr_gain_control: bool,
|
||||||
|
initial_map_zoom: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/status")]
|
#[get("/status")]
|
||||||
@@ -85,6 +86,10 @@ fn inject_frontend_meta(json: &str, meta: FrontendMeta) -> String {
|
|||||||
"show_sdr_gain_control".to_string(),
|
"show_sdr_gain_control".to_string(),
|
||||||
serde_json::json!(meta.show_sdr_gain_control),
|
serde_json::json!(meta.show_sdr_gain_control),
|
||||||
);
|
);
|
||||||
|
map.insert(
|
||||||
|
"initial_map_zoom".to_string(),
|
||||||
|
serde_json::json!(meta.initial_map_zoom),
|
||||||
|
);
|
||||||
|
|
||||||
serde_json::to_string(&value).unwrap_or_else(|_| json.to_string())
|
serde_json::to_string(&value).unwrap_or_else(|_| json.to_string())
|
||||||
}
|
}
|
||||||
@@ -101,6 +106,7 @@ fn frontend_meta_from_context(
|
|||||||
rig_ids: rig_ids_from_context(context),
|
rig_ids: rig_ids_from_context(context),
|
||||||
owner_callsign: owner_callsign_from_context(context),
|
owner_callsign: owner_callsign_from_context(context),
|
||||||
show_sdr_gain_control: show_sdr_gain_control_from_context(context),
|
show_sdr_gain_control: show_sdr_gain_control_from_context(context),
|
||||||
|
initial_map_zoom: initial_map_zoom_from_context(context),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,6 +144,10 @@ fn show_sdr_gain_control_from_context(context: &FrontendRuntimeContext) -> bool
|
|||||||
context.http_show_sdr_gain_control
|
context.http_show_sdr_gain_control
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn initial_map_zoom_from_context(context: &FrontendRuntimeContext) -> u8 {
|
||||||
|
context.http_initial_map_zoom
|
||||||
|
}
|
||||||
|
|
||||||
#[get("/events")]
|
#[get("/events")]
|
||||||
pub async fn events(
|
pub async fn events(
|
||||||
state: web::Data<watch::Receiver<RigState>>,
|
state: web::Data<watch::Receiver<RigState>>,
|
||||||
|
|||||||
Reference in New Issue
Block a user