v1.1.46: phase2 — scenario runner MVP (YAML config, DB schema, API endpoints, UI section)
This commit is contained in:
@@ -468,4 +468,84 @@ function toggleLog(){
|
||||
if(el.style.display==='none'){ el.style.display='block'; startLogPoll(); }
|
||||
else el.style.display='none';
|
||||
}
|
||||
|
||||
// === Сценарии (автотесты) ===
|
||||
let scenarioOpen=false, scenarioPollTimer=null;
|
||||
|
||||
async function toggleScenario(){
|
||||
const body=document.getElementById('scenario-body');
|
||||
scenarioOpen=!scenarioOpen;
|
||||
body.style.display=scenarioOpen?'block':'none';
|
||||
if(!scenarioOpen){ stopScenarioPoll(); return; }
|
||||
await loadScenarios();
|
||||
}
|
||||
|
||||
async function loadScenarios(){
|
||||
const body=document.getElementById('scenario-body');
|
||||
try{
|
||||
const [sr, srHistory]=await Promise.all([
|
||||
fetch('/api/scenarios').then(r=>r.json()),
|
||||
fetch('/api/scenario/status').then(r=>r.json()),
|
||||
]);
|
||||
let html='';
|
||||
if(sr.length){
|
||||
html+='<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:4px;">';
|
||||
sr.forEach(s=>{
|
||||
html+=`<button class="btn btn-sm" style="font-size:11px;" onclick="runScenario('${_esc(s.name)}')">▶ ${_esc(s.name)} <span style="color:var(--muted);">(${s.steps} шагов)</span></button>`;
|
||||
});
|
||||
html+='</div>';
|
||||
}else{
|
||||
html+='<span style="color:var(--muted);font-size:11px;">Нет сценариев в config.yaml</span>';
|
||||
}
|
||||
// Последний запуск
|
||||
if(srHistory && srHistory.length){
|
||||
const last=srHistory[0];
|
||||
const icon=last.status==='OK'?'✅':last.status==='FAIL'?'❌':last.status==='RUNNING'?'⏳':'⏱';
|
||||
const time=last.created_at?last.created_at.replace('T',' ').substring(0,19):'?';
|
||||
html+=`<div style="font-size:11px;margin-top:4px;color:var(--muted);">Последний: ${icon} ${_esc(last.scenario_name)} — ${last.status} (шаг ${last.current_step}/${last.total_steps}) ${last.duration_sec!=null?last.duration_sec.toFixed(1)+'s':''} — ${time}</div>`;
|
||||
if(last.error_log) html+=`<div style="font-size:10px;color:var(--destructive);">${_esc(last.error_log)}</div>`;
|
||||
}
|
||||
body.innerHTML=html;
|
||||
}catch(e){body.innerHTML='<span style="color:var(--destructive);font-size:11px;">Ошибка загрузки</span>';}
|
||||
}
|
||||
|
||||
async function runScenario(name){
|
||||
if(busy){ return; }
|
||||
busy=true;
|
||||
stopScenarioPoll();
|
||||
const body=document.getElementById('scenario-body');
|
||||
body.innerHTML=`<div style="font-size:11px;">⏳ Запуск сценария ${_esc(name)}...</div>`;
|
||||
try{
|
||||
const r=await fetch('/api/scenario/run',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({scenario:name})});
|
||||
const d=await r.json();
|
||||
if(d.error){ body.innerHTML=`<span style="color:var(--destructive);">Ошибка: ${_esc(d.error)}</span>`; busy=false; return; }
|
||||
// Поллинг статуса
|
||||
scenarioPollTimer=setInterval(async()=>{
|
||||
try{
|
||||
const sr=await fetch('/api/scenario/status');
|
||||
const rows=await sr.json();
|
||||
if(!rows||!rows.length) return;
|
||||
const last=rows[0];
|
||||
const icon=last.status==='OK'?'✅':last.status==='FAIL'?'❌':last.status==='RUNNING'?'⏳':'⏱';
|
||||
const time=last.created_at?last.created_at.replace('T',' ').substring(0,19):'?';
|
||||
let html=`<div style="font-size:11px;">${icon} ${_esc(last.scenario_name)} — ${last.status} (шаг ${last.current_step}/${last.total_steps}) ${last.duration_sec!=null?last.duration_sec.toFixed(1)+'s':''} — ${time}</div>`;
|
||||
if(last.error_log) html+=`<div style="font-size:10px;color:var(--destructive);">${_esc(last.error_log)}</div>`;
|
||||
body.innerHTML=html;
|
||||
if(last.status!=='RUNNING'){
|
||||
stopScenarioPoll();
|
||||
busy=false;
|
||||
await refreshInstances();
|
||||
if(historyOpen) await loadHistory();
|
||||
}
|
||||
}catch(e){}
|
||||
},3000);
|
||||
}catch(e){
|
||||
body.innerHTML=`<span style="color:var(--destructive);">Ошибка: ${_esc(e.message)}</span>`;
|
||||
busy=false;
|
||||
}
|
||||
}
|
||||
|
||||
function stopScenarioPoll(){
|
||||
if(scenarioPollTimer){ clearInterval(scenarioPollTimer); scenarioPollTimer=null; }
|
||||
}
|
||||
startLogPoll();
|
||||
Reference in New Issue
Block a user