Simplify Systems Operational, reword Domain Status, blue restart buttons
- Restart and retry actions (topbar Reboot, Restart Entire System in the update and rebuild dialogs and the restart confirmation, Retry Update, Try Again) are now blue instead of amber — amber read as an error. Status pills keep their semantic colors (amber = restart required). - The service-modal domain section is no longer a checklist: it is titled "Domain Status" and shows a single green "Domain is active" line with the domain (or the backend's not-configured detail and Configure Domain action when there is no domain yet). No "Step 1" wording. - Systems Operational keeps the complexity hidden: the Router card now shows just a verdict — green "Ports 80 and 443 are open" or red "Ports 80 and 443 are not open" — derived from the same live backend diagnostics. Port-forwarding instructions are gone (onboarding covers them); on the Node-only role the card still explains that ports only matter once BTCPay Server or Lightning Wallet Connections (LNURL) is enabled.
This commit is contained in:
@@ -62,22 +62,23 @@ button:disabled {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
}
|
||||
|
||||
/* Amber — destructive-ish confirmations (restart, reboot, retry) */
|
||||
/* Blue — restart / retry actions (amber reads as an error) */
|
||||
.btn-amber,
|
||||
.btn-reboot,
|
||||
.btn-restart-amber,
|
||||
.btn-warning {
|
||||
background: rgba(233, 182, 74, 0.10);
|
||||
border-color: rgba(233, 182, 74, 0.32);
|
||||
color: #f2c45e;
|
||||
background: rgba(120, 174, 237, 0.10);
|
||||
border-color: rgba(120, 174, 237, 0.35);
|
||||
color: #a5cbf2;
|
||||
}
|
||||
|
||||
.btn-amber:hover:not(:disabled),
|
||||
.btn-reboot:hover:not(:disabled),
|
||||
.btn-restart-amber:hover:not(:disabled),
|
||||
.btn-warning:hover:not(:disabled) {
|
||||
background: rgba(233, 182, 74, 0.18);
|
||||
border-color: rgba(233, 182, 74, 0.5);
|
||||
background: rgba(120, 174, 237, 0.18);
|
||||
border-color: rgba(120, 174, 237, 0.55);
|
||||
color: #c2dcf8;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
@@ -96,9 +97,9 @@ button:disabled {
|
||||
/* ── Header / topbar buttons ────────────────────────────────────── */
|
||||
|
||||
.btn-header-reboot {
|
||||
background: rgba(233, 182, 74, 0.10);
|
||||
border: 1px solid rgba(233, 182, 74, 0.32);
|
||||
color: #f2c45e;
|
||||
background: rgba(120, 174, 237, 0.10);
|
||||
border: 1px solid rgba(120, 174, 237, 0.35);
|
||||
color: #a5cbf2;
|
||||
font-size: 0.77rem;
|
||||
font-weight: 700;
|
||||
padding: 6px 14px;
|
||||
@@ -106,8 +107,8 @@ button:disabled {
|
||||
}
|
||||
|
||||
.btn-header-reboot:hover:not(:disabled) {
|
||||
background: rgba(233, 182, 74, 0.18);
|
||||
border-color: rgba(233, 182, 74, 0.5);
|
||||
background: rgba(120, 174, 237, 0.18);
|
||||
border-color: rgba(120, 174, 237, 0.55);
|
||||
}
|
||||
|
||||
.btn-logout {
|
||||
|
||||
@@ -208,12 +208,6 @@
|
||||
|
||||
/* ── Systems Operational modal ───────────────────────────────── */
|
||||
|
||||
function internalIp() {
|
||||
var el = document.getElementById("ip-internal");
|
||||
var v = el ? el.textContent.trim() : "";
|
||||
return (v && v !== "…" && v !== "—") ? v : "";
|
||||
}
|
||||
|
||||
function step(n, title, sub, value) {
|
||||
return '<div class="sysstep"><div class="sysnum">' + n + '</div><div class="sysstep-x">' +
|
||||
'<div class="sysstep-t">' + title + (sub ? ' <span class="sysstep-sub">· ' + sub + '</span>' : '') + '</div>' +
|
||||
@@ -250,9 +244,6 @@
|
||||
else running++;
|
||||
});
|
||||
|
||||
var ip = internalIp();
|
||||
var fwd = ip ? ('\u2192 ' + escHtml(ip)) : "forward to this computer";
|
||||
|
||||
var html = "";
|
||||
|
||||
/* System status */
|
||||
@@ -263,32 +254,23 @@
|
||||
step(3, "Turned off", "", off ? escHtml(offNames.join(", ")) : "None") +
|
||||
'</div>';
|
||||
|
||||
/* Router ports — repo wording (domain-prereqs.js / server.py).
|
||||
Node-only role: ports matter only once BTCPay Server or Lightning
|
||||
Wallet Connections (LNURL) is turned on — until then, no router task. */
|
||||
/* Router — a simple open / not-open verdict. How to open the ports is
|
||||
covered during onboarding, so the modal does not repeat instructions.
|
||||
Node-only role: ports only matter once BTCPay Server or Lightning
|
||||
Wallet Connections (LNURL) is turned on. */
|
||||
if (isNodeRole() && !hasEnabledDomainService(services)) {
|
||||
html += '<div class="sysmodal-card">' +
|
||||
'<div class="sysmodal-card-title">' + icon("g-wifi") + 'Router</div>' +
|
||||
'<div class="sysnote"><div class="sysnote-title">' + icon("g-check") + 'No router setup needed yet</div>' +
|
||||
'<div class="sysnote-desc">Ports 80 and 443 only need to be forwarded on your router if you turn on <strong>BTCPay Server</strong> or <strong>Lightning Wallet Connections (LNURL)</strong>. If you enable one of them, come back here — this card will show exactly what to do.</div></div>' +
|
||||
'<div class="sysnote-desc">Ports 80 and 443 only need to be forwarded on your router if you turn on <strong>BTCPay Server</strong> or <strong>Lightning Wallet Connections (LNURL)</strong>. If you enable one of them, come back here to check your ports.</div></div>' +
|
||||
'</div>';
|
||||
} else {
|
||||
html += '<div class="sysmodal-card">' +
|
||||
'<div class="sysmodal-card-title">' + icon("g-wifi") + 'Router — Ports to Forward</div>' +
|
||||
step(1, "Port 80", "TCP — HTTP (redirect to HTTPS)", fwd) +
|
||||
step(2, "Port 443", "TCP — HTTPS", fwd) +
|
||||
'<div class="sysnote"><div class="sysnote-title">' + icon("g-alert") + 'One router task</div>' +
|
||||
'<div class="sysnote-desc">Set the internal and external port to the <strong>same number</strong>. You only need to do this once — all your services share these two ports.</div></div>' +
|
||||
html += '<div class="sysmodal-card" id="sys-ports-card" style="display:none">' +
|
||||
'<div class="sysmodal-card-title">' + icon("g-wifi") + 'Router</div>' +
|
||||
'<div id="sys-ports-status"><div class="sysfineprint">Checking…</div></div>' +
|
||||
'</div>';
|
||||
}
|
||||
|
||||
/* Live domain diagnostics (sequential checklist from the backend —
|
||||
same data the domain-service modals show) */
|
||||
html += '<div class="sysmodal-card" id="sys-check-card" style="display:none">' +
|
||||
'<div class="sysmodal-card-title">' + icon("g-check") + 'Ports 80 & 443 Check</div>' +
|
||||
'<div id="sys-check-steps"><div class="sysfineprint">Checking…</div></div>' +
|
||||
'</div>';
|
||||
|
||||
/* Who uses these ports (redundant on a Node install with no domain
|
||||
services on — the router note above already covers it) */
|
||||
if (!isNodeRole() || hasEnabledDomainService(services)) {
|
||||
@@ -300,33 +282,32 @@
|
||||
$sysBody.innerHTML = html;
|
||||
$sysModal.classList.add("open");
|
||||
|
||||
/* Poll the first configured domain service for its live checklist */
|
||||
var checkCard = document.getElementById("sys-check-card");
|
||||
var stepsEl = document.getElementById("sys-check-steps");
|
||||
/* Poll the first configured domain service and reduce its diagnostics
|
||||
to one verdict: the ports are open or they are not. */
|
||||
var portsCard = document.getElementById("sys-ports-card");
|
||||
var portsEl = document.getElementById("sys-ports-status");
|
||||
var units = DOMAIN_UNITS.filter(function (u) {
|
||||
return services.some(function (s) { return s.unit === u && s.enabled; });
|
||||
});
|
||||
if (!units.length || !checkCard || !stepsEl) return;
|
||||
checkCard.style.display = "";
|
||||
if (!units.length || !portsCard || !portsEl) return;
|
||||
portsCard.style.display = "";
|
||||
|
||||
apiFetch("/api/service-detail/" + encodeURIComponent(units[0]))
|
||||
.then(function (data) {
|
||||
var steps = (data && data.domain_check_steps) || [];
|
||||
if (!steps.length) { checkCard.style.display = "none"; return; }
|
||||
var mark = { ok: "\u2705", error: "\u274c", warning: "\u26a0\ufe0f", skipped: "\u23ed\ufe0f" };
|
||||
var html2 = "";
|
||||
steps.forEach(function (st) {
|
||||
var m = mark[st.status] || "\u2014";
|
||||
var detail = escHtml(st.detail || "").replace(/\n/g, "<br>");
|
||||
html2 += '<div class="sysstep"><div class="sysnum">' + st.step + '</div><div class="sysstep-x">' +
|
||||
'<div class="sysstep-t">' + m + " " + escHtml(st.label || "") + '</div>' +
|
||||
(detail ? '<div class="sysstep-t" style="font-weight:400;color:var(--text-2);font-size:0.77rem;margin-top:3px">' + detail + '</div>' : '') +
|
||||
'</div></div>';
|
||||
var portsStep = null;
|
||||
steps.forEach(function (s) {
|
||||
if (Number(s.step) === 3 || /ports?\s*80/i.test(s.label || "")) portsStep = s;
|
||||
});
|
||||
stepsEl.innerHTML = html2;
|
||||
if (!portsStep) { portsCard.style.display = "none"; return; }
|
||||
if (portsStep.status === "ok") {
|
||||
portsEl.innerHTML = '<div class="svc-detail-status" style="font-size:0.92rem"><span class="status-dot active"></span>Ports 80 and 443 are open</div>';
|
||||
} else {
|
||||
portsEl.innerHTML = '<div class="svc-detail-status" style="font-size:0.92rem"><span class="status-dot failed"></span>Ports 80 and 443 are not open</div>';
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
checkCard.style.display = "none";
|
||||
portsCard.style.display = "none";
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -725,16 +725,20 @@ async function openServiceDetailModal(unit, name, icon) {
|
||||
});
|
||||
var stepsHtml = "";
|
||||
steps.forEach(function(step) {
|
||||
var iconLabel = "—";
|
||||
if (step.status === "ok") iconLabel = "✅";
|
||||
else if (step.status === "error") iconLabel = "❌";
|
||||
else if (step.status === "warning") iconLabel = "⚠️";
|
||||
else if (step.status === "skipped") iconLabel = "⏭️";
|
||||
var detail = escHtml(step.detail || "").replace(/\n/g, "<br>");
|
||||
stepsHtml += '<div class="svc-detail-troubleshoot" style="margin-bottom:10px">' +
|
||||
'<strong>' + iconLabel + ' Step ' + escHtml(String(step.step)) + ': ' + escHtml(step.label || "") + '</strong>' +
|
||||
(detail ? '<div style="margin-top:6px">' + detail + '</div>' : '') +
|
||||
'</div>';
|
||||
if (step.status === "ok") {
|
||||
// Not a checklist anymore — just note that the domain works.
|
||||
stepsHtml += '<div class="svc-detail-status"><span class="status-dot active"></span>Domain is active</div>' +
|
||||
(detail ? '<div class="svc-detail-desc" style="margin-top:6px">' + detail + '</div>' : '');
|
||||
} else {
|
||||
var iconLabel = "❌";
|
||||
if (step.status === "warning") iconLabel = "⚠️";
|
||||
else if (step.status === "skipped") iconLabel = "⏭️";
|
||||
stepsHtml += '<div class="svc-detail-troubleshoot" style="margin-bottom:10px">' +
|
||||
'<strong>' + iconLabel + ' ' + escHtml(step.label || "Domain not configured") + '</strong>' +
|
||||
(detail ? '<div style="margin-top:6px">' + detail + '</div>' : '') +
|
||||
'</div>';
|
||||
}
|
||||
});
|
||||
|
||||
var domainActionHtml = "";
|
||||
@@ -746,7 +750,7 @@ async function openServiceDetailModal(unit, name, icon) {
|
||||
}
|
||||
|
||||
addSetup('<div class="svc-detail-section">' +
|
||||
'<div class="svc-detail-section-title">Domain Diagnostic Checklist</div>' +
|
||||
'<div class="svc-detail-section-title">Domain Status</div>' +
|
||||
stepsHtml +
|
||||
domainActionHtml +
|
||||
'</div>');
|
||||
|
||||
Reference in New Issue
Block a user