Meta-pipeline UI: add Stop/Restart/Results controls per pipeline

Each pipeline card now shows:
- Status dot + name + status tag + best score
- Stop button (red) when running
- Restart button (green) when stopped/completed
- Results button (magenta) to drill into iterations
- Live progress text when running
- Stages and iteration count on info line

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
root 2026-03-26 05:06:24 -05:00
parent 28df789745
commit c9901dbc94

View File

@ -4007,43 +4007,66 @@ async function loadMetaPipelines() {
title.textContent = 'Pipeline Runs';
el.appendChild(title);
pipes.forEach(function(p) {
var row = document.createElement('div');
row.style.cssText = 'display:flex;align-items:center;gap:8px;padding:8px;background:rgba(0,0,0,0.2);border:2px solid var(--border);border-radius:2px;margin-bottom:4px;cursor:pointer;transition:border-color 0.15s;font-size:11px';
if (p.status === 'running') row.style.borderColor = 'rgba(217,70,239,0.3)';
if (p.status === 'completed') row.style.borderColor = 'rgba(74,222,128,0.2)';
row.onmouseenter = function(){row.style.borderColor='var(--accent)'};
row.onmouseleave = function(){row.style.borderColor = p.status==='running'?'rgba(217,70,239,0.3)':p.status==='completed'?'rgba(74,222,128,0.2)':'var(--border)'};
// Status dot
var card = document.createElement('div');
card.style.cssText = 'background:rgba(0,0,0,0.2);border:2px solid var(--border);border-radius:2px;margin-bottom:6px;padding:10px 12px';
if (p.status === 'running') card.style.borderColor = 'rgba(217,70,239,0.3)';
if (p.status === 'completed') card.style.borderColor = 'rgba(74,222,128,0.2)';
// Top row: status + name + score + controls
var topRow = document.createElement('div');
topRow.style.cssText = 'display:flex;align-items:center;gap:8px;font-size:11px';
var dot = document.createElement('div');
var dotColor = p.status==='running'?'#d946ef':p.status==='completed'?'var(--green)':'var(--text2)';
dot.style.cssText = 'width:8px;height:8px;border-radius:50%;background:'+dotColor+';flex-shrink:0';
if (p.status === 'running') dot.style.animation = 'pulse 2s infinite';
row.appendChild(dot);
topRow.appendChild(dot);
var name = document.createElement('span');
name.style.cssText = 'font-weight:700;min-width:140px';
name.textContent = p.name; row.appendChild(name);
var stagesEl = document.createElement('span');
stagesEl.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:9px;color:var(--text2);flex:1';
stagesEl.textContent = (p.stages||[]).join('');
row.appendChild(stagesEl);
if (p.live_status && p.status === 'running') {
var prog = document.createElement('span');
prog.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:9px;color:#d946ef';
prog.textContent = p.live_status.substep || '';
row.appendChild(prog);
}
name.style.cssText = 'font-weight:700';
name.textContent = p.name; topRow.appendChild(name);
var statusTag = document.createElement('span');
statusTag.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:8px;text-transform:uppercase;letter-spacing:1px;padding:2px 6px;border:1px solid;border-radius:1px;color:'+dotColor+';border-color:'+dotColor;
statusTag.textContent = p.status; topRow.appendChild(statusTag);
if (p.best_score > 0) {
var score = document.createElement('span');
score.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:10px;font-weight:700;color:var(--green)';
score.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:11px;font-weight:700;color:var(--green)';
score.textContent = p.best_score.toFixed(1)+'/10';
row.appendChild(score);
topRow.appendChild(score);
}
var iters = document.createElement('span');
iters.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:9px;color:var(--text2)';
iters.textContent = (p.iterations||0)+' iters';
row.appendChild(iters);
row.onclick = function(){viewMetaPipeline(p.id)};
el.appendChild(row);
var spacer = document.createElement('span'); spacer.style.flex = '1'; topRow.appendChild(spacer);
// Controls
if (p.status === 'running') {
var stopBtn = document.createElement('button');
stopBtn.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:8px;text-transform:uppercase;padding:3px 8px;border:2px solid rgba(224,82,82,0.3);border-radius:2px;background:transparent;color:var(--red);cursor:pointer';
stopBtn.textContent = 'Stop';
stopBtn.onclick = function(e){e.stopPropagation();fetch('/api/meta-pipeline/'+p.id+'/stop',{method:'POST'}).then(function(){loadMetaPipelines()})};
topRow.appendChild(stopBtn);
} else if (p.status !== 'running') {
var startBtn = document.createElement('button');
startBtn.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:8px;text-transform:uppercase;padding:3px 8px;border:2px solid rgba(74,222,128,0.3);border-radius:2px;background:transparent;color:var(--green);cursor:pointer';
startBtn.textContent = 'Restart';
startBtn.onclick = function(e){e.stopPropagation();fetch('/api/meta-pipeline/'+p.id+'/start',{method:'POST'}).then(function(){loadMetaPipelines()})};
topRow.appendChild(startBtn);
}
var viewBtn = document.createElement('button');
viewBtn.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:8px;text-transform:uppercase;padding:3px 8px;border:2px solid rgba(217,70,239,0.3);border-radius:2px;background:transparent;color:#d946ef;cursor:pointer';
viewBtn.textContent = 'Results';
viewBtn.onclick = function(e){e.stopPropagation();viewMetaPipeline(p.id)};
topRow.appendChild(viewBtn);
card.appendChild(topRow);
// Info row: stages + iterations + live status
var infoRow = document.createElement('div');
infoRow.style.cssText = 'font-family:JetBrains Mono,monospace;font-size:9px;color:var(--text2);margin-top:4px;display:flex;gap:12px';
infoRow.textContent = (p.stages||[]).join('') + ' | ' + (p.iterations||0) + ' iterations';
if (p.live_status && p.status === 'running') {
var prog = document.createElement('span');
prog.style.cssText = 'color:#d946ef;margin-left:auto';
prog.textContent = p.live_status.substep || '';
infoRow.appendChild(prog);
}
card.appendChild(infoRow);
el.appendChild(card);
});
} catch(e) {}
}