Settings: General, Connections, Security and Admin tabs (last one remembered); Reminders no longer hangs when the service worker does not start
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a3010299d0
commit
668c7241a1
4 files changed
+44
-15
No files matched your search
+35
-14
@@ -67,16 +67,13 @@ function viewSettings() {
|
||||
const isAdmin = ME && ME.role === 'admin';
|
||||
const tabNames = ME ? TABS.filter(t => ME.tabs.includes(t[0]) && !['home', 'settings'].includes(t[0])).map(t => t[1]).join(', ') : '';
|
||||
$('#view').innerHTML = `<div class="wrap"><h1>Settings</h1>
|
||||
${ME ? `<h2>Signed in as</h2><div class="list"><div class="row"><span class="grow"><b>${esc(ME.name)}</b><small style="white-space:normal">${isAdmin ? 'Admin · can use everything and manage people' : 'Can use: ' + esc(tabNames || 'Home and Settings only')}</small></span></div></div>` : ''}
|
||||
${isAdmin ? `<h2>People</h2><div class="list" id="people"><div class="row"><span class="grow"><small>Loading…</small></span></div></div>
|
||||
<div class="bar"><button class="btn" id="addperson">Add a person</button></div>
|
||||
<h2>Storage</h2><div class="list" id="stor"><div class="row"><span class="grow"><small>Checking…</small></span></div></div>
|
||||
<div class="bar"><a class="btn ghost" href="/api/backup" download>Download a backup</a></div><p class="sub">A .tar.gz of everything in /data (accounts, passkeys, tasks, events, settings, Signal history). Keep it private: it holds the session secret and encrypted sign-in tokens. Restore by unpacking it into the data volume.</p>` : ''}
|
||||
<h2>Passkeys</h2><div class="list" id="pks"><div class="row"><span class="grow"><small>Loading…</small></span></div></div>
|
||||
<div class="bar"><button class="btn ghost" id="addpk">Add a passkey</button><button class="btn ghost" id="invpk">Invite a device</button><button class="btn danger" id="hubout">Sign out of NE Hub</button></div>
|
||||
<h2>Recovery codes</h2><div class="list"><div class="row"><span class="grow"><b id="rcn">Checking…</b><small style="white-space:normal">One-time codes that let you add a new passkey if you lose every device. Keep them somewhere safe (a password manager or on paper).</small></span><button class="btn ghost" id="rcgen">Make codes</button></div></div>
|
||||
${isAdmin ? `<h2>Activity</h2><div class="list" id="audit"><div class="row"><span class="grow"><small>Loading…</small></span></div></div>` : ''}
|
||||
<div id="sec-conn"><h2>Connections</h2><div class="list">
|
||||
<div class="sgrp" id="settabs" role="tablist" aria-label="Settings sections">${[['general', 'General'], ['connections', 'Connections'], ['security', 'Security'], ...(isAdmin ? [['admin', 'Admin']] : [])].map(([k, l]) => `<a href="#" role="tab" data-g="${k}">${l}</a>`).join('')}</div>
|
||||
<div class="sgroup" data-g="general">${ME ? `<h2>Signed in as</h2><div class="list"><div class="row"><span class="grow"><b>${esc(ME.name)}</b><small style="white-space:normal">${isAdmin ? 'Admin · can use everything and manage people' : 'Can use: ' + esc(tabNames || 'Home and Settings only')}</small></span></div></div>` : ''}
|
||||
<div id="sec-signal"><h2>Signal alerts</h2><p class="sub">How this computer gets your attention when a Signal message arrives (not while you are looking at that chat). Saved on this device only.</p>
|
||||
<div class="list"><label class="row" style="cursor:pointer"><span class="grow"><b>Play a sound</b><small>A short chime</small></span><input type="checkbox" id="sga-s"></label>
|
||||
<label class="row" style="cursor:pointer"><span class="grow"><b>Desktop notification</b><small id="sga-ns">Pops up even when this tab is in the background</small></span><input type="checkbox" id="sga-n"></label></div>
|
||||
<div class="bar"><button class="btn ghost" id="sga-t">Play test sound</button></div></div>${remindersHtml()}<h2>Install</h2>${installHtml()}</div>
|
||||
<div class="sgroup" data-g="connections"><div id="sec-conn"><h2>Connections</h2><div class="list">
|
||||
<div class="row" id="row-sf"><span class="grow"><b>Seafile</b><small id="sfst">${esc(cfg.seafile)} · ${signed ? 'Checking…' : 'signed out'}</small></span></div>
|
||||
<div class="row" id="row-plex"><span class="grow"><b>Plex</b><small id="plexst">Checking…</small></span><button class="btn danger" id="plexout" hidden>Sign out</button></div>
|
||||
<div class="row" id="row-oo"><span class="grow"><b>OnlyOffice</b><small>${esc(cfg.onlyoffice)}</small></span></div>
|
||||
@@ -88,10 +85,17 @@ function viewSettings() {
|
||||
<input type="text" id="ab-u" autocomplete="off" autocapitalize="off" value="${esc(abCreds().u)}">
|
||||
<label for="ab-p">Password</label>
|
||||
<input type="password" id="ab-p" autocomplete="new-password" value="${esc(abCreds().p)}"></div>
|
||||
</div><div id="sec-signal"><h2>Signal alerts</h2><p class="sub">How this computer gets your attention when a Signal message arrives (not while you are looking at that chat). Saved on this device only.</p>
|
||||
<div class="list"><label class="row" style="cursor:pointer"><span class="grow"><b>Play a sound</b><small>A short chime</small></span><input type="checkbox" id="sga-s"></label>
|
||||
<label class="row" style="cursor:pointer"><span class="grow"><b>Desktop notification</b><small id="sga-ns">Pops up even when this tab is in the background</small></span><input type="checkbox" id="sga-n"></label></div>
|
||||
<div class="bar"><button class="btn ghost" id="sga-t">Play test sound</button></div></div>${remindersHtml()}<h2>Install</h2>${installHtml()}</div>`;
|
||||
</div></div>
|
||||
<div class="sgroup" data-g="security"><h2>Passkeys</h2><div class="list" id="pks"><div class="row"><span class="grow"><small>Loading…</small></span></div></div>
|
||||
<div class="bar"><button class="btn ghost" id="addpk">Add a passkey</button><button class="btn ghost" id="invpk">Invite a device</button><button class="btn danger" id="hubout">Sign out of NE Hub</button></div>
|
||||
<h2>Recovery codes</h2><div class="list"><div class="row"><span class="grow"><b id="rcn">Checking…</b><small style="white-space:normal">One-time codes that let you add a new passkey if you lose every device. Keep them somewhere safe (a password manager or on paper).</small></span><button class="btn ghost" id="rcgen">Make codes</button></div></div>
|
||||
</div>
|
||||
<div class="sgroup" data-g="admin">${isAdmin ? `<h2>People</h2><div class="list" id="people"><div class="row"><span class="grow"><small>Loading…</small></span></div></div>
|
||||
<div class="bar"><button class="btn" id="addperson">Add a person</button></div>
|
||||
<h2>Storage</h2><div class="list" id="stor"><div class="row"><span class="grow"><small>Checking…</small></span></div></div>
|
||||
<div class="bar"><a class="btn ghost" href="/api/backup" download>Download a backup</a></div><p class="sub">A .tar.gz of everything in /data (accounts, passkeys, tasks, events, settings, Signal history). Keep it private: it holds the session secret and encrypted sign-in tokens. Restore by unpacking it into the data volume.</p>` : ''}
|
||||
${isAdmin ? `<h2>Activity</h2><div class="list" id="audit"><div class="row"><span class="grow"><small>Loading…</small></span></div></div>` : ''}
|
||||
</div></div>`;
|
||||
remindersInit();
|
||||
installInit();
|
||||
// only show what this person may use
|
||||
@@ -99,6 +103,7 @@ function viewSettings() {
|
||||
hide(!((allowed('mail') && cfg.mail) || cfg.mailAdmin), '#sec-mail'); hide(!allowed('audio'), '#sec-audio'); hide(!allowed('signal'), '#sec-signal'); hide(!(allowed('files') || allowed('office')), '#row-sf, #out');
|
||||
hide(!allowed('music'), '#row-plex'); hide(!allowed('office'), '#row-oo');
|
||||
if (!document.querySelector('#sec-conn .list .row')) hide(true, '#sec-conn'); // nothing to show here for this person
|
||||
settingsTabs();
|
||||
if ($('#sga-s')) {
|
||||
const a = sgAlerts(), ns = $('#sga-ns'); $('#sga-s').checked = a.sound; $('#sga-n').checked = a.notify && 'Notification' in window && Notification.permission === 'granted';
|
||||
if (!('Notification' in window)) { $('#sga-n').disabled = true; ns.textContent = 'This browser does not support notifications'; }
|
||||
@@ -190,3 +195,19 @@ function installInit() {
|
||||
b.hidden = false;
|
||||
b.onclick = async () => { const ev = installEvt; installEvt = null; b.hidden = true; try { await ev.prompt(); } catch {} };
|
||||
}
|
||||
|
||||
// ---- Settings sections: one group at a time (General, Connections, Security, Admin), the last one is remembered on this device
|
||||
function settingsTabs() {
|
||||
const tabs = [...document.querySelectorAll('#settabs a')], groups = [...document.querySelectorAll('.sgroup')];
|
||||
const empty = g => !g.textContent.trim() && !g.querySelector('input, button');
|
||||
for (const g of groups) if (empty(g)) { g.remove(); const a = tabs.find(x => x.dataset.g === g.dataset.g); if (a) a.remove(); }
|
||||
const left = [...document.querySelectorAll('#settabs a')]; if (left.length < 2) { const b = $('#settabs'); if (b) b.hidden = true; }
|
||||
const show = k => {
|
||||
if (!left.some(a => a.dataset.g === k)) k = left[0] && left[0].dataset.g;
|
||||
left.forEach(a => { a.classList.toggle('on', a.dataset.g === k); a.setAttribute('aria-selected', a.dataset.g === k); });
|
||||
document.querySelectorAll('.sgroup').forEach(g => { g.hidden = g.dataset.g !== k; });
|
||||
try { store.set('settings_tab', k); } catch {}
|
||||
};
|
||||
left.forEach(a => a.onclick = e => { e.preventDefault(); show(a.dataset.g); $('#view').scrollTop = 0; });
|
||||
show(store.get('settings_tab', 'general'));
|
||||
}
|
||||
Reference in new issue
Block a user