feat(http-frontend): add rig and owner header lines

This commit is contained in:
2026-02-27 01:14:30 +01:00
parent 600257a7c4
commit 223c01392a
5 changed files with 55 additions and 16 deletions
+1
View File
@@ -238,6 +238,7 @@ async fn async_init() -> DynResult<AppState> {
.callsign
.clone()
.or_else(|| cfg.general.callsign.clone());
frontend_runtime.owner_callsign = callsign.clone();
info!(
"Starting trx-client (remote: {}, frontends: {})",
+3
View File
@@ -153,6 +153,8 @@ pub struct FrontendRuntimeContext {
pub remote_active_rig_id: Arc<Mutex<Option<String>>>,
/// Cached remote rig list from GetRigs polling.
pub remote_rigs: Arc<Mutex<Vec<RemoteRigEntry>>>,
/// Owner callsign from trx-client config/CLI for frontend display.
pub owner_callsign: Option<String>,
}
impl FrontendRuntimeContext {
@@ -180,6 +182,7 @@ impl FrontendRuntimeContext {
http_auth_cookie_same_site: "Lax".to_string(),
remote_active_rig_id: Arc::new(Mutex::new(None)),
remote_rigs: Arc::new(Mutex::new(Vec::new())),
owner_callsign: None,
}
}
}
@@ -285,6 +285,8 @@ const swrValue = document.getElementById("swr-value");
const loadingEl = document.getElementById("loading");
const contentEl = document.getElementById("content");
const serverSubtitle = document.getElementById("server-subtitle");
const rigSubtitle = document.getElementById("rig-subtitle");
const ownerSubtitle = document.getElementById("owner-subtitle");
const loadingTitle = document.getElementById("loading-title");
const loadingSub = document.getElementById("loading-sub");
const headerSigCanvas = document.getElementById("header-sig-canvas");
@@ -297,7 +299,6 @@ const headerRigSwitchBtn = document.getElementById("header-rig-switch-btn");
let lastControl;
let lastTxEn = null;
let lastRendered = null;
let rigName = "Rig";
let hintTimer = null;
let sigMeasuring = false;
let sigLastSUnits = null;
@@ -729,6 +730,8 @@ function setDisabled(disabled) {
let serverVersion = null;
let serverBuildDate = null;
let serverCallsign = null;
let ownerCallsign = null;
let rigDisplayName = null;
let serverLat = null;
let serverLon = null;
@@ -741,17 +744,20 @@ function updateFooterBuildInfo() {
}
function updateTitle() {
let title = rigName || "Rig";
if (serverCallsign) title = `${serverCallsign}'s ${title}`;
document.getElementById("rig-title").textContent = title;
document.getElementById("rig-title").textContent = originalTitle;
}
function render(update) {
if (!update) return;
if (update.info && update.info.model) rigName = update.info.model;
if (update.info && typeof update.info.model === "string" && update.info.model.length > 0) {
rigDisplayName = update.info.model;
}
if (update.server_version) serverVersion = update.server_version;
if (update.server_build_date) serverBuildDate = update.server_build_date;
if (update.server_callsign) serverCallsign = update.server_callsign;
if (typeof update.owner_callsign === "string" && update.owner_callsign.length > 0) {
ownerCallsign = update.owner_callsign;
}
if (update.server_latitude != null) serverLat = update.server_latitude;
if (update.server_longitude != null) serverLon = update.server_longitude;
updateTitle();
@@ -786,17 +792,21 @@ function render(update) {
if (contentEl) contentEl.style.display = "";
}
// Server subtitle: "trx-server vX.Y.Z hosted by CALL"
if (update.server_version || update.server_callsign) {
let parts = "trx-server";
if (update.server_version) parts += ` v${update.server_version}`;
if (update.server_callsign) {
const cs = update.server_callsign;
serverSubtitle.innerHTML = `${parts} hosted by <a href="https://www.qrzcq.com/call/${encodeURIComponent(cs)}" target="_blank" rel="noopener">${cs}</a>`;
document.title = `${cs} - ${originalTitle}`;
} else {
serverSubtitle.textContent = parts;
if (serverSubtitle) {
if (update.server_version && update.server_callsign) {
serverSubtitle.textContent = `trx-server v${update.server_version} hosted by ${update.server_callsign}`;
} else if (update.server_version) {
serverSubtitle.textContent = `trx-server v${update.server_version}`;
} else if (update.server_callsign) {
serverSubtitle.textContent = `trx-server hosted by ${update.server_callsign}`;
}
}
if (rigSubtitle) {
rigSubtitle.textContent = `Rig: ${rigDisplayName || "--"}`;
}
if (ownerSubtitle) {
ownerSubtitle.textContent = `Owner: ${ownerCallsign || "--"}`;
}
setDisabled(false);
if (update.info && update.info.capabilities && Array.isArray(update.info.capabilities.supported_modes)) {
const modes = update.info.capabilities.supported_modes.map(normalizeMode).filter(Boolean);
@@ -15,7 +15,8 @@
<div class="header-text">
<div class="title"><span id="rig-title">trx-rs</span></div>
<div class="subtitle" id="server-subtitle"></div>
<div class="subtitle">{pkg} v{ver}</div>
<div class="subtitle" id="rig-subtitle">Rig: --</div>
<div class="subtitle" id="owner-subtitle">Owner: --</div>
</div>
<div class="header-signal-wrap" aria-hidden="true">
<canvas id="header-sig-canvas"></canvas>
@@ -32,9 +32,23 @@ const REQUEST_TIMEOUT: Duration = Duration::from_secs(15);
#[get("/status")]
pub async fn status_api(
state: web::Data<watch::Receiver<RigState>>,
clients: web::Data<Arc<AtomicUsize>>,
context: web::Data<Arc<FrontendRuntimeContext>>,
) -> Result<impl Responder, Error> {
let state = wait_for_view(state.get_ref().clone()).await?;
Ok(HttpResponse::Ok().json(state))
let json = serde_json::to_string(&state).map_err(actix_web::error::ErrorInternalServerError)?;
let json = inject_frontend_meta(
&json,
clients.load(Ordering::Relaxed),
context.rigctl_clients.load(Ordering::Relaxed),
rigctl_addr_from_context(context.get_ref().as_ref()),
active_rig_id_from_context(context.get_ref().as_ref()),
rig_ids_from_context(context.get_ref().as_ref()),
owner_callsign_from_context(context.get_ref().as_ref()),
);
Ok(HttpResponse::Ok()
.insert_header((header::CONTENT_TYPE, "application/json"))
.body(json))
}
/// Inject `"clients": N` into a JSON object string.
@@ -45,6 +59,7 @@ fn inject_frontend_meta(
rigctl_addr: Option<String>,
active_rig_id: Option<String>,
rig_ids: Vec<String>,
owner_callsign: Option<String>,
) -> String {
let mut value: serde_json::Value = match serde_json::from_str(json) {
Ok(v) => v,
@@ -66,6 +81,9 @@ fn inject_frontend_meta(
map.insert("active_rig_id".to_string(), serde_json::json!(rig_id));
}
map.insert("rig_ids".to_string(), serde_json::json!(rig_ids));
if let Some(owner) = owner_callsign {
map.insert("owner_callsign".to_string(), serde_json::json!(owner));
}
serde_json::to_string(&value).unwrap_or_else(|_| json.to_string())
}
@@ -96,6 +114,10 @@ fn rig_ids_from_context(context: &FrontendRuntimeContext) -> Vec<String> {
.unwrap_or_default()
}
fn owner_callsign_from_context(context: &FrontendRuntimeContext) -> Option<String> {
context.owner_callsign.clone()
}
#[get("/events")]
pub async fn events(
state: web::Data<watch::Receiver<RigState>>,
@@ -117,6 +139,7 @@ pub async fn events(
rigctl_addr_from_context(context.get_ref().as_ref()),
active_rig_id_from_context(context.get_ref().as_ref()),
rig_ids_from_context(context.get_ref().as_ref()),
owner_callsign_from_context(context.get_ref().as_ref()),
);
let initial_stream =
once(async move { Ok::<Bytes, Error>(Bytes::from(format!("data: {initial_json}\n\n"))) });
@@ -136,6 +159,7 @@ pub async fn events(
rigctl_addr_from_context(context.as_ref()),
active_rig_id_from_context(context.as_ref()),
rig_ids_from_context(context.as_ref()),
owner_callsign_from_context(context.as_ref()),
);
Ok::<Bytes, Error>(Bytes::from(format!("data: {json}\n\n")))
})