Skip to content

Commit 816ddb2

Browse files
perf(admin): P2P settings popup opens instantly (render before fetch)
The drawer was async and awaited GET /api/settings BEFORE building any DOM, so the popup only appeared after a full round-trip — and during an active audit the single Node event loop is busy, so even that trivial GET lagged, making the popup feel slow. Now the shell renders and appends synchronously (instant open) with the coded fallbacks as placeholders and inputs disabled + a "Loading current settings…" message. The fetch runs after the popup is on screen; on resolve it populates the real values (incl. the env-driven gigabytes default hint + batch-size echo) and enables the inputs. On fetch failure the operator can still work from defaults. s/d are `let` so the reset/save closures observe the loaded values.
1 parent 4c0cc94 commit 816ddb2

1 file changed

Lines changed: 43 additions & 15 deletions

File tree

admin.html

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2410,13 +2410,15 @@ <h1 style="margin:0;flex:0 0 auto">SENTINEL NODE TEST</h1>
24102410
const existing = document.getElementById('p2pSettingsBackdrop');
24112411
if (existing) { if (existing._onEsc) document.removeEventListener('keydown', existing._onEsc); existing.remove(); }
24122412

2413-
let payload = { settings: {}, defaults: {} };
2414-
try {
2415-
const res = await fetch('/api/settings');
2416-
if (res.ok) payload = await res.json();
2417-
} catch {}
2418-
const s = payload.settings || {};
2419-
const d = payload.defaults || {};
2413+
// Build + show the popup SYNCHRONOUSLY so it appears the instant the user
2414+
// clicks — do NOT await the network first (during an active audit the Node
2415+
// event loop is busy and even a trivial /api/settings GET can lag, which is
2416+
// what made this popup feel slow). s/d start empty (template renders the
2417+
// coded fallbacks as placeholders); real values populate once the fetch
2418+
// resolves, via the load block at the bottom. s/d are `let` so the
2419+
// reset/save closures below see the loaded values.
2420+
let s = {};
2421+
let d = {};
24202422

