diff --git a/Plugin/unraid/Varaverk.page b/Plugin/unraid/Varaverk.page
index 54266d1..7c32b22 100644
--- a/Plugin/unraid/Varaverk.page
+++ b/Plugin/unraid/Varaverk.page
@@ -277,8 +277,14 @@ function vvPtWatchJob(id, mountEl) {
: (s.status === 'never_run' ? 'did not start ⚠' : `${s.status} (exit ${s.exit ?? '?'})`);
mountEl.innerHTML = `${lbl}`
+ ` log`;
- // Only the Partnership tab defines a reload; the wizard has nothing to refresh.
if (typeof _vvPtReload === 'function') _vvPtReload();
+ // The wizard does have something to refresh, and saying it did not is why the mirror's
+ // Join button stayed greyed at "Running" after the run finished. Worse, the mirror's own
+ // job takes about three seconds — it only notifies the owner — while the Phase 2 it
+ // triggers runs for minutes on the far side. So "this job is done" is not "the
+ // partnership is done", and a single reload here would still show an unfinished wizard.
+ // vvOnJobDone polls until the checklist actually turns.
+ if (typeof vvOnJobDone === 'function') vvOnJobDone(id, s);
})
.catch(() => {});
};
diff --git a/Plugin/unraid/pages/setup.php b/Plugin/unraid/pages/setup.php
index 64c6064..32621cf 100644
--- a/Plugin/unraid/pages/setup.php
+++ b/Plugin/unraid/pages/setup.php
@@ -540,20 +540,43 @@ function vvRenderDone(d) {
if (!el) return;
const partner = vvDetectedIdentity?.role === 'partner';
- if (d.complete) {
- const next = partner
- ? `Next: install this server's SSH key on ${vvEscHtml(vvDetectedIdentity.primary || 'the primary')} `
- + `and join, both on the Partnership tab.`
- : 'Next: review the schedule, then onboard a partner when you have one.';
- el.innerHTML = `
- ✓ Setup complete — every required item is done.
- ${next}
`;
+ const blocking = (d.items || []).filter(i => !i.ok && i.blocking);
+ const onboarded = (d.items || []).some(i => i.id === 'partnership' && i.ok);
+ const optional = (d.items || []).filter(i => !i.ok && !i.blocking);
+
+ // Three states, not two. The old code returned '' when nothing was blocking but `complete` was
+ // still false — which is exactly the moment a partnership finishes, because `complete` also
+ // wants the optional media-server keys deferred or filled. So the wizard went blank at the end
+ // of a successful onboard, beside a Join button still greyed at "running", and there was
+ // nothing on screen to say it was over. People wait at a blank screen.
+ if (d.complete || !blocking.length) {
+ const heading = onboarded
+ ? 'Partnership established — this server is onboarded.'
+ : 'Setup complete — every required item is done.';
+ const leftover = optional.length
+ ? `
+ ${optional.length} optional item${optional.length > 1 ? 's' : ''} still open
+ (${optional.map(i => vvEscHtml(i.label)).join(', ')}) — fill them in whenever, or
+ dismiss with “Not now”. Nothing is waiting on them.
${blocking.length} required item${blocking.length > 1 ? 's' : ''} left:
@@ -561,6 +584,38 @@ function vvRenderDone(d) {
Anything marked optional can be dismissed with “Not now”.
`;
}
+// Called by vvPtWatchJob when a job it was watching finishes.
+//
+// On the mirror, "the onboard job finished" means the owner has been notified — three seconds of
+// work — and the Phase 2 it kicked off then runs for minutes on the other machine. Reloading once
+// here would redraw the same unfinished wizard and stop, which is how the panel ended up frozen
+// with a greyed Running button and no way to tell it had actually succeeded.
+//
+// So: reload immediately, and if the partnership is still not green keep asking. Bounded at five
+// minutes because a Phase 2 that has not landed by then has failed and the operator should be
+// looking at the log, not at a spinner.
+let _vvPartnerPoll = null;
+function vvOnJobDone(id, status) {
+ if (!String(id).includes('partnership_onboard')) { vvLoadChecklist(); return; }
+ if (_vvPartnerPoll) clearInterval(_vvPartnerPoll);
+ const deadline = Date.now() + 5 * 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();
+ }
+ })
+ .catch(() => {});
+ };
+ vvLoadChecklist();
+ check();
+ _vvPartnerPoll = setInterval(check, 6000);
+}
+
function vvLoadChecklist() {
fetch('/plugins/varaverk/api/checklist.php?_=' + Date.now())
.then(r => r.json()).then(d => {