diff --git a/public_html/admin/index.php b/public_html/admin/index.php index ac084b9..cd728aa 100644 --- a/public_html/admin/index.php +++ b/public_html/admin/index.php @@ -2172,10 +2172,82 @@ function wToast(msg,err=false) { setTimeout(()=>{t.style.opacity='0';},3000); } async function workerAction(type,id,action) { + if (type === 'agent' && action === 'update') { + await agentUpdateFlow(id); + return; + } const res=await api('worker_action',{worker_type:type,worker_id:id,action}); if(res&&res.ok){wToast(res.msg||'Done');setTimeout(loadWorkers,2500);} else wToast((res&&res.error)||'Action failed',true); } + +async function agentUpdateFlow(agentId) { + // Find the current version for this agent from the table + const row = [...document.querySelectorAll('#workers-agents tr')] + .find(r => r.innerHTML.includes(agentId)); + const curVerEl = row ? row.querySelector('td:nth-child(5) span') : null; + const curVer = curVerEl ? curVerEl.textContent.replace(/[^0-9.]/g,'').trim() : '?'; + + // Show modal with live status + openModal(`⬆ UPDATE AGENT — ${agentId}`, + `
+
Dispatching update command...
+
`, null, null); + document.getElementById('modalSave').style.display = 'none'; + + const log = (msg, col) => { + const el = document.getElementById('upd-status'); + if (el) el.innerHTML += `
${msg}
`; + }; + + // Dispatch command + const res = await api('worker_action', {worker_type:'agent', worker_id:agentId, action:'update'}); + if (!res || !res.ok) { + log('✗ Failed to dispatch: ' + (res?.error||'unknown'), 'var(--red)'); + document.getElementById('modalSave').style.display = ''; + document.getElementById('modalSave').textContent = 'CLOSE'; + document.getElementById('modalSave').onclick = closeModal; + return; + } + log('✓ Command dispatched — waiting for agent to pick up...', 'var(--cyan)'); + + // Poll agent_commands for the result (max 90s) + const cmdRes = await api('worker_action', {worker_type:'agent', worker_id:agentId, action:'update_status'}).catch(()=>null); + // Actually poll via workers_list for version change + const deadline = Date.now() + 90000; + let done = false; + while (Date.now() < deadline) { + await new Promise(r => setTimeout(r, 4000)); + const wData = await api('workers_list').catch(()=>null); + if (!wData || !wData.agents) break; + const ag = wData.agents.find(a => a.agent_id === agentId); + if (!ag) break; + const newVer = ag.version || null; + const latest = (wData.latest_versions||{})[ag.agent_type] || null; + if (latest && newVer === latest) { + log(`✓ Agent confirmed v${newVer} — up to date!`, 'var(--green)'); + // Update the version cell in the table live + if (curVerEl) { + curVerEl.textContent = `v${newVer} ✓`; + curVerEl.style.color = 'var(--green)'; + const tdVer = curVerEl.closest('td'); + if (tdVer) tdVer.innerHTML = `v${newVer} ✓`; + } + done = true; + break; + } else if (newVer && newVer !== curVer) { + log(`↻ Version changed: ${curVer} → ${newVer} (checking if latest...)`, 'var(--yellow)'); + } else { + log('· Waiting...', 'var(--text-dim)'); + } + } + if (!done) { + log('⚠ Timed out — agent may update in background (self-update runs periodically)', 'var(--yellow)'); + } + document.getElementById('modalSave').style.display = ''; + document.getElementById('modalSave').textContent = 'CLOSE'; + document.getElementById('modalSave').onclick = () => { closeModal(); loadWorkers(); }; +} async function loadWorkers() { const d=await api('workers_list'); if(!d||d.error) return;