v1.2.11: scenario list — expandable steps + run confirmation

- Click on scenario name → expands to show step details:
  operation → service_id (output/ref/uid) (params)
- ▶ Запустить button inside expanded view
- confirm('Запустить сценарий?') before running
- CRUD buttons (✏📋🗑) with event.stopPropagation()
- toggleScenarioSteps(defId): single-expand (closes others)
This commit is contained in:
2026-07-31 13:55:11 +04:00
parent e618d6d011
commit bfa21accf5
2 changed files with 41 additions and 6 deletions
+40 -5
View File
@@ -23,13 +23,17 @@ async function loadScenarios(){
html+='<div style="display:flex;flex-direction:column;gap:4px;margin-bottom:4px;">';
sr.forEach(s=>{
const seed = s.is_seed;
html+=`<div style="display:flex;align-items:center;gap:4px;">`;
html+=`<button class="btn btn-sm" style="font-size:12px;flex:1;text-align:left;" onclick="runScenario(${s.id})" title="Запустить">▶ ${_esc(s.name)} <span style="color:var(--muted);">(${s.steps} шагов)</span></button>`;
if(!seed) html+=`<button class="btn btn-sm" style="font-size:13px;padding:0 6px;" onclick="editScenario(${s.id})" title="Редактировать">✏</button>`;
html+=`<button class="btn btn-sm" style="font-size:13px;padding:0 6px;" onclick="cloneScenario(${s.id},'${_esc(s.name)}')" title="Копировать">📋</button>`;
if(!seed) html+=`<button class="btn btn-sm" style="font-size:13px;padding:0 6px;color:var(--destructive);" onclick="deleteScenario(${s.id},'${_esc(s.name)}')" title="Удалить">🗑</button>`;
html+=`<div style="border:1px solid var(--brand-gray);border-radius:4px;padding:4px 6px;">`;
html+=`<div style="display:flex;align-items:center;gap:4px;cursor:pointer;" onclick="toggleScenarioSteps(${s.id})">`;
html+=`<span style="font-size:13px;font-weight:600;flex:1;">${_esc(s.name)}</span>`;
html+=`<span style="color:var(--muted);font-size:11px;">${s.steps} шагов</span>`;
if(!seed) html+=`<button class="btn btn-sm" style="font-size:12px;padding:0 6px;" onclick="event.stopPropagation();editScenario(${s.id})" title="Редактировать"></button>`;
html+=`<button class="btn btn-sm" style="font-size:12px;padding:0 6px;" onclick="event.stopPropagation();cloneScenario(${s.id},'${_esc(s.name)}')" title="Копировать">📋</button>`;
if(!seed) html+=`<button class="btn btn-sm" style="font-size:12px;padding:0 6px;color:var(--destructive);" onclick="event.stopPropagation();deleteScenario(${s.id},'${_esc(s.name)}')" title="Удалить">🗑</button>`;
if(seed) html+=`<span style="font-size:9px;color:var(--muted);padding:0 4px;">seed</span>`;
html+=`</div>`;
html+=`<div id="scenario-steps-${s.id}" style="display:none;margin-top:4px;padding-left:8px;"></div>`;
html+=`</div>`;
});
html+='</div>';
}else{
@@ -49,8 +53,39 @@ async function loadScenarios(){
}catch(e){body.innerHTML='<span style="color:var(--destructive);font-size:11px;">Ошибка загрузки</span>';}
}
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 = '<div style="font-size:11px;padding:4px 0;">';
steps.forEach((s, i) => {
const svcName = s.service_id ? 'сервис ' + s.service_id : '?';
html += `<div style="padding:2px 0;">${i+1}. <b>${_esc(s.operation)}</b> → ${svcName}`;
if (s.output) html += ` <span style="color:var(--muted);">(${_esc(s.output)})</span>`;
if (s.instance_ref) html += ` <span style="color:var(--muted);">→ ${_esc(s.instance_ref)}</span>`;
if (s.instance_uid) html += ` <span style="color:var(--muted);">→ ${_esc(s.instance_uid.substring(0,8))}...</span>`;
const params = Object.entries(s.params || {});
if (params.length) html += ' <span style="color:var(--muted);">(' + params.map(([k,v]) => k+'='+v).join(', ') + ')</span>';
html += '</div>';
});
html += `<button class="btn btn-sm" style="margin-top:4px;font-size:11px;background:var(--brand-primary);color:#fff;" onclick="event.stopPropagation();runScenario(${defId})">▶ Запустить</button>`;
html += '</div>';
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');