release(v1.7.27-alpha): mirror transparency — served-by line + one-click test button

- New "Served by {mirror}" line on the System Update page so operators can see
  which mirror actually served the available manifest (vs. which is configured
  primary). Backend threads the served URL through UpdateState.manifest_mirror.
- New update.test-mirror RPC + per-row lightning-bolt button that pings a
  mirror and renders reachable/latency or error inline under the URL.
- UI polish on the mirrors section: Set Primary, Remove, and the new Test
  action are compact icon buttons; add-mirror form moved into a dialog.
- "What's New" block prepended for v1.7.27-alpha.

21/21 update module tests pass. vue-tsc + vite build clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-04-21 13:05:42 -04:00
co-authored by Claude Opus 4.7
parent 0d15ca588a
commit 9868991900
7 changed files with 280 additions and 44 deletions
@@ -444,6 +444,10 @@ impl RpcHandler {
let p = params.unwrap_or(serde_json::json!({}));
self.handle_update_set_primary_mirror(&p).await
}
"update.test-mirror" => {
let p = params.unwrap_or(serde_json::json!({}));
self.handle_update_test_mirror(&p).await
}
"update.apply" => self.handle_update_apply().await,
"update.git-apply" => self.handle_update_git_apply().await,
"update.rollback" => self.handle_update_rollback().await,
+16
View File
@@ -40,6 +40,7 @@ impl RpcHandler {
"last_check": state.last_check,
"update_available": update_info.is_some(),
"update": update_info,
"manifest_mirror": state.manifest_mirror,
}))
}
@@ -195,6 +196,7 @@ impl RpcHandler {
"update_available": state.available_update.is_some(),
"update_in_progress": state.update_in_progress,
"rollback_available": state.rollback_available,
"manifest_mirror": state.manifest_mirror,
"download_progress": if active || completed {
Some(serde_json::json!({
"bytes_downloaded": downloaded,
@@ -290,6 +292,20 @@ impl RpcHandler {
Ok(serde_json::json!({ "mirrors": list }))
}
/// Ping a mirror's manifest URL. Returns reachability, wall-clock
/// latency, and HTTP status. Params: `{ url }`.
pub(super) async fn handle_update_test_mirror(
&self,
params: &serde_json::Value,
) -> Result<serde_json::Value> {
let url = params
.get("url")
.and_then(|v| v.as_str())
.ok_or_else(|| anyhow::anyhow!("missing url"))?;
let result = update::test_mirror(url).await;
Ok(serde_json::to_value(result)?)
}
/// Move a mirror to the top of the list so it's tried first.
/// Params: `{ url }`.
pub(super) async fn handle_update_set_primary_mirror(