Files
Alfredv2/alfred/app/static/js/alfred-developer-glass.js
T

46 lines
3.9 KiB
JavaScript

(() => {
'use strict';
const $=id=>document.getElementById(id);
let csrf='',selected=null,latest=null, busy=false;
const message=(txt,ok=false,id='dvMessage')=>{let e=$(id);e.textContent=txt;e.classList.toggle('ok',ok);};
async function fetchJson(url,options={}){
const r=await fetch(url,{credentials:'same-origin',cache:'no-store',...options});
const d=await r.json().catch(()=>({}));
if(!r.ok)throw Error(d.error || 'Erreur HTTP '+r.status);
return d;
}
async function auth(){
const d=await fetchJson('/api/control/auth');csrf=d.csrf||'';
$('dvLoginBox').hidden=!!d.authenticated;$('dvApp').hidden=!d.authenticated;
if(d.authenticated)await refresh();
}
async function getName(){try{const r=await fetchJson('/api/alfred/identity/name');let n=r.name||'Assistant';$('dvName').textContent=n;$('dvInitial').textContent=Array.from(n)[0]?.toLocaleUpperCase('fr-FR')||'A';document.title='Maintenance · '+n;}catch(_){}}
function renderTasks(tasks){$('dvCount').textContent=tasks.length+' propositions';const host=$('dvTasks');host.replaceChildren();
if(!tasks.length){let p=document.createElement('p');p.className='dv-muted';p.textContent='Aucune proposition pour le moment.';host.append(p);return;}
for(const t of tasks){let btn=document.createElement('button');btn.type='button';btn.className='dv-task'+(selected===t.id?' selected':'');
let strong=document.createElement('strong');strong.textContent=t.title;let small=document.createElement('small');small.textContent=t.id+' · '+t.status+' · '+t.changed.length+' fichier(s)';btn.append(strong,small);btn.addEventListener('click',()=>select(t.id));host.append(btn);}
}
async function refresh(){const r=await fetchJson('/api/control/developer/tasks');renderTasks(r.tasks);if(selected)await select(selected,false);}
async function select(id,again=true){selected=id;const d=await fetchJson('/api/control/developer/tasks/'+id);latest=d.task;
$('dvEmpty').hidden=true;$('dvSelected').hidden=false;$('dvTitle').textContent=latest.title;
$('dvState').textContent=latest.status;$('dvMeta').textContent='Proposition '+id+' · '+latest.changed.length+' fichier(s) · '+latest.created_at;
$('dvDiff').textContent=latest.diff||'Aucun changement détecté.';
const c=$('dvChecks');c.replaceChildren();for(const t of latest.checks||[]){let div=document.createElement('div');div.className='dv-check'+(t.ok?'':' fail');div.textContent=(t.ok?'✓ ':'✗ ')+t.file+' — '+t.detail;c.append(div);}
if(!c.childNodes.length)c.textContent='Contrôles pas encore réalisés.';
$('dvActions').hidden=latest.status!=='pending';$('dvNext').hidden=latest.status!=='approved';
$('dvCommand').textContent='sudo python3 /opt/alfred/app/tools/alfred_deploy.py deploy '+id+' --apply';
if(again)await refresh();
}
async function decide(decision){if(!latest||busy)return;const desc=decision==='approve'?'approuver':'refuser';
if(!confirm('Confirmer : '+desc+' la proposition '+latest.id+' ?'))return;
busy=true;try{const id=latest.id;const d=await fetchJson('/api/control/developer/tasks/'+id+'/decision',{
method:'POST',headers:{'Content-Type':'application/json','X-Alfred-CSRF':csrf},body:JSON.stringify({decision,diff_sha256:latest.diff_sha256})
});message('Décision enregistrée : '+d.result.status,true);await select(id);}catch(e){message(e.message);}finally{busy=false;}
}
$('dvLogin').addEventListener('submit',async e=>{e.preventDefault();try{await fetchJson('/api/control/login',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({password:$('dvPassword').value})});$('dvPassword').value='';await auth();}catch(err){message(err.message,false,'dvLoginInfo');}});
$('dvRefresh').addEventListener('click',()=>refresh().catch(err=>message(err.message)));
$('dvApprove').addEventListener('click',()=>decide('approve'));
$('dvReject').addEventListener('click',()=>decide('reject'));
getName();auth().catch(e=>{$('dvLoginBox').hidden=false;message(e.message,false,'dvLoginInfo');});
})();