Files
groot 47c523dd98
All checks were successful
release-tag / release-image (push) Successful in 3m51s
RC-14
2026-08-14 06:17:30 +02:00

2 lines
3.5 KiB
JavaScript

const $=id=>document.getElementById(id);function esc(s){return String(s??'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c]))}function msg(t,e=false){$('msg').textContent=t;$('msg').className='msg'+(e?' err':'');$('msg').classList.remove('hidden');setTimeout(()=>$('msg').classList.add('hidden'),6500)}async function api(p,o={}){if(o.body&&typeof o.body!=='string'){o.headers={'Content-Type':'application/json',...(o.headers||{})};o.body=JSON.stringify(o.body)}const r=await fetch(p,{credentials:'same-origin',...o});const x=await r.json().catch(()=>({}));if(!r.ok){const e=new Error(x.error||`HTTP ${r.status}`);e.status=r.status;throw e}return x}function workerHTML(w){return `<div class="worker"><div class="worker-main"><strong>${esc(w.worker_id||'—')}</strong><code>${esc(w.name||w.id)}</code><div class="small">${esc(w.image)} · ${esc(w.status||w.state)}</div></div><span class="pill ${w.running?'on':''}">${w.running?'RUNNING':'STOPPED'}</span><button class="ghost restart" data-id="${esc(w.id)}">RESTART</button><button class="ghost start" data-id="${esc(w.id)}" ${w.running?'disabled':''}>START</button><button class="danger stop" data-id="${esc(w.id)}" ${w.running?'':'disabled'}>STOP</button></div>`}function bind(){document.querySelectorAll('.start').forEach(b=>b.onclick=()=>action(b,'start'));document.querySelectorAll('.stop').forEach(b=>b.onclick=()=>action(b,'stop'));document.querySelectorAll('.restart').forEach(b=>b.onclick=()=>action(b,'restart'))}async function action(b,a){b.disabled=true;try{await api(`/api/admin/workers/${encodeURIComponent(b.dataset.id)}/${a}`,{method:'POST'});msg(`Worker ${a}`);await load()}catch(e){msg(e.message,true)}finally{b.disabled=false}}async function load(){const x=await api('/api/admin/overview');$('loginBox').classList.add('hidden');$('panel').classList.remove('hidden');$('controllerName').textContent=x.controller?.name||x.controller?.id||'Service Controller';const mc=x.controller?.master_connected?'MASTER ONLINE':'MASTER OFFLINE';const ma=x.controller?.master_last_attempt?new Date(x.controller.master_last_attempt).toLocaleString('de-DE'):'';const me=x.controller?.master_last_error?` · ${x.controller.master_last_error}`:'';$('controllerMeta').textContent=`${x.controller?.id||''} · ${x.controller?.advertise_url||''} · Master ${x.controller?.master_url||''} · ${mc}${ma?' · '+ma:''}${me}`;$('running').textContent=x.running||0;$('maxRunning').textContent=x.controller?.max_running||0;$('total').textContent=x.total||0;$('maxWorkers').textContent=x.controller?.max_workers||0;$('workers').innerHTML=(x.workers||[]).map(workerHTML).join('')||'<div class="small">Keine verwalteten Worker auf diesem Host.</div>';bind()}$('login').onclick=async()=>{try{await api('/api/admin/login',{method:'POST',body:{Username:$('user').value,Password:$('pass').value}});await load()}catch(e){msg(e.message,true)}};$('logout').onclick=async()=>{await api('/api/admin/logout',{method:'POST'}).catch(()=>{});location.reload()};$('refresh').onclick=()=>load().catch(e=>msg(e.message,true));$('stopAll').onclick=async()=>{if(!confirm('ALLE laufenden Neural-Hunt-Worker auf diesem Host stoppen?'))return;try{const x=await api('/api/admin/workers/stop-all',{method:'POST'});msg(`${x.stopped||0} Worker gestoppt${x.warnings?.length?' · '+x.warnings.length+' Warnungen':''}`,!!x.warnings?.length);await load()}catch(e){msg(e.message,true)}};$('pullImage').onclick=async()=>{try{const x=await api('/api/admin/image/pull',{method:'POST'});msg(`Image aktualisiert: ${x.image}`)}catch(e){msg(e.message,true)}};load().catch(()=>{});