From e23358ea0c490bd0e7c5674456939a2845af6e19 Mon Sep 17 00:00:00 2001 From: Gmer4Lfe Date: Mon, 17 Aug 2026 12:25:16 -0400 Subject: [PATCH] Tell the mirror that Phase 2 is running instead of leaving it on a greyed button MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mirror's own job ends in seconds while Phase 2 runs for minutes on the owner, so the screen sat unchanged on the phase-1 panel — which reads as a hang, and the reasonable response to a hang is to start clicking. --- Plugin/unraid/Varaverk.page | 27 +++++++++++++++++++++++++++ Plugin/unraid/pages/setup.php | 35 ++++++++++++++++++++++++++++++----- 2 files changed, 57 insertions(+), 5 deletions(-) diff --git a/Plugin/unraid/Varaverk.page b/Plugin/unraid/Varaverk.page index 7c32b22..380e5b0 100644 --- a/Plugin/unraid/Varaverk.page +++ b/Plugin/unraid/Varaverk.page @@ -332,6 +332,33 @@ function vvRenderMirrorOnboard(opts) { // Phase 2 means the partnership is actually established, so the instructions have genuinely // stopped being needed. Until then showing them costs nothing — a step already done reads as a // reminder, a step still needed and hidden is a dead end. + // Phase 2 runs on the OWNER and takes minutes — 4m05s on a measured run, longer as the arr + // library grows. The mirror's own job finishes in about three seconds, because all it does is + // send the notification, so for the rest of that window the screen showed the unchanged + // phase-1 panel with a greyed-out button and no statement that anything was happening + // elsewhere. That reads as a hang, and the reasonable response to a hang is to start clicking. + if ((opts.phase ?? 0) < 2 && opts.waiting) { + const mins = opts.waitingSince + ? Math.floor((Date.now() - opts.waitingSince) / 60000) : 0; + const secs = opts.waitingSince + ? Math.floor(((Date.now() - opts.waitingSince) % 60000) / 1000) : 0; + return `
+
+ +
+
+ Onboard in progress — please wait
+
+ ${owner} is running Phase 2: deploying containers, syncing auth data and + bootstrapping the arr libraries. This normally takes 4–6 minutes and nothing is + needed from you here. This page updates itself when it finishes.
+ ${opts.waitingSince ? `
elapsed ${mins}m ${String(secs).padStart(2,'0')}s
` : ''} +
+
+
`; + } + if ((opts.phase ?? 0) >= 2) { // Done state. This used to return the same "Join partnership · ▶ Onboard" panel as the // not-started state, under a comment saying it collapsed — so a fully onboarded mirror diff --git a/Plugin/unraid/pages/setup.php b/Plugin/unraid/pages/setup.php index 0925b8b..9c8662f 100644 --- a/Plugin/unraid/pages/setup.php +++ b/Plugin/unraid/pages/setup.php @@ -525,6 +525,8 @@ function vvRenderOnboardPanel(d) { termCmd: `bash ${dir}/Partnership/partnership_onboard.sh --phase1-only`, phase: vvDetectedIdentity.phase ?? 0, hasPartner: true, + waiting: _vvPhase2Waiting, + waitingSince: _vvPhase2Since, }); }); } @@ -599,23 +601,45 @@ function vvRenderDone(d) { // bootstrap in Step 9 pushed a real run to 4m05s and it grows with library size, so the poll was // 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 _vvPartnerPoll = null; +let _vvPhase2Waiting = false; // Phase 2 is running on the owner right now +let _vvPhase2Since = 0; // epoch ms, for the elapsed counter +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; } 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(); + + const stop = () => { + _vvPhase2Waiting = false; + if (_vvPartnerPoll) { clearInterval(_vvPartnerPoll); _vvPartnerPoll = null; } + if (_vvPhase2Tick) { clearInterval(_vvPhase2Tick); _vvPhase2Tick = null; } + vvLoadChecklist(); + }; + const deadline = Date.now() + 20 * 60 * 1000; const check = () => { fetch('/plugins/varaverk/api/checklist.php?_=' + Date.now()) .then(r => r.json()) .then(d => { const done = (d.items || []).some(i => i.id === 'partnership' && i.ok); - if (done || Date.now() > deadline) { - clearInterval(_vvPartnerPoll); _vvPartnerPoll = null; - vvLoadChecklist(); - } + if (done || Date.now() > deadline) stop(); }) .catch(() => {}); }; + + // Redraw between checklist polls so the elapsed counter moves. Without it the panel is static + // for six seconds at a time, which reads as frozen — the thing this panel exists to prevent. + _vvPhase2Tick = setInterval(() => { + if (_vvPhase2Waiting) vvRenderOnboardPanel(_vvLastChecklist || {items: []}); + }, 1000); + vvLoadChecklist(); check(); _vvPartnerPoll = setInterval(check, 6000); @@ -625,6 +649,7 @@ function vvLoadChecklist() { fetch('/plugins/varaverk/api/checklist.php?_=' + Date.now()) .then(r => r.json()).then(d => { const el = document.getElementById('vv-checklist'); + _vvLastChecklist = d; if (!d.ok || !d.items) { el.innerHTML = 'Unable to load checklist'; return; } vvLabelExit(); vvRenderOnboardPanel(d);