diff --git a/app/sovran_systemsos_web/static/app.js b/app/sovran_systemsos_web/static/app.js index e62d49d..3fab03e 100644 --- a/app/sovran_systemsos_web/static/app.js +++ b/app/sovran_systemsos_web/static/app.js @@ -27,8 +27,9 @@ let _updateLog = ""; let _updatePollTimer = null; let _updateLogOffset = 0; let _serverWasDown = false; +let _updateFinished = false; -// ── DOM refs ────────────────────────────────────────────���───────── +// ── DOM refs ────────────────────────────────────────────────────── const $tilesArea = document.getElementById("tiles-area"); const $updateBtn = document.getElementById("btn-update"); @@ -250,8 +251,13 @@ async function loadNetwork() { async function checkUpdates() { try { const data = await apiFetch("/api/updates/check"); + const hasUpdates = !!data.available; if ($updateBadge) { - $updateBadge.classList.toggle("visible", !!data.available); + $updateBadge.classList.toggle("visible", hasUpdates); + } + // Toggle button color: blue (default) → green (updates available) + if ($updateBtn) { + $updateBtn.classList.toggle("has-updates", hasUpdates); } } catch (_) {} } @@ -263,6 +269,7 @@ function openUpdateModal() { _updateLog = ""; _updateLogOffset = 0; _serverWasDown = false; + _updateFinished = false; if ($modalLog) $modalLog.textContent = ""; if ($modalStatus) $modalStatus.textContent = "Starting update…"; if ($modalSpinner) $modalSpinner.classList.add("spinning"); @@ -323,6 +330,9 @@ function stopUpdatePoll() { } async function pollUpdateStatus() { + // Don't poll if we already know it's done + if (_updateFinished) return; + try { const data = await apiFetch(`/api/updates/status?offset=${_updateLogOffset}`); @@ -340,6 +350,7 @@ async function pollUpdateStatus() { // Check if finished if (!data.running) { + _updateFinished = true; stopUpdatePoll(); if (data.result === "success") { onUpdateDone(true); @@ -402,7 +413,7 @@ if ($modal) { }); } -// ── Init ────────────────────────────────────────────────────────── +// ── Init ──────��─────────────────────────────────────────────────── async function init() { try { diff --git a/app/sovran_systemsos_web/static/style.css b/app/sovran_systemsos_web/static/style.css index 2031d70..6263d99 100644 --- a/app/sovran_systemsos_web/static/style.css +++ b/app/sovran_systemsos_web/static/style.css @@ -100,9 +100,10 @@ button:disabled { opacity: 0.88; } +/* Update button: blue by default, green when updates available */ .btn-update { - background-color: var(--green); - color: #fff; + background-color: var(--accent-color); + color: #1e1e2e; position: relative; display: flex; align-items: center; @@ -110,6 +111,15 @@ button:disabled { } .btn-update:hover:not(:disabled) { + opacity: 0.88; +} + +.btn-update.has-updates { + background-color: var(--green); + color: #fff; +} + +.btn-update.has-updates:hover:not(:disabled) { background-color: #27ae6e; } @@ -451,6 +461,7 @@ button:disabled { background-color: #12121c; white-space: pre-wrap; word-break: break-all; + min-height: 200px; } .modal-footer { @@ -462,13 +473,14 @@ button:disabled { border-top: 1px solid var(--border-color); } +/* Reboot button: green */ .btn-reboot { - background-color: var(--red); + background-color: var(--green); color: #fff; } .btn-reboot:hover:not(:disabled) { - background-color: #c0181f; + background-color: #27ae6e; } .btn-save { @@ -527,4 +539,4 @@ button:disabled { width: 160px; min-height: 200px; } -} +} \ No newline at end of file