diff --git a/js/ui.js b/js/ui.js index a7ddd7f..b8e42a0 100644 --- a/js/ui.js +++ b/js/ui.js @@ -298,6 +298,8 @@ async function saveInstance() { showToast(`${name} ${editingVmid ? 'updated' : 'created'}`, 'success'); closeModal(); + if (!editingVmid) await _waitForOnCreateJobs(); + if (currentVmid && document.getElementById('page-detail').classList.contains('active')) { await renderDetailPage(vmid); } else { @@ -305,6 +307,30 @@ async function saveInstance() { } } +async function _waitForOnCreateJobs() { + const jobs = await fetch('/api/jobs').then(r => r.json()); + const relevant = jobs.filter(j => { + try { return JSON.parse(j.config || '{}').run_on_create; } catch { return false; } + }); + if (!relevant.length) return; + + // Snapshot run IDs before jobs fire so we can detect new completions + const baseline = new Map(relevant.map(j => [j.id, j.last_run_id ?? null])); + + const deadline = Date.now() + 30_000; + while (Date.now() < deadline) { + await new Promise(r => setTimeout(r, 500)); + const current = await fetch('/api/jobs').then(r => r.json()); + const allDone = relevant.every(j => { + const cur = current.find(c => c.id === j.id); + if (!cur) return true; + if (cur.last_run_id === baseline.get(j.id)) return false; // new run not started yet + return cur.last_status !== 'running'; // new run complete + }); + if (allDone) return; + } +} + // ── Confirm Dialog ──────────────────────────────────────────────────────────── function confirmDeleteDialog(inst) {