Rework Update System dialog to the approved design; match rebuild dialog

The update dialog kept the old bare title + spinner layout from the
previous theme. Rework it (and the rebuild dialog, for consistency) to
the approved The Hub dialog anatomy:

- Header: green chip icon, title, version chip, status pill
  (Checking… / Up to date / Updating… / Restart required / Update
  failed / Status unknown) and a header close button. A spinner appears
  in the header while an update is starting or running.
- System Details card: current version, release channel, and last
  checked (relative time, refreshed on every check).
- The log renders as a console with green "ok" and dim hint lines; the
  up-to-date result shows as a single green console line exactly once
  (the redundant status line is hidden in that state).
- Footer: Close plus a "Check again" primary action that re-runs the
  update check. Close and Check again are disabled while a check or
  update is in flight; all existing recovery actions (Save Error
  Report, Retry Status, Retry Update, Restart Entire System) keep their
  exact semantics.
- Opening the dialog now shows a "Checking…" state immediately while
  the existing reattach-then-check logic runs; reattaching to an
  in-progress update (page reload, RDP reconnect) is unchanged.

Sidebar Update System status tints now use the theme palette (red /
amber / blue / green), and the periodic background check refreshes the
dialog's "last checked" value.

Rebuild dialog gets the same header (icon, version chip, Applying… /
Done / Restart required / Failed pill, header close disabled while a
rebuild runs); its log stays hidden as before.

No API or state-machine changes: same endpoints, same polling, same
reattach and recovery behavior.
This commit is contained in:
2026-09-08 16:40:06 -05:00
parent 2013df55bd
commit d164d423ad
7 changed files with 274 additions and 45 deletions
+9 -8
View File
@@ -272,6 +272,7 @@ async function loadNetwork() {
async function checkUpdates() {
try {
var data = await apiFetch("/api/updates/check");
if (typeof markUpdateChecked === "function") markUpdateChecked();
var hasUpdates = !!data.available;
var updateStatus = data.status || "idle";
var sidebarUpdateBtn = document.getElementById("sidebar-btn-update");
@@ -280,20 +281,20 @@ async function checkUpdates() {
if (updateStatus === "failed") {
// Last update errored and did not apply — surface it as a persistent
// red banner that re-opens the failed run with a "Retry Update" action.
sidebarUpdateBtn.style.borderColor = "#e01b24";
sidebarUpdateBtn.style.backgroundColor = "rgba(224, 27, 36, 0.10)";
sidebarUpdateBtn.style.borderColor = "#f66151";
sidebarUpdateBtn.style.backgroundColor = "rgba(246, 97, 81, 0.10)";
if (sidebarUpdateHint) sidebarUpdateHint.textContent = "Update failed — click to retry";
} else if (updateStatus === "reboot_required") {
sidebarUpdateBtn.style.borderColor = "#e5a50a";
sidebarUpdateBtn.style.backgroundColor = "rgba(229, 165, 10, 0.10)";
sidebarUpdateBtn.style.borderColor = "#e9b64a";
sidebarUpdateBtn.style.backgroundColor = "rgba(233, 182, 74, 0.10)";
if (sidebarUpdateHint) sidebarUpdateHint.textContent = "Restart required";
} else if (updateStatus === "running") {
sidebarUpdateBtn.style.borderColor = "#3584e4";
sidebarUpdateBtn.style.backgroundColor = "rgba(53, 132, 228, 0.10)";
sidebarUpdateBtn.style.borderColor = "#78aeed";
sidebarUpdateBtn.style.backgroundColor = "rgba(120, 174, 237, 0.10)";
if (sidebarUpdateHint) sidebarUpdateHint.textContent = "Update in progress…";
} else if (hasUpdates) {
sidebarUpdateBtn.style.borderColor = "#2ec27e";
sidebarUpdateBtn.style.backgroundColor = "rgba(46, 194, 126, 0.08)";
sidebarUpdateBtn.style.borderColor = "#3ecf8e";
sidebarUpdateBtn.style.backgroundColor = "rgba(62, 207, 142, 0.10)";
if (sidebarUpdateHint) sidebarUpdateHint.textContent = "Updates available!";
} else {
sidebarUpdateBtn.style.borderColor = "";