feat(settings): keep backup pwd on disable, dedicated pwd button, tab icons
Auto-backup no longer wipes the stored password when disabled, so re-enabling reuses it silently. A dedicated "Set/Change backup password" button (mirrors sync) owns the password, with a warning status when unset. Corrected the stale hint that claimed the backup pwd was derived from the master password. Added icons to each settings tab. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2198,10 +2198,12 @@ body[data-editor-position="center"]:has(#settingsPanel.is-open)::before {
|
|||||||
flex: 0 0 auto; border-right: 1px solid var(--border); overflow-y: auto;
|
flex: 0 0 auto; border-right: 1px solid var(--border); overflow-y: auto;
|
||||||
}
|
}
|
||||||
.settings-tab {
|
.settings-tab {
|
||||||
|
display: flex; align-items: center; gap: 8px;
|
||||||
text-align: left; width: 100%; padding: 7px 12px; font-size: 12px; cursor: pointer;
|
text-align: left; width: 100%; padding: 7px 12px; font-size: 12px; cursor: pointer;
|
||||||
color: var(--text-dim); background: transparent; border: 1px solid transparent;
|
color: var(--text-dim); background: transparent; border: 1px solid transparent;
|
||||||
border-radius: 6px; white-space: nowrap;
|
border-radius: 6px; white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
.settings-tab svg { width: 15px; height: 15px; flex: 0 0 auto; }
|
||||||
.settings-tab:hover { background: var(--bg-elev-2); }
|
.settings-tab:hover { background: var(--bg-elev-2); }
|
||||||
.settings-tab.is-active { color: var(--accent-fg); background: var(--accent); border-color: var(--accent); }
|
.settings-tab.is-active { color: var(--accent-fg); background: var(--accent); border-color: var(--accent); }
|
||||||
.slideover-field.is-tab-hidden { display: none; }
|
.slideover-field.is-tab-hidden { display: none; }
|
||||||
|
|||||||
Binary file not shown.
+12
-8
@@ -415,11 +415,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="settings-main">
|
<div class="settings-main">
|
||||||
<div class="settings-tabs" id="settingsTabs">
|
<div class="settings-tabs" id="settingsTabs">
|
||||||
<button class="settings-tab is-active" data-tab="general">General</button>
|
<button class="settings-tab is-active" data-tab="general"><svg><use href="#i-settings"/></svg>General</button>
|
||||||
<button class="settings-tab" data-tab="security">Security</button>
|
<button class="settings-tab" data-tab="security"><svg><use href="#i-shield"/></svg>Security</button>
|
||||||
<button class="settings-tab" data-tab="autofill">Autofill</button>
|
<button class="settings-tab" data-tab="autofill"><svg><use href="#i-key"/></svg>Autofill</button>
|
||||||
<button class="settings-tab" data-tab="account">Account</button>
|
<button class="settings-tab" data-tab="account"><svg><use href="#i-user"/></svg>Account</button>
|
||||||
<button class="settings-tab" data-tab="sync">Sync & Backup</button>
|
<button class="settings-tab" data-tab="sync"><svg><use href="#i-rotate-ccw"/></svg>Sync & Backup</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="slideover-body" id="settingsBody">
|
<div class="slideover-body" id="settingsBody">
|
||||||
<div class="slideover-field">
|
<div class="slideover-field">
|
||||||
@@ -769,10 +769,14 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<p style="font-size:11px;color:var(--text-faint);margin:0 0 8px;line-height:1.4">
|
<p style="font-size:11px;color:var(--text-faint);margin:0 0 8px;line-height:1.4">
|
||||||
Backups are encrypted with a password derived from your
|
Backups are encrypted with a password you choose
|
||||||
master password (so restore needs the master at the
|
(independent of your master password — you'll need it
|
||||||
time of backup). Filename pattern: <code>vault-autobackup-YYYYMMDD-HHmmss.json</code>.
|
to restore). Filename pattern: <code>vault-autobackup-YYYYMMDD-HHmmss.json</code>.
|
||||||
</p>
|
</p>
|
||||||
|
<div style="display:flex;gap:8px;align-items:center;margin-bottom:8px">
|
||||||
|
<button class="btn btn-ghost btn-sm" id="autoBackupSetPwdBtn">Set backup password</button>
|
||||||
|
<span id="autoBackupPwdStatus" style="font-size:11px;display:inline-flex;align-items:center;gap:4px"></span>
|
||||||
|
</div>
|
||||||
<div style="display:flex;gap:6px;flex-wrap:wrap;align-items:center">
|
<div style="display:flex;gap:6px;flex-wrap:wrap;align-items:center">
|
||||||
<button class="btn btn-ghost btn-sm" id="autoBackupNowBtn">
|
<button class="btn btn-ghost btn-sm" id="autoBackupNowBtn">
|
||||||
<svg><use href="#i-log-out"/></svg> Backup now
|
<svg><use href="#i-log-out"/></svg> Backup now
|
||||||
|
|||||||
+29
-12
@@ -59,6 +59,18 @@ function refreshAutoBackupUI(cfg) {
|
|||||||
$('#autoBackupLast').textContent = cfg.last
|
$('#autoBackupLast').textContent = cfg.last
|
||||||
? 'Last run: ' + cfg.last.replace('T', ' ').slice(0, 16)
|
? 'Last run: ' + cfg.last.replace('T', ' ').slice(0, 16)
|
||||||
: 'Never run yet';
|
: 'Never run yet';
|
||||||
|
$('#autoBackupSetPwdBtn').textContent = cfg.hasPwd
|
||||||
|
? 'Change backup password' : 'Set backup password';
|
||||||
|
const pwdStatus = $('#autoBackupPwdStatus');
|
||||||
|
if (cfg.hasPwd) {
|
||||||
|
pwdStatus.innerHTML = '';
|
||||||
|
pwdStatus.style.color = 'var(--text-faint)';
|
||||||
|
pwdStatus.textContent = 'Set.';
|
||||||
|
} else {
|
||||||
|
pwdStatus.style.color = 'var(--warning, #e0a800)';
|
||||||
|
pwdStatus.innerHTML = '<svg width="13" height="13"><use href="#i-alert"/></svg>' +
|
||||||
|
'<span>Not set — backups won\'t run</span>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function pickAutoBackupFolder() {
|
async function pickAutoBackupFolder() {
|
||||||
@@ -100,27 +112,32 @@ async function promptAndStoreBackupPwd() {
|
|||||||
async function onToggleAutoBackup(ev) {
|
async function onToggleAutoBackup(ev) {
|
||||||
const enabled = ev.target.checked;
|
const enabled = ev.target.checked;
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
const cfg = await loadAutoBackupConfig();
|
|
||||||
if (!cfg.hasPwd && !(await promptAndStoreBackupPwd())) {
|
|
||||||
ev.target.checked = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Bridge.setPref(ABK.enabled, '1');
|
Bridge.setPref(ABK.enabled, '1');
|
||||||
$('#autoBackupConfig').style.display = '';
|
$('#autoBackupConfig').style.display = '';
|
||||||
toast('Auto-backup enabled');
|
// No pwd prompt here — the dedicated "Set backup password" button
|
||||||
// Refresh the dir/last display in case we came from cold state.
|
// owns it (like sync). Backups no-op until it's set.
|
||||||
const fresh = await loadAutoBackupConfig();
|
const cfg = await loadAutoBackupConfig();
|
||||||
refreshAutoBackupUI(fresh);
|
refreshAutoBackupUI(cfg);
|
||||||
|
toast(cfg.hasPwd ? 'Auto-backup enabled'
|
||||||
|
: 'Auto-backup enabled — set a backup password to start');
|
||||||
} else {
|
} else {
|
||||||
Bridge.setPref(ABK.enabled, '');
|
Bridge.setPref(ABK.enabled, '');
|
||||||
// Forget the stored backup pwd so re-enabling prompts fresh —
|
// Keep the stored pwd — re-enabling reuses it silently. Change it
|
||||||
// gives the user a way to change it without extra UI.
|
// anytime via the dedicated "Change backup password" button.
|
||||||
Bridge.setPref(ABK.pwd, '');
|
|
||||||
$('#autoBackupConfig').style.display = 'none';
|
$('#autoBackupConfig').style.display = 'none';
|
||||||
toast('Auto-backup disabled');
|
toast('Auto-backup disabled');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dedicated pwd button (mirrors sync's syncSetEncPwdFlow) so the user can
|
||||||
|
// change the backup password without the disable/re-enable dance.
|
||||||
|
async function changeBackupPwd() {
|
||||||
|
if (await promptAndStoreBackupPwd()) {
|
||||||
|
refreshAutoBackupUI(await loadAutoBackupConfig());
|
||||||
|
toast('Backup password saved');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function runAutoBackupNow(silent) {
|
async function runAutoBackupNow(silent) {
|
||||||
const cfg = await loadAutoBackupConfig();
|
const cfg = await loadAutoBackupConfig();
|
||||||
if (!cfg) return silent || toast('Bridge not available', 'error');
|
if (!cfg) return silent || toast('Bridge not available', 'error');
|
||||||
|
|||||||
@@ -8994,6 +8994,7 @@ async function init() {
|
|||||||
e.target.value = n;
|
e.target.value = n;
|
||||||
Bridge.setPref(ABK.keep, String(n));
|
Bridge.setPref(ABK.keep, String(n));
|
||||||
});
|
});
|
||||||
|
$('#autoBackupSetPwdBtn').addEventListener('click', changeBackupPwd);
|
||||||
$('#autoBackupNowBtn').addEventListener('click', () => runAutoBackupNow());
|
$('#autoBackupNowBtn').addEventListener('click', () => runAutoBackupNow());
|
||||||
|
|
||||||
$('#settingFavicons').addEventListener('change', e => {
|
$('#settingFavicons').addEventListener('change', e => {
|
||||||
|
|||||||
Reference in New Issue
Block a user