Pithos: renames and vault unlocks reach every open view

A renamed user kept its old name in the full page and in the other open
views until they were reloaded, and the pithos.sia address still named
the old user. The server now tells every view, and each one updates its
selection, its address and the page on screen.

When the vault locked while pithos.sia was open, the page fell through
to the console password sign-in, which a Theseus user has no use for.
It now shows the vault's PIN unlock, and it opens again on its own
once the vault is unlocked anywhere, the sidebar's PIN pad included.
The sidebar likewise opens again when the vault is unlocked elsewhere.
This commit is contained in:
Local Dev 2026-10-07 21:45:12 +02:00
parent 24e90e16ce
commit 527bfee4d4
2 changed files with 67 additions and 4 deletions

View file

@ -320,6 +320,9 @@ export async function createPithos(opts = {}) {
if (wasRunning) { try { daemon.start(); } catch (e) { daemon.pushLog('sys', `could not start s3d: ${e.message}`); } }
}
daemon.pushLog('sys', `renamed user ${p.name} to ${name}`);
// every open view (sidebar, full page, browser) follows the new name
siteUsersCache = { at: 0, set: new Set() };
broadcast('user-renamed', { from: p.name, to: name });
return { name };
});
route('GET', '/api/keys', (req, url) => cli.listKeys(url.searchParams.get('user') || undefined));

View file

@ -175,6 +175,7 @@ const eventHandlers = {
if (['done', 'already'].includes(d?.state) && d.state !== was) refreshNavAccount(true);
},
install(p) { if (p.phase === 'extract') toast('Verified checksum, installing…'); },
'user-renamed'(d) { followRename(d); },
move(p) { progressSink?.(p); },
convert(p) { progressSink?.(p); },
};
@ -274,6 +275,29 @@ function navTo(hash) {
route();
}
// A user renamed here or in another Pithos view (sidebar, full page,
// browser): the selection, the address and the page on screen follow.
function followRename({ from, to } = {}) {
if (!from || !to || from === to) return;
if (state.selectedUser === from) { state.selectedUser = to; try { localStorage.setItem('pithos.user', to); } catch {} }
const swap = (parts, i) => {
let cur = '';
try { cur = decodeURIComponent(parts[i] || ''); } catch {}
if (cur !== from) return false;
parts[i] = encodeURIComponent(to);
return true;
};
if (PATH_MODE) {
const segs = location.pathname.split('/');
if (swap(segs, 1)) history.replaceState(null, '', segs.join('/') + location.search);
} else if (location.hash.startsWith('#/u/')) {
const parts = location.hash.split('/');
if (swap(parts, 2)) history.replaceState(null, '', parts.join('/'));
}
const [page] = currentRoute();
if (page === 'users' || page === 'buckets') route();
}
function route() {
cleanup.forEach((fn) => fn());
cleanup = [];
@ -1101,10 +1125,8 @@ function users(main) {
if (!name || name === current) return;
try {
await api('POST', `/api/users/${encodeURIComponent(current)}/rename`, { name });
if (state.selectedUser === current) { state.selectedUser = name; try { localStorage.setItem('pithos.user', name); } catch {} }
expanded.delete(current);
toast(`Renamed to ${name}`);
load();
followRename({ from: current, to: name });
} catch (e) { fail(e); load(); }
}
@ -2735,6 +2757,10 @@ function watchVaultLock() {
if (st.setup && st.prompt && !st.unlocked && $('#locked').hidden) {
$('#app').hidden = true;
$('#locked').hidden = false;
} else if (st.unlocked && !$('#locked').hidden) {
// unlocked somewhere else (the full page, Settings): open again
$('#locked').hidden = true;
$('#app').hidden = false;
}
});
}
@ -2902,14 +2928,48 @@ function addBackToSidebar() {
}
function showSignin() {
// pithos.sia in Theseus signs out when the vault locks (idle, Lock now):
// that is the vault's PIN prompt, not the console password.
if (PATH_MODE) {
api('GET', '/api/session').then((s) => (s.locked ? showLocked() : showPassword())).catch(showPassword);
return;
}
showPassword();
}
function showPassword() {
$('#app').hidden = true;
$('#locked').hidden = true;
$('#signin').hidden = false;
}
// Locked with the Theseus vault. Unlocking anywhere (this page's button, the
// sidebar's PIN pad, Settings) reopens the page by itself.
let lockWatch = null;
function showLocked() {
$('#app').hidden = true;
$('#signin').hidden = true;
$('#locked').hidden = false;
if (lockWatch) return;
const check = async () => {
let s;
try { s = await api('GET', '/api/session'); } catch { return; }
if (s.locked || !s.authenticated) return;
clearInterval(lockWatch);
lockWatch = null;
document.removeEventListener('visibilitychange', onShow);
window.removeEventListener('focus', check);
location.reload(); // a fresh start: the event stream ended with the lock
};
const onShow = () => { if (!document.hidden) check(); };
lockWatch = setInterval(check, 2000);
document.addEventListener('visibilitychange', onShow);
window.addEventListener('focus', check);
}
async function boot() {
const s = await api('GET', '/api/session');
// pithos.sia in Theseus: locked with the vault, like the sidebar panel.
if (s.locked) { $('#locked').hidden = false; return; }
if (s.locked) { showLocked(); return; }
if (!s.authenticated) {
showSignin();
if (!s.passwordLogin) {