Backup step: Read sits beside the password, like Check beside the folder

"Read this backup" was a button floating below the form, which reads as a step
of its own rather than as the action for the field above it. It is now inline
in the password row, styled exactly like the folder's Check — each field
carries its own action on the right.

Shortened to "Read" so it fits the row without resizing it mid-request, and the
status line moved inside that field for the same reason: it is an answer about
the password, not about the step.

The gate message names the button it is pointing at, so renaming one meant
renaming the other. That is the kind of drift nothing catches — the message is
only reachable by trying to advance without reading first.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
librelad 2026-08-29 08:08:47 +01:00
parent f77915de3b
commit aff9b398da
2 changed files with 16 additions and 8 deletions

View File

@ -457,15 +457,12 @@ class SetupWizard {
</label>
<div class="setup-input-row">
<span class="setup-field-icon setup-field-icon-emoji" aria-hidden="true">\u{1F512}</span>
<input type="password" id="sw-rs-pass" class="setup-input-with-icon" placeholder="Unlocks the repository" autocomplete="off">
</div>
</div>
<div class="setup-field">
<button type="button" class="setup-domain-add" id="sw-rs-read">Read this backup</button>
<input type="password" id="sw-rs-pass" class="setup-input-with-icon" placeholder="Unlocks this backup" autocomplete="off">
<button type="button" class="setup-storage-details" id="sw-rs-read">Read</button>
</div>
<div id="sw-rs-status"></div>
</div>
</div>
</section>
<!-- What is in there -->
@ -1508,7 +1505,7 @@ class SetupWizard {
status.innerHTML = `<p class="setup-rs-error">${this.escapeHtml(e.message || String(e))}</p>`;
}
} finally {
if (btn) { btn.disabled = false; btn.textContent = 'Read this backup'; }
if (btn) { btn.disabled = false; btn.textContent = 'Read'; }
}
}
@ -2377,7 +2374,7 @@ class SetupWizard {
const problem = this._restoreSourceProblem();
if (problem) return problem;
if (!this.restoreInfo) {
return 'Select "Read this backup" first \u2014 we have to open it before we can show you what is inside.';
return 'Select \u201cRead\u201d beside the password first \u2014 we have to open the backup before we can show you what is inside.';
}
}

View File

@ -198,6 +198,14 @@ read -r -d '' DRIVE <<'JS'
// one, and kept telling them after they had.
const BACKUP = w.stepNames.indexOf('Backup');
out.passwordLabel = ($('label[for="sw-rs-pass"]') || {}).textContent?.trim().split('\n')[0].trim();
// The action sits beside the field it acts on, the same way Check does for
// the folder. A button floating below the form reads as a step of its own.
const readBtn = $('#sw-rs-read');
const readRow = readBtn && readBtn.closest('.setup-input-row');
out.readSitsInThePasswordRow = !!(readRow && readRow.querySelector('#sw-rs-pass'));
out.readMatchesCheckStyling = !!(readBtn && $('#sw-rs-verify')
&& readBtn.className === $('#sw-rs-verify').className);
out.readIsShortEnoughToSitInline = !!readBtn && readBtn.textContent.trim().length <= 8;
out.verdictHasNoInstruction =
!/enter its password/i.test(($('#sw-rs-verify-result') || {}).textContent || '');
@ -360,6 +368,9 @@ chk "and the real path is offered" "$(g .offersTheRealPath)" true
echo "the step gates rather than instructs"
chk "the field is called Backup Password" "$(g .passwordLabel)" "Backup Password"
chk "Read sits beside the password" "$(g .readSitsInThePasswordRow)" true
chk "styled like the folder's Check" "$(g .readMatchesCheckStyling)" true
chk "and short enough to sit inline" "$(g .readIsShortEnoughToSitInline)" true
chk "no 'enter its password' copy" "$(g .verdictHasNoInstruction)" true
chk "blocked without a password" "$(g .blockedWithoutPassword)" true
chk "blocked until the backup is read" "$(g .blockedUntilRead)" true