From 6fd6587714d999e8053c95a18361d48e4ad9b74b Mon Sep 17 00:00:00 2001 From: librelad Date: Wed, 26 Aug 2026 06:39:25 +0100 Subject: [PATCH] feat(setup): selections above, drives below, and both roots choosable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reworks the Storage step: two labelled choices with tooltips at the top — LibrePortal and New apps — and the drive list underneath as reference. The drive cards lose their checkboxes. Choosing a drive in a dropdown IS the request to register it, so a separate tick was a second way to say the same thing, and the way you end up with a drive ticked that nobody selected. Cards are now informational plus Details. Both dropdowns only render when there is a second drive; with one disk both answers are forced and a pair of selects showing one option each is furniture. Moving LibrePortal's own tree cannot be a WebUI action. It re-bakes the six root-owned helpers, the systemd unit and the WebUI's own bind-mounts — real root, not the scoped sudo the manager holds. A helper that re-baked the other helpers from a manager-supplied path would hand the manager exactly the trust boundary those helpers exist to defend. So picking a different disk for LibrePortal surfaces the root command to run rather than pretending the wizard can do it; the payload carries the choice so the finish screen can repeat it. libreportal-relocate follows. Also drops "itself" from the installer's wording. Co-Authored-By: Claude Opus 5 --- .../frontend/core/setup/css/setup-wizard.css | 29 +++ .../frontend/core/setup/js/setup-wizard.js | 165 ++++++++++-------- docs/guide/install-and-use.md | 2 +- init.sh | 2 +- 4 files changed, 125 insertions(+), 73 deletions(-) diff --git a/containers/libreportal/frontend/core/setup/css/setup-wizard.css b/containers/libreportal/frontend/core/setup/css/setup-wizard.css index 3c82c30..447d8b8 100755 --- a/containers/libreportal/frontend/core/setup/css/setup-wizard.css +++ b/containers/libreportal/frontend/core/setup/css/setup-wizard.css @@ -1391,3 +1391,32 @@ body.setup-wizard-open .eo-modal { z-index: 10000; } other dropdowns rather than showing stock white chrome. */ .setup-storage-default select, .setup-storage-default .custom-select { flex: 1; min-width: 180px; } + +/* Two choices above the drive list. The list below is reference, not input. */ +.setup-storage-choice { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 10px; +} +.setup-storage-choice-label { + flex: 0 0 120px; + font-size: 0.92em; + opacity: 0.92; +} +.setup-storage-choice select, +.setup-storage-choice .custom-select { flex: 1; min-width: 180px; } +.setup-storage-choice-msg { + margin: 2px 0 4px; + padding: 9px 11px; + border-radius: 8px; + border: 1px solid rgba(255, 190, 60, 0.32); + background: rgba(255, 190, 60, 0.09); + font-size: 0.86em; + line-height: 1.5; +} +.setup-storage-choice-msg code { + display: inline-block; + margin-top: 4px; + word-break: break-all; +} diff --git a/containers/libreportal/frontend/core/setup/js/setup-wizard.js b/containers/libreportal/frontend/core/setup/js/setup-wizard.js index bbc84af..4c72abc 100755 --- a/containers/libreportal/frontend/core/setup/js/setup-wizard.js +++ b/containers/libreportal/frontend/core/setup/js/setup-wizard.js @@ -34,6 +34,8 @@ class SetupWizard { this.fstabWanted = []; // Which drive new apps default to: 'primary' or a ticked drive's path. this.storageDefault = 'primary'; + // Where LibrePortal's own tree should live (root-only to change post-install). + this.storageSystemChoice = 'primary'; this.installLevel = 'beginner'; this.totalSteps = this._effectiveTotalSteps(); this.domainCount = 0; // tracked dynamically as the user adds rows @@ -238,8 +240,9 @@ class SetupWizard {
Storage ?
+
+
-

@@ -476,39 +479,27 @@ class SetupWizard { title="${used}% used, ${100 - used}% free">`; } - // One card, one line. + // One card, one line — informational. + // + // No checkbox: the dropdowns above ARE the selection, and a drive picked + // there is registered automatically. Two ways to say the same thing (tick it + // AND choose it) is how you end up with a ticked drive nobody selected. // // The badge carries severity and Details carries the explanation, so the card - // itself stays a single row — listing every warning here pushed each drive to - // three lines and made the step tall for no gain. - // - // `locked` renders it ticked and non-interactive: the system drive is what - // apps fall back to, so it cannot be deselected. Details still works, which - // is the point of showing it at all on a single-disk box. + // stays a single row. _storageCard(c, key, opts) { const o = opts || {}; const refused = c.verdict === 'refuse'; - const badge = o.locked - ? 'default' + const badge = o.system + ? 'system' : (refused ? 'can\u2019t be used' : (c.verdict === 'warn' ? 'needs care' : '')); - const title = o.locked ? 'System disk' : c.path; - - // The system disk carries NO checkbox — not even a disabled one. Apps fall - // back to it whatever happens, so it is not a choice, and a control that - // can never change state reads as "locked option" rather than "this is - // simply where things go". It is a
for the same reason: a