Make the onboard-in-progress state survive a page reload

It was a browser flag set on click, and refreshing is the first thing anyone does when a page looks stuck — which put them back on the phase-1 panel the state exists to replace.
This commit is contained in:
Gmer4Lfe
2026-08-17 13:06:45 -04:00
parent e23358ea0c
commit 1badb93331
+40 -5
View File
@@ -84,6 +84,31 @@ if ($vvDetected['slot'] !== '') {
: ((!empty($vvSt[$vvSlUp . '_PHASE1_DONE']) || !empty($vvSt[$vvDetected['slot'] . '_phase1_done'])) ? 1 : 0);
}
// ── Is Phase 2 running on the owner right now? ───────────────────────────────────────────────
// Derived here rather than only tracked in the browser, so it survives a reload. The client flag
// alone was set when the operator pressed Join and lost on refresh — and refreshing is the first
// thing anyone does when a page looks stuck, which put them straight back at the phase-1 panel
// the in-progress state exists to replace.
//
// The evidence is the mirror's own job record: it finishes in about three seconds because all it
// does is notify the owner, so "this job ended recently AND our phase is still below 2" is
// precisely the window in which the owner is mid-Phase-2. Bounded at 20 minutes so an onboard
// abandoned days ago does not render as in progress for ever.
$vvPhase2Since = 0;
if ($vvDetected['role'] === 'partner' && ($vvDetected['phase'] ?? 0) < 2) {
$vvJob = '/var/log/varaverk/Partnership/partnership_onboard.json';
if (is_file($vvJob)) {
$vvJ = json_decode((string)@file_get_contents($vvJob), true);
if (is_array($vvJ)) {
$vvEnd = (int)($vvJ['end'] ?? 0);
$vvOk = ($vvJ['status'] ?? '') === 'ok';
if ($vvOk && $vvEnd > 0 && (time() - $vvEnd) < 1200) {
$vvPhase2Since = $vvEnd * 1000;
}
}
}
}
// ── Custom docker networks, adopted from the owner ───────────────────────────────────────────
// master.conf names the hosts; it does not name the networks, which live in each host's own
// host*.conf. The owner's copy is available here anyway: onboard Phase 1 caches it into
@@ -602,19 +627,29 @@ function vvRenderDone(d) {
// expiring before the flag landed and the wizard sat unchanged on a partnership that had already
// succeeded — the exact symptom this function exists to remove.
let _vvPartnerPoll = null;
let _vvPhase2Waiting = false; // Phase 2 is running on the owner right now
let _vvPhase2Since = 0; // epoch ms, for the elapsed counter
// Seeded from PHP so a reload mid-Phase-2 keeps showing the in-progress panel.
let _vvPhase2Since = <?= (int)$vvPhase2Since ?>;
let _vvPhase2Waiting = _vvPhase2Since > 0;
if (_vvPhase2Waiting) setTimeout(() => vvStartPhase2Watch(_vvPhase2Since), 0);
let _vvPhase2Tick = null; // redraws the counter between checklist polls
let _vvLastChecklist = null; // last payload, so the ticker can redraw without refetching
function vvOnJobDone(id, status) {
if (!String(id).includes('partnership_onboard')) { vvLoadChecklist(); return; }
// The mirror's job ending is the START of the wait, not the end of the work — Phase 2 begins on
// the owner at this moment.
vvStartPhase2Watch(Date.now());
}
// Two ways in: pressing Join (vvOnJobDone), or loading a page while Phase 2 is already running
// (seeded from PHP above). Both need the same watcher, and the reload path must keep the original
// start time rather than restarting the clock at zero — an elapsed counter that resets on refresh
// is worse than none, because it suggests the work restarted too.
function vvStartPhase2Watch(sinceMs) {
if (_vvPartnerPoll) clearInterval(_vvPartnerPoll);
if (_vvPhase2Tick) clearInterval(_vvPhase2Tick);
// The mirror's job ending is the START of the wait, not the end of the work — Phase 2 begins on
// the owner at this moment. Hold the in-progress panel until the checklist actually turns.
_vvPhase2Waiting = true;
_vvPhase2Since = Date.now();
_vvPhase2Since = sinceMs || Date.now();
const stop = () => {
_vvPhase2Waiting = false;