// scenario-list.js — список сценариев, запуск, поллинг 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=''; html+=``; if(sr.length){ html+='
'; sr.forEach(s=>{ const seed = s.is_seed; html+=`
`; html+=`
`; html+=`${_esc(s.name)}`; html+=`${s.steps} шаг.`; if(seed) html+=`seed`; html+=`
`; html+=``; html+=`
`; }); html+='
'; }else{ html+='Нет сценариев в БД'; } const curVer=window.APP&&window.APP.version||''; const verHistory=srHistory&&srHistory.filter(r=>r.app_version===curVer); if(verHistory && verHistory.length){ const last=verHistory[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):'?'; const runningStyle = last.status==='RUNNING' ? 'background:#fef3c7;padding:2px 4px;border-radius:3px;' : ''; html+=`
Последний: ${icon} ${_esc(last.scenario_name)} — ${last.status} (шаг ${last.current_step}/${last.total_steps}) ${last.duration_sec!=null?last.duration_sec.toFixed(1)+'s':''} — ${time}
`; if(last.error_log) html+=`
${_esc(last.error_log)}
`; } body.innerHTML=html; }catch(e){body.innerHTML='Ошибка загрузки';} } async function toggleScenarioSteps(defId) { const el = document.getElementById('scenario-steps-' + defId); if (!el) return; if (el.style.display === 'block') { el.style.display = 'none'; return; } // Загрузить шаги try { const r = await fetch('/api/scenario/definitions/' + defId); const def = await r.json(); if (def.error) return; const steps = def.steps || []; let html = '
'; steps.forEach((s, i) => { const svcName = s.service_id ? 'сервис ' + s.service_id : '?'; html += `
${i+1}. ${_esc(s.operation)} → ${svcName}`; if (s.output) html += ` (${_esc(s.output)})`; if (s.instance_ref) html += ` → ${_esc(s.instance_ref)}`; if (s.instance_uid) html += ` → ${_esc(s.instance_uid.substring(0,8))}...`; const params = Object.entries(s.params || {}); if (params.length) html += ' (' + params.map(([k,v]) => k+'='+v).join(', ') + ')'; html += '
'; }); html += ``; html += ``; html += ``; if (!def.is_seed) html += ``; html += '
'; el.innerHTML = html; el.style.display = 'block'; // Закрыть другие document.querySelectorAll('[id^="scenario-steps-"]').forEach(e => { if (e !== el) e.style.display = 'none'; }); } catch (e) {} } async function runScenario(defId){ if(busy){ return; } if(!confirm('Запустить сценарий?')) return; busy=true; stopScenarioPoll(); const body=document.getElementById('scenario-body'); body.innerHTML=`
⏳ Запуск...
`; try{ const r=await fetch('/api/scenario/run',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({definition_id:defId})}); const d=await r.json(); if(d.error){ body.innerHTML=`Ошибка: ${_esc(d.error)}`; busy=false; return; } const runId=d.run_id; if(!runId){ body.innerHTML=`Ошибка: нет run_id в ответе`; busy=false; return; } scenarioPollTimer=setInterval(async()=>{ try{ const sr=await fetch('/api/scenario/run/'+runId); if(!sr.ok){ return; } const last=await sr.json(); if(!last||last.error) return; const icon=last.status==='OK'?'✅':last.status==='FAIL'?'❌':last.status==='RUNNING'?'⏳':'⏱'; const time=last.created_at?last.created_at.replace('T',' ').substring(0,19):'?'; const runningBg = last.status==='RUNNING' ? 'background:#fef3c7;padding:2px 4px;border-radius:3px;' : ''; let html=`
${icon} ${_esc(last.scenario_name)} — ${last.status} (шаг ${last.current_step}/${last.total_steps}) ${last.duration_sec!=null?last.duration_sec.toFixed(1)+'s':''} — ${time}
`; if(last.error_log) html+=`
${_esc(last.error_log)}
`; body.innerHTML=html; if(last.status!=='RUNNING'){ stopScenarioPoll(); busy=false; await refreshInstances(); if(historyOpen) await loadHistory(); } }catch(e){} },3000); }catch(e){ body.innerHTML=`Ошибка: ${_esc(e.message)}`; busy=false; } } function stopScenarioPoll(){ if(scenarioPollTimer){ clearInterval(scenarioPollTimer); scenarioPollTimer=null; } }