[feat](trx-frontend-http): add Plugins tab showing registered frontends
Add GET /frontends API endpoint returning registered frontend names as JSON. Add Plugins tab to the web UI that fetches and displays the list. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
This commit is contained in:
@@ -615,6 +615,18 @@ document.querySelector(".tab-bar").addEventListener("click", (e) => {
|
||||
|
||||
connect();
|
||||
|
||||
// --- Plugins tab ---
|
||||
fetch("/frontends").then(r => r.json()).then(names => {
|
||||
const list = document.getElementById("plugins-list");
|
||||
if (!Array.isArray(names) || names.length === 0) {
|
||||
list.innerHTML = '<div class="plugin-item" style="color:var(--text-muted);">No frontends registered</div>';
|
||||
return;
|
||||
}
|
||||
list.innerHTML = names.map(n => `<div class="plugin-item">${n}</div>`).join("");
|
||||
}).catch(err => {
|
||||
console.error("Failed to fetch frontends", err);
|
||||
});
|
||||
|
||||
// --- Signal measurement ---
|
||||
const sigMeasureBtn = document.getElementById("sig-measure-btn");
|
||||
const sigClearBtn = document.getElementById("sig-clear-btn");
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
</div>
|
||||
<div class="tab-bar">
|
||||
<button class="tab active" data-tab="main">Main</button>
|
||||
<button class="tab" data-tab="plugins">Plugins</button>
|
||||
<button class="tab" data-tab="about">About</button>
|
||||
</div>
|
||||
<div id="tab-main" class="tab-panel">
|
||||
@@ -116,6 +117,9 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tab-plugins" class="tab-panel" style="display:none;">
|
||||
<div id="plugins-list"></div>
|
||||
</div>
|
||||
<div id="tab-about" class="tab-panel" style="display:none;">
|
||||
<table class="about-table">
|
||||
<tr><td>Server</td><td id="about-server-ver">--</td></tr>
|
||||
|
||||
@@ -157,6 +157,8 @@ small { color: var(--text-muted); }
|
||||
.about-table td { padding: 0.5rem 0.6rem; border-bottom: 1px solid var(--border); }
|
||||
.about-table tr:last-child td { border-bottom: none; }
|
||||
.about-table td:first-child { color: var(--text-muted); width: 40%; }
|
||||
.plugin-item { padding: 0.5rem 0.6rem; border-bottom: 1px solid var(--border); color: var(--text); }
|
||||
.plugin-item:last-child { border-bottom: none; }
|
||||
.footer { display: flex; justify-content: space-between; align-items: baseline; margin-top: 1.1rem; }
|
||||
.full-row { grid-column: 1 / -1; }
|
||||
.copyright { color: var(--text-muted); font-size: 0.75rem; opacity: 0.7; }
|
||||
|
||||
@@ -26,6 +26,12 @@ const FAVICON_BYTES: &[u8] = include_bytes!(concat!(
|
||||
const LOGO_BYTES: &[u8] =
|
||||
include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/trx-logo.png"));
|
||||
|
||||
#[get("/frontends")]
|
||||
pub async fn frontends_api() -> Result<impl Responder, Error> {
|
||||
let names = trx_frontend::registered_frontends();
|
||||
Ok(HttpResponse::Ok().json(names))
|
||||
}
|
||||
|
||||
#[get("/status")]
|
||||
pub async fn status_api(
|
||||
state: web::Data<watch::Receiver<RigState>>,
|
||||
@@ -229,6 +235,7 @@ pub async fn set_tx_limit(
|
||||
|
||||
pub fn configure(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(index)
|
||||
.service(frontends_api)
|
||||
.service(status_api)
|
||||
.service(events)
|
||||
.service(toggle_power)
|
||||
@@ -322,9 +329,17 @@ async fn wait_for_view(mut rx: watch::Receiver<RigState>) -> Result<RigSnapshot,
|
||||
return Ok(view);
|
||||
}
|
||||
|
||||
while rx.changed().await.is_ok() {
|
||||
if let Some(view) = rx.borrow().snapshot() {
|
||||
return Ok(view);
|
||||
// Wait up to 5 seconds for a valid snapshot; fall back to a placeholder
|
||||
// so the SSE stream starts immediately and the browser isn't left hanging.
|
||||
let deadline = time::Instant::now() + Duration::from_secs(5);
|
||||
loop {
|
||||
match time::timeout_at(deadline, rx.changed()).await {
|
||||
Ok(Ok(())) => {
|
||||
if let Some(view) = rx.borrow().snapshot() {
|
||||
return Ok(view);
|
||||
}
|
||||
}
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user