Files
VianoBugAnalysis/src/viano_bug_analysis/web/operations.js
T

44 lines
4.2 KiB
JavaScript

'use strict';
let operationState=null, operationSending=false;
function clearOperations(){operationState=null;['operation-status','operation-projects','operation-events'].forEach(id=>$(id).replaceChildren());$('operation-audit').hidden=true;}
async function changeOperation(data,button){
if(operationSending)return;const generation=session;operationSending=true;button.disabled=true;
try{const result=await api('/v1/operations',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(data)});
if(generation!==session)return;
error(result.status==='QUEUED'?'Fortsetzung vorgemerkt. Der Worker prüft die Freigabe vor der Ausführung.':'');
await refreshOperations();
}catch(e){if(generation===session)error(`Betriebsaktion fehlgeschlagen: ${e.message}`);}
finally{operationSending=false;if(generation===session)button.disabled=false;}
}
function addRetryControl(data,root){
if(!operationState?.operator||data.revision!==data.current_revision)return;
if(data.state==='BLOCKED'&&data.reason==='ENTITY_RESOLUTION_INVALID_RESPONSES'){
root.append(text('p','Nach einer technischen Korrektur kann ein zusätzlicher Antwortversuch für die Namensauflösung freigegeben werden. Vorhandene Ergebnisse und Untersuchungsbudgets bleiben erhalten. Der Folgeaufruf kann LLM-Kosten verursachen.','hint'));
const label=text('label','Durchgeführte Fehlerbehebung (keine Schlüssel oder Passwörter)');
const reason=document.createElement('textarea');reason.maxLength=1000;reason.rows=2;label.append(reason);root.append(label);
const button=text('button','Einen Reparaturversuch freigeben');button.type='button';
button.addEventListener('click',()=>{const note=reason.value.trim();if(!note){error('Bitte die durchgeführte Fehlerbehebung beschreiben.');return;}
changeOperation({action:'repair',key:data.key,package_generation:data.package_generation,reason:note},button);});
root.append(button);return;
}
const retry=data.state==='BLOCKED'?data.reason==='RESEARCH_UNAVAILABLE':!finished.has(data.state)&&['ERROR','ATTENTION','BUSY','DEFERRED','RETRY_PENDING'].includes(data.worker.status);
if(!retry)return;
const button=text('button','Fortsetzung nach Fehlerbehebung anfordern');button.type='button';
button.addEventListener('click',()=>changeOperation({action:'retry',key:data.key,package_generation:data.package_generation},button));root.append(button);
}
async function refreshOperations(){
const generation=session;const result=await api('/v1/operations');if(generation!==session)return;
const changed=operationState?.operator!==result.operator;operationState=result;
const status=$('operation-status');status.replaceChildren();
if(result.worker){const w=result.worker;status.append(text('p',`${w.live?'Worker erreichbar':'Kein lebender Worker bestätigt'} · Letzter Zustand: ${w.status||'Unbekannt'}${w.code?' · '+w.code:''}`));
if(w.updated_at)status.append(text('p',`Letzte Aktivität: ${new Date(w.updated_at).toLocaleString('de-DE')}`,'hint'));}
else status.append(text('p',result.operator?'Workerdetails erfordern Zugriff auf alle Projekte.':'Lesender Betriebszugriff. Betreiberaktionen sind nicht freigegeben.','hint'));
if(result.pending)status.append(text('p',`${result.pending} Fortsetzungsaufträge warten auf den Worker.`));
const projectsRoot=$('operation-projects');projectsRoot.replaceChildren();
result.projects.forEach(p=>{const row=text('div','','section-head');row.append(text('p',`${p.project_id} · ${p.paused?'Neue Fälle pausiert':'Neue Fälle freigegeben'}`));
if(result.operator){const button=text('button',p.paused?'Neue Fälle wieder zulassen':'Neue Fälle pausieren');button.type='button';button.addEventListener('click',()=>changeOperation({action:p.paused?'resume':'pause',project_id:p.project_id},button));row.append(button);}projectsRoot.append(row);});
$('operation-audit').hidden=!result.operator;const log=$('operation-events');log.replaceChildren();
result.events.slice().reverse().forEach(e=>log.append(text('p',`${new Date(e.at).toLocaleString('de-DE')} · ${e.actor} · ${e.project_id}${e.case_id?' · '+e.case_id:''} · ${e.action} · ${e.status}${e.code?' · '+e.code:''}`)));
if(changed&&selectedCase&&location.hash.startsWith('#case/'))renderDetail(selectedCase);
}