24212423
const backdrop = document.createElement('div');
24222424
backdrop.id = 'p2pSettingsBackdrop';
@@ -2446,37 +2448,37 @@ <h1 style="margin:0;flex:0 0 auto">SENTINEL NODE TEST</h1>
24462448
24472449
<label style="display:flex;flex-direction:column;gap:4px">
24482450
<span style="font-weight:700;letter-spacing:0.4px">Gigabytes per node
2449-
<span style="color:var(--text-muted);font-weight:400">(deposit size; 1–100, default ${_esc(d.gigabytes ?? 1)})</span></span>
2450-
<input id="setGigs" type="number" min="1" max="100" step="1" value="${_esc(s.gigabytes ?? 1)}"
2451+
<span style="color:var(--text-muted);font-weight:400">(deposit size; 1–100, default <span id="p2pDefGigs">${_esc(d.gigabytes ?? 1)}</span>)</span></span>
2452+
<input id="setGigs" type="number" min="1" max="100" step="1" value="${_esc(s.gigabytes ?? 1)}" disabled
24512453
style="background:var(--bg-input);border:1px solid var(--border);color:var(--text);border-radius:6px;padding:6px 10px;font:inherit;font-size:12px"/>
24522454
</label>
24532455
24542456
<label style="display:flex;flex-direction:column;gap:4px">
24552457
<span style="font-weight:700;letter-spacing:0.4px">Batch size
24562458
<span style="color:var(--text-muted);font-weight:400">(messages per TX; 1–5, default ${_esc(d.batchSize ?? 5)})</span></span>
2457-
<input id="setBatch" type="number" min="1" max="5" step="1" value="${_esc(s.batchSize ?? 5)}"
2459+
<input id="setBatch" type="number" min="1" max="5" step="1" value="${_esc(s.batchSize ?? 5)}" disabled
24582460
style="background:var(--bg-input);border:1px solid var(--border);color:var(--text);border-radius:6px;padding:6px 10px;font:inherit;font-size:12px"/>
24592461
</label>
24602462
24612463
<label style="display:flex;flex-direction:column;gap:4px">
24622464
<span style="font-weight:700;letter-spacing:0.4px">Max price (udvpn / GB)
24632465
<span style="color:var(--text-muted);font-weight:400">(0 = no cap)</span></span>
2464-
<input id="setMaxPrice" type="number" min="0" max="1000000000" step="1" value="${_esc(s.maxPriceUdvpn ?? 0)}"
2466+
<input id="setMaxPrice" type="number" min="0" max="1000000000" step="1" value="${_esc(s.maxPriceUdvpn ?? 0)}" disabled
24652467
style="background:var(--bg-input);border:1px solid var(--border);color:var(--text);border-radius:6px;padding:6px 10px;font:inherit;font-size:12px"/>
24662468
<span style="color:var(--text-muted);font-weight:400;font-size:11px">Skips any node priced above this. Real cheapest mainnet node is ≈ 4,000,000 udvpn/GB.</span>
24672469
</label>
24682470
24692471
<label style="display:flex;align-items:flex-start;gap:8px;padding:10px;border:1px solid var(--border);border-radius:6px;cursor:pointer">
2470-
<input id="setAutoCancel" type="checkbox" ${s.autoCancelAfterTest ? 'checked' : ''} style="accent-color:var(--accent);margin-top:2px;cursor:pointer"/>
2472+
<input id="setAutoCancel" type="checkbox" ${s.autoCancelAfterTest ? 'checked' : ''} disabled style="accent-color:var(--accent);margin-top:2px;cursor:pointer"/>
24712473
<span style="display:flex;flex-direction:column;gap:3px">
24722474
<span style="font-weight:700;letter-spacing:0.4px">Auto-cancel sessions after each batch</span>
2473-
<span style="color:var(--text-muted);font-weight:400;font-size:11px">After a batch finishes testing, broadcast a single TX with up to ${_esc(s.batchSize ?? 5)} <code style="color:var(--accent)">MsgCancelSession</code> messages so the chain settles each session and refunds any unused balance to this wallet. Verified live (Apr 2026 mainnet): the cancel TX emits only <code style="color:var(--accent)">EventUpdateStatus</code>; the chain sets <code style="color:var(--accent)">inactive_at = status_at + 2h</code>, refund is credited at that block. If the node never reported usage, 100% of the deposit is refundable.</span>
2475+
<span style="color:var(--text-muted);font-weight:400;font-size:11px">After a batch finishes testing, broadcast a single TX with up to <span id="p2pBatchEcho">${_esc(s.batchSize ?? 5)}</span> <code style="color:var(--accent)">MsgCancelSession</code> messages so the chain settles each session and refunds any unused balance to this wallet. Verified live (Apr 2026 mainnet): the cancel TX emits only <code style="color:var(--accent)">EventUpdateStatus</code>; the chain sets <code style="color:var(--accent)">inactive_at = status_at + 2h</code>, refund is credited at that block. If the node never reported usage, 100% of the deposit is refundable.</span>
24742476
</span>
24752477
</label>
24762478
24772479
<div style="display:flex;gap:8px;justify-content:flex-end;margin-top:6px">
2478-
<button id="p2pSettingsReset" type="button" style="background:transparent;color:var(--text-dim);border:1px solid var(--border);border-radius:6px;padding:6px 12px;font:inherit;font-size:11px;font-weight:700;letter-spacing:0.5px;cursor:pointer">RESET DEFAULTS</button>
2479-
<button id="p2pSettingsSave" type="button" style="background:var(--accent);color:var(--bg-card-solid);border:0;border-radius:6px;padding:6px 14px;font:inherit;font-size:11px;font-weight:700;letter-spacing:0.5px;cursor:pointer">SAVE</button>
2480+
<button id="p2pSettingsReset" type="button" disabled style="background:transparent;color:var(--text-dim);border:1px solid var(--border);border-radius:6px;padding:6px 12px;font:inherit;font-size:11px;font-weight:700;letter-spacing:0.5px;cursor:pointer">RESET DEFAULTS</button>
2481+
<button id="p2pSettingsSave" type="button" disabled style="background:var(--accent);color:var(--bg-card-solid);border:0;border-radius:6px;padding:6px 14px;font:inherit;font-size:11px;font-weight:700;letter-spacing:0.5px;cursor:pointer">SAVE</button>
24802482
</div>
24812483
24822484
<div id="p2pSettingsMsg" style="font-size:11px;color:var(--text-muted);min-height:14px"></div>
@@ -2525,6 +2527,32 @@ <h1 style="margin:0;flex:0 0 auto">SENTINEL NODE TEST</h1>
25252527
setMsg('Save failed: ' + (err && err.message ? err.message : err), true);
25262528
}
25272529
});
2530+
2531+
// Load current settings AFTER the popup is on screen, then populate the
2532+
// (disabled) inputs and enable them. Keeps the open instantaneous.
2533+
const _inputs = ['#setGigs', '#setBatch', '#setMaxPrice', '#setAutoCancel'].map(sel => panel.querySelector(sel));
2534+
const _btns = ['#p2pSettingsReset', '#p2pSettingsSave'].map(sel => panel.querySelector(sel));
2535+
const _setEnabled = (on) => { [..._inputs, ..._btns].forEach(el => { if (el) el.disabled = !on; }); };
2536+
setMsg('Loading current settings…', false);
2537+
try {
2538+
const res = await fetch('/api/settings');
2539+
if (!res.ok) throw new Error('HTTP ' + res.status);
2540+
const payload = await res.json();
2541+
s = payload.settings || {};
2542+
d = payload.defaults || {};
2543+
panel.querySelector('#setGigs').value = s.gigabytes ?? d.gigabytes ?? 1;
2544+
panel.querySelector('#setBatch').value = s.batchSize ?? d.batchSize ?? 5;
2545+
panel.querySelector('#setMaxPrice').value = s.maxPriceUdvpn ?? d.maxPriceUdvpn ?? 0;
2546+
panel.querySelector('#setAutoCancel').checked = !!s.autoCancelAfterTest;
2547+
panel.querySelector('#p2pDefGigs').textContent = _esc(d.gigabytes ?? 1);
2548+
panel.querySelector('#p2pBatchEcho').textContent = _esc(s.batchSize ?? 5);
2549+
_setEnabled(true);
2550+
setMsg('', false);
2551+
} catch (err) {
2552+
// Couldn't load — still let the operator work from the placeholder defaults.
2553+
_setEnabled(true);
2554+
setMsg('Could not load saved settings; showing defaults.', true);
2555+
}
25282556
}
25292557

25302558
async function openOnchainPopup() {

0 commit comments

Comments
 (0)