diff --git a/Plugin/unraid/pages/setup.php b/Plugin/unraid/pages/setup.php index 9c8662f..4b689fa 100644 --- a/Plugin/unraid/pages/setup.php +++ b/Plugin/unraid/pages/setup.php @@ -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 = ; +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;