Merge pull request #55 from naturallaw777/copilot/remove-feature-manager-step
[WIP] Remove Feature Manager step from onboarding wizard
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
/* Sovran_SystemsOS Hub — First-Boot Onboarding Wizard
|
/* Sovran_SystemsOS Hub — First-Boot Onboarding Wizard
|
||||||
Drives the 6-step post-install setup flow. */
|
Drives the 5-step post-install setup flow. */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// ── Constants ─────────────────────────────────────────────────────
|
// ── Constants ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
const TOTAL_STEPS = 6;
|
const TOTAL_STEPS = 5;
|
||||||
|
|
||||||
// Domains that may need configuration, with service unit mapping for enabled check
|
// Domains that may need configuration, with service unit mapping for enabled check
|
||||||
const DOMAIN_DEFS = [
|
const DOMAIN_DEFS = [
|
||||||
@@ -17,18 +17,11 @@ const DOMAIN_DEFS = [
|
|||||||
{ name: "wordpress", label: "WordPress", unit: "phpfpm-wordpress.service", needsDdns: true },
|
{ name: "wordpress", label: "WordPress", unit: "phpfpm-wordpress.service", needsDdns: true },
|
||||||
];
|
];
|
||||||
|
|
||||||
const REBUILD_POLL_INTERVAL = 2000;
|
|
||||||
|
|
||||||
// ── State ─────────────────────────────────────────────────────────
|
// ── State ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
var _currentStep = 1;
|
var _currentStep = 1;
|
||||||
var _servicesData = null;
|
var _servicesData = null;
|
||||||
var _domainsData = null;
|
var _domainsData = null;
|
||||||
var _featuresData = null;
|
|
||||||
|
|
||||||
var _rebuildPollTimer = null;
|
|
||||||
var _rebuildLogOffset = 0;
|
|
||||||
var _rebuildFinished = false;
|
|
||||||
|
|
||||||
// ── Helpers ───────────────────────────────────────────────────────
|
// ── Helpers ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -89,7 +82,6 @@ function showStep(step) {
|
|||||||
if (step === 2) loadStep2();
|
if (step === 2) loadStep2();
|
||||||
if (step === 3) loadStep3();
|
if (step === 3) loadStep3();
|
||||||
if (step === 4) loadStep4();
|
if (step === 4) loadStep4();
|
||||||
if (step === 5) loadStep5();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Step 1: Welcome ───────────────────────────────────────────────
|
// ── Step 1: Welcome ───────────────────────────────────────────────
|
||||||
@@ -454,217 +446,10 @@ async function loadStep4() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Step 5: Feature Manager ───────────────────────────────────────
|
// ── Step 5: Complete ──────────────────────────────────────────────
|
||||||
|
|
||||||
async function loadStep5() {
|
|
||||||
var body = document.getElementById("step-5-body");
|
|
||||||
if (!body) return;
|
|
||||||
body.innerHTML = '<p class="onboarding-loading">Loading features…</p>';
|
|
||||||
|
|
||||||
try {
|
|
||||||
_featuresData = await apiFetch("/api/features");
|
|
||||||
} catch (err) {
|
|
||||||
body.innerHTML = '<p class="onboarding-error">⚠ Could not load features: ' + escHtml(err.message) + '</p>';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderFeaturesStep(_featuresData);
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderFeaturesStep(data) {
|
|
||||||
var body = document.getElementById("step-5-body");
|
|
||||||
if (!body) return;
|
|
||||||
|
|
||||||
var SUBCATEGORY_LABELS = {
|
|
||||||
"infrastructure": "🔧 Infrastructure",
|
|
||||||
"bitcoin": "₿ Bitcoin",
|
|
||||||
"communication": "💬 Communication",
|
|
||||||
"nostr": "📡 Nostr",
|
|
||||||
};
|
|
||||||
|
|
||||||
var SUBCATEGORY_ORDER = ["infrastructure", "bitcoin", "communication", "nostr"];
|
|
||||||
|
|
||||||
var grouped = {};
|
|
||||||
(data.features || []).forEach(function(f) {
|
|
||||||
var cat = f.category || "other";
|
|
||||||
if (!grouped[cat]) grouped[cat] = [];
|
|
||||||
grouped[cat].push(f);
|
|
||||||
});
|
|
||||||
|
|
||||||
var html = "";
|
|
||||||
var orderedCats = SUBCATEGORY_ORDER.filter(function(k) { return grouped[k]; });
|
|
||||||
Object.keys(grouped).forEach(function(k) {
|
|
||||||
if (orderedCats.indexOf(k) === -1) orderedCats.push(k);
|
|
||||||
});
|
|
||||||
|
|
||||||
orderedCats.forEach(function(catKey) {
|
|
||||||
var feats = grouped[catKey];
|
|
||||||
if (!feats || feats.length === 0) return;
|
|
||||||
|
|
||||||
var catLabel = SUBCATEGORY_LABELS[catKey] || catKey;
|
|
||||||
html += '<div class="onboarding-feat-group">';
|
|
||||||
html += '<div class="onboarding-feat-group-title">' + escHtml(catLabel) + '</div>';
|
|
||||||
|
|
||||||
feats.forEach(function(feat) {
|
|
||||||
var domainHtml = "";
|
|
||||||
if (feat.needs_domain) {
|
|
||||||
if (feat.domain_configured) {
|
|
||||||
domainHtml = '<span class="onboarding-feat-domain onboarding-feat-domain--ok">🌐 Domain configured</span>';
|
|
||||||
} else {
|
|
||||||
domainHtml = '<span class="onboarding-feat-domain onboarding-feat-domain--missing">🌐 Domain not set</span>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '<div class="onboarding-feat-card" id="feat-card-' + escHtml(feat.id) + '">';
|
|
||||||
html += '<div class="onboarding-feat-info">';
|
|
||||||
html += '<div class="onboarding-feat-name">' + escHtml(feat.name) + '</div>';
|
|
||||||
html += '<div class="onboarding-feat-desc">' + escHtml(feat.description) + '</div>';
|
|
||||||
html += domainHtml;
|
|
||||||
html += '</div>';
|
|
||||||
html += '<label class="feature-toggle' + (feat.enabled ? " active" : "") + '" title="Toggle ' + escHtml(feat.name) + '">';
|
|
||||||
html += '<input type="checkbox" class="feature-toggle-input" data-feat-id="' + escHtml(feat.id) + '"' + (feat.enabled ? " checked" : "") + ' />';
|
|
||||||
html += '<span class="feature-toggle-slider"></span>';
|
|
||||||
html += '</label>';
|
|
||||||
html += '</div>';
|
|
||||||
});
|
|
||||||
|
|
||||||
html += '</div>';
|
|
||||||
});
|
|
||||||
|
|
||||||
body.innerHTML = html;
|
|
||||||
|
|
||||||
// Wire up toggles
|
|
||||||
body.querySelectorAll(".feature-toggle-input").forEach(function(input) {
|
|
||||||
var featId = input.dataset.featId;
|
|
||||||
var label = input.closest(".feature-toggle");
|
|
||||||
var feat = (data.features || []).find(function(f) { return f.id === featId; });
|
|
||||||
if (!feat) return;
|
|
||||||
|
|
||||||
input.addEventListener("change", function() {
|
|
||||||
var newEnabled = input.checked;
|
|
||||||
// Revert UI until confirmed/done
|
|
||||||
input.checked = feat.enabled;
|
|
||||||
if (newEnabled) { if (label) label.classList.remove("active"); }
|
|
||||||
else { if (label) label.classList.add("active"); }
|
|
||||||
|
|
||||||
handleFeatureToggleStep5(feat, newEnabled, input, label);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleFeatureToggleStep5(feat, newEnabled, inputEl, labelEl) {
|
|
||||||
// For Bitcoin features being enabled, show a clear mutual-exclusivity confirmation
|
|
||||||
if (newEnabled && (feat.id === "bip110" || feat.id === "bitcoin-core")) {
|
|
||||||
var confirmMsg;
|
|
||||||
if (feat.id === "bip110") {
|
|
||||||
confirmMsg = "Only one Bitcoin node implementation can be active. Enabling Bitcoin Knots + BIP110 will disable Bitcoin Core (if active). Continue?";
|
|
||||||
} else {
|
|
||||||
confirmMsg = "Only one Bitcoin node implementation can be active. Enabling Bitcoin Core will disable Bitcoin Knots + BIP110 (if active). Continue?";
|
|
||||||
}
|
|
||||||
if (!confirm(confirmMsg)) {
|
|
||||||
if (inputEl) inputEl.checked = feat.enabled;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setStatus("step-5-rebuild-status", "Saving…", "info");
|
|
||||||
|
|
||||||
// Collect nostr_npub if needed
|
|
||||||
var extra = {};
|
|
||||||
if (newEnabled && feat.id === "haven") {
|
|
||||||
var npub = prompt("Enter your Nostr public key (npub1…):");
|
|
||||||
if (!npub || !npub.trim()) {
|
|
||||||
setStatus("step-5-rebuild-status", "⚠ npub required for Haven", "error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
extra.nostr_npub = npub.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
await apiFetch("/api/features/toggle", {
|
|
||||||
method: "POST",
|
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify({ feature: feat.id, enabled: newEnabled, extra: extra }),
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
setStatus("step-5-rebuild-status", "⚠ " + err.message, "error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update local state
|
|
||||||
feat.enabled = newEnabled;
|
|
||||||
if (inputEl) inputEl.checked = newEnabled;
|
|
||||||
if (labelEl) {
|
|
||||||
if (newEnabled) labelEl.classList.add("active");
|
|
||||||
else labelEl.classList.remove("active");
|
|
||||||
}
|
|
||||||
|
|
||||||
setStatus("step-5-rebuild-status", "✓ Feature updated — system rebuild started", "ok");
|
|
||||||
startRebuildPoll();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Rebuild progress polling ──────────────────────────────────────
|
|
||||||
|
|
||||||
function startRebuildPoll() {
|
|
||||||
_rebuildLogOffset = 0;
|
|
||||||
_rebuildFinished = false;
|
|
||||||
|
|
||||||
var modal = document.getElementById("ob-rebuild-modal");
|
|
||||||
var statusEl = document.getElementById("ob-rebuild-status");
|
|
||||||
var logEl = document.getElementById("ob-rebuild-log");
|
|
||||||
var closeBtn = document.getElementById("ob-rebuild-close");
|
|
||||||
var spinner = document.getElementById("ob-rebuild-spinner");
|
|
||||||
|
|
||||||
if (modal) modal.style.display = "flex";
|
|
||||||
if (statusEl) statusEl.textContent = "Rebuilding…";
|
|
||||||
if (logEl) logEl.textContent = "";
|
|
||||||
if (closeBtn) closeBtn.disabled = true;
|
|
||||||
if (spinner) spinner.style.display = "";
|
|
||||||
|
|
||||||
if (_rebuildPollTimer) clearInterval(_rebuildPollTimer);
|
|
||||||
_rebuildPollTimer = setInterval(pollRebuild, REBUILD_POLL_INTERVAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function pollRebuild() {
|
|
||||||
if (_rebuildFinished) {
|
|
||||||
clearInterval(_rebuildPollTimer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
var data = await apiFetch("/api/rebuild/status?offset=" + _rebuildLogOffset);
|
|
||||||
var logEl = document.getElementById("ob-rebuild-log");
|
|
||||||
var statusEl = document.getElementById("ob-rebuild-status");
|
|
||||||
var closeBtn = document.getElementById("ob-rebuild-close");
|
|
||||||
var spinner = document.getElementById("ob-rebuild-spinner");
|
|
||||||
|
|
||||||
if (data.log && logEl) {
|
|
||||||
logEl.textContent += data.log;
|
|
||||||
logEl.scrollTop = logEl.scrollHeight;
|
|
||||||
_rebuildLogOffset = data.offset || _rebuildLogOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data.running) {
|
|
||||||
_rebuildFinished = true;
|
|
||||||
clearInterval(_rebuildPollTimer);
|
|
||||||
if (data.result === "success" || data.result === "ok") {
|
|
||||||
if (statusEl) statusEl.textContent = "✓ Rebuild complete";
|
|
||||||
if (spinner) spinner.style.display = "none";
|
|
||||||
setStatus("step-5-rebuild-status", "✓ Rebuild complete", "ok");
|
|
||||||
} else {
|
|
||||||
if (statusEl) statusEl.textContent = "⚠ Rebuild finished with issues";
|
|
||||||
if (spinner) spinner.style.display = "none";
|
|
||||||
setStatus("step-5-rebuild-status", "⚠ Rebuild finished with issues — see log", "error");
|
|
||||||
}
|
|
||||||
if (closeBtn) closeBtn.disabled = false;
|
|
||||||
}
|
|
||||||
} catch (_) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Step 6: Complete ──────────────────────────────────────────────
|
|
||||||
|
|
||||||
async function completeOnboarding() {
|
async function completeOnboarding() {
|
||||||
var btn = document.getElementById("step-6-finish");
|
var btn = document.getElementById("step-5-finish");
|
||||||
if (btn) { btn.disabled = true; btn.textContent = "Finishing…"; }
|
if (btn) { btn.disabled = true; btn.textContent = "Finishing…"; }
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -698,32 +483,19 @@ function wireNavButtons() {
|
|||||||
var s3next = document.getElementById("step-3-next");
|
var s3next = document.getElementById("step-3-next");
|
||||||
if (s3next) s3next.addEventListener("click", function() { showStep(4); });
|
if (s3next) s3next.addEventListener("click", function() { showStep(4); });
|
||||||
|
|
||||||
// Step 4 → 5
|
// Step 4 → 5 (Complete)
|
||||||
var s4next = document.getElementById("step-4-next");
|
var s4next = document.getElementById("step-4-next");
|
||||||
if (s4next) s4next.addEventListener("click", function() { showStep(5); });
|
if (s4next) s4next.addEventListener("click", function() { showStep(5); });
|
||||||
|
|
||||||
// Step 5 → 6
|
// Step 5: finish
|
||||||
var s5next = document.getElementById("step-5-next");
|
var s5finish = document.getElementById("step-5-finish");
|
||||||
if (s5next) s5next.addEventListener("click", function() { showStep(6); });
|
if (s5finish) s5finish.addEventListener("click", completeOnboarding);
|
||||||
|
|
||||||
// Step 6: finish
|
|
||||||
var s6finish = document.getElementById("step-6-finish");
|
|
||||||
if (s6finish) s6finish.addEventListener("click", completeOnboarding);
|
|
||||||
|
|
||||||
// Back buttons
|
// Back buttons
|
||||||
document.querySelectorAll(".onboarding-btn-back").forEach(function(btn) {
|
document.querySelectorAll(".onboarding-btn-back").forEach(function(btn) {
|
||||||
var prev = parseInt(btn.dataset.prev, 10);
|
var prev = parseInt(btn.dataset.prev, 10);
|
||||||
btn.addEventListener("click", function() { showStep(prev); });
|
btn.addEventListener("click", function() { showStep(prev); });
|
||||||
});
|
});
|
||||||
|
|
||||||
// Rebuild modal close
|
|
||||||
var rebuildClose = document.getElementById("ob-rebuild-close");
|
|
||||||
if (rebuildClose) {
|
|
||||||
rebuildClose.addEventListener("click", function() {
|
|
||||||
var modal = document.getElementById("ob-rebuild-modal");
|
|
||||||
if (modal) modal.style.display = "none";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Init ──────────────────────────────────────────────────────────
|
// ── Init ──────────────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -36,8 +36,6 @@
|
|||||||
<span class="onboarding-step-dot" data-step="4">4</span>
|
<span class="onboarding-step-dot" data-step="4">4</span>
|
||||||
<span class="onboarding-step-connector"></span>
|
<span class="onboarding-step-connector"></span>
|
||||||
<span class="onboarding-step-dot" data-step="5">5</span>
|
<span class="onboarding-step-dot" data-step="5">5</span>
|
||||||
<span class="onboarding-step-connector"></span>
|
|
||||||
<span class="onboarding-step-dot" data-step="6">6</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Step panels -->
|
<!-- Step panels -->
|
||||||
@@ -140,30 +138,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ── Step 5: Feature Manager ── -->
|
<!-- ── Step 5: Complete ── -->
|
||||||
<div class="onboarding-panel" id="step-5" style="display:none">
|
<div class="onboarding-panel" id="step-5" style="display:none">
|
||||||
<div class="onboarding-step-header">
|
|
||||||
<span class="onboarding-step-icon">⚙️</span>
|
|
||||||
<h2 class="onboarding-step-title">Feature Manager</h2>
|
|
||||||
<p class="onboarding-step-desc">
|
|
||||||
Enable or disable optional features. Toggling a feature will start
|
|
||||||
a system rebuild in the background.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="onboarding-card onboarding-card--scroll" id="step-5-body">
|
|
||||||
<p class="onboarding-loading">Loading features…</p>
|
|
||||||
</div>
|
|
||||||
<div id="step-5-rebuild-status" class="onboarding-save-status"></div>
|
|
||||||
<div class="onboarding-footer">
|
|
||||||
<button class="btn btn-close-modal onboarding-btn-back" data-prev="4">← Back</button>
|
|
||||||
<button class="btn btn-primary onboarding-btn-next" id="step-5-next">
|
|
||||||
Continue →
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ── Step 6: Complete ── -->
|
|
||||||
<div class="onboarding-panel" id="step-6" style="display:none">
|
|
||||||
<div class="onboarding-hero">
|
<div class="onboarding-hero">
|
||||||
<div class="onboarding-logo">✅</div>
|
<div class="onboarding-logo">✅</div>
|
||||||
<h1 class="onboarding-title">Your Sovran_SystemsOS is Ready!</h1>
|
<h1 class="onboarding-title">Your Sovran_SystemsOS is Ready!</h1>
|
||||||
@@ -178,12 +154,11 @@
|
|||||||
<li>✅ Domain configuration saved</li>
|
<li>✅ Domain configuration saved</li>
|
||||||
<li>✅ Port forwarding reviewed</li>
|
<li>✅ Port forwarding reviewed</li>
|
||||||
<li>✅ Credentials noted</li>
|
<li>✅ Credentials noted</li>
|
||||||
<li>✅ Features configured</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="onboarding-footer">
|
<div class="onboarding-footer">
|
||||||
<button class="btn btn-close-modal onboarding-btn-back" data-prev="5">← Back</button>
|
<button class="btn btn-close-modal onboarding-btn-back" data-prev="4">← Back</button>
|
||||||
<button class="btn btn-primary" id="step-6-finish">
|
<button class="btn btn-primary" id="step-5-finish">
|
||||||
Go to Dashboard →
|
Go to Dashboard →
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -192,21 +167,6 @@
|
|||||||
</div><!-- /panel-wrap -->
|
</div><!-- /panel-wrap -->
|
||||||
</div><!-- /shell -->
|
</div><!-- /shell -->
|
||||||
|
|
||||||
<!-- Rebuild progress modal (reused from main app) -->
|
|
||||||
<div class="modal-overlay" id="ob-rebuild-modal" role="dialog" aria-modal="true" aria-labelledby="ob-rebuild-title">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-header">
|
|
||||||
<span class="modal-title" id="ob-rebuild-title">Rebuilding System…</span>
|
|
||||||
<div class="modal-spinner" id="ob-rebuild-spinner"></div>
|
|
||||||
<span class="modal-status" id="ob-rebuild-status">Please wait</span>
|
|
||||||
</div>
|
|
||||||
<div class="modal-log" id="ob-rebuild-log" aria-live="polite"></div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button class="btn btn-close-modal" id="ob-rebuild-close" disabled>Close</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="/static/onboarding.js?v={{ onboarding_js_hash }}"></script>
|
<script src="/static/onboarding.js?v={{ onboarding_js_hash }}"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -27,8 +27,6 @@
|
|||||||
<span class="onboarding-step-dot" data-step="4">4</span>
|
<span class="onboarding-step-dot" data-step="4">4</span>
|
||||||
<span class="onboarding-step-connector"></span>
|
<span class="onboarding-step-connector"></span>
|
||||||
<span class="onboarding-step-dot" data-step="5">5</span>
|
<span class="onboarding-step-dot" data-step="5">5</span>
|
||||||
<span class="onboarding-step-connector"></span>
|
|
||||||
<span class="onboarding-step-dot" data-step="6">6</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Step panels -->
|
<!-- Step panels -->
|
||||||
@@ -131,30 +129,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- ── Step 5: Feature Manager ── -->
|
<!-- ── Step 5: Complete ── -->
|
||||||
<div class="onboarding-panel" id="step-5" style="display:none">
|
<div class="onboarding-panel" id="step-5" style="display:none">
|
||||||
<div class="onboarding-step-header">
|
|
||||||
<span class="onboarding-step-icon">⚙️</span>
|
|
||||||
<h2 class="onboarding-step-title">Feature Manager</h2>
|
|
||||||
<p class="onboarding-step-desc">
|
|
||||||
Enable or disable optional features. Toggling a feature will start
|
|
||||||
a system rebuild in the background.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div class="onboarding-card onboarding-card--scroll" id="step-5-body">
|
|
||||||
<p class="onboarding-loading">Loading features…</p>
|
|
||||||
</div>
|
|
||||||
<div id="step-5-rebuild-status" class="onboarding-save-status"></div>
|
|
||||||
<div class="onboarding-footer">
|
|
||||||
<button class="btn btn-close-modal onboarding-btn-back" data-prev="4">← Back</button>
|
|
||||||
<button class="btn btn-primary onboarding-btn-next" id="step-5-next">
|
|
||||||
Continue →
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ── Step 6: Complete ── -->
|
|
||||||
<div class="onboarding-panel" id="step-6" style="display:none">
|
|
||||||
<div class="onboarding-hero">
|
<div class="onboarding-hero">
|
||||||
<div class="onboarding-logo">✅</div>
|
<div class="onboarding-logo">✅</div>
|
||||||
<h1 class="onboarding-title">Your Sovran_SystemsOS is Ready!</h1>
|
<h1 class="onboarding-title">Your Sovran_SystemsOS is Ready!</h1>
|
||||||
@@ -169,12 +145,11 @@
|
|||||||
<li>✅ Domain configuration saved</li>
|
<li>✅ Domain configuration saved</li>
|
||||||
<li>✅ Port forwarding reviewed</li>
|
<li>✅ Port forwarding reviewed</li>
|
||||||
<li>✅ Credentials noted</li>
|
<li>✅ Credentials noted</li>
|
||||||
<li>✅ Features configured</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="onboarding-footer">
|
<div class="onboarding-footer">
|
||||||
<button class="btn btn-close-modal onboarding-btn-back" data-prev="5">← Back</button>
|
<button class="btn btn-close-modal onboarding-btn-back" data-prev="4">← Back</button>
|
||||||
<button class="btn btn-primary" id="step-6-finish">
|
<button class="btn btn-primary" id="step-5-finish">
|
||||||
Go to Dashboard →
|
Go to Dashboard →
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -183,21 +158,6 @@
|
|||||||
</div><!-- /panel-wrap -->
|
</div><!-- /panel-wrap -->
|
||||||
</div><!-- /shell -->
|
</div><!-- /shell -->
|
||||||
|
|
||||||
<!-- Rebuild progress modal (reused from main app) -->
|
|
||||||
<div class="modal-overlay" id="ob-rebuild-modal" role="dialog" aria-modal="true" aria-labelledby="ob-rebuild-title">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-header">
|
|
||||||
<span class="modal-title" id="ob-rebuild-title">Rebuilding System…</span>
|
|
||||||
<div class="modal-spinner" id="ob-rebuild-spinner"></div>
|
|
||||||
<span class="modal-status" id="ob-rebuild-status">Please wait</span>
|
|
||||||
</div>
|
|
||||||
<div class="modal-log" id="ob-rebuild-log" aria-live="polite"></div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button class="btn btn-close-modal" id="ob-rebuild-close" disabled>Close</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="/static/onboarding.js?v={{ onboarding_js_hash }}"></script>
|
<script src="/static/onboarding.js?v={{ onboarding_js_hash }}"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user