Upload 8 files
Browse files- web/static/runs.js +50 -2
web/static/runs.js
CHANGED
|
@@ -226,7 +226,7 @@ function renderRunRows(runs,compact=false){
|
|
| 226 |
<p class="run-list-id" title="${escapeHtml(r.run_id)}">${escapeHtml(r.run_id)}</p>
|
| 227 |
</div>
|
| 228 |
<div class="run-list-status">
|
| 229 |
-
<em class="run-status-pill ${tone}" title="${escapeHtml(isLoading?'Loading details…':badgeLabel(status))}">${escapeHtml(runCompactStatusLabel(status))}</em>
|
| 230 |
<time>${escapeHtml(time)}</time>
|
| 231 |
</div>
|
| 232 |
<button class="icon-btn danger run-delete-btn" type="button" data-run-delete="${escapeHtml(r.run_id)}" title="${canDelete?'Delete this finished run':'Delete becomes available after this run finishes'}" aria-label="Delete run ${escapeHtml(r.run_id)}" ${canDelete?'':'disabled aria-disabled="true"'}>×</button>
|
|
@@ -464,6 +464,10 @@ function forgetRunEverywhere(runId){
|
|
| 464 |
if(state.runDetailRequests){
|
| 465 |
delete state.runDetailRequests[`${runId}:light`];
|
| 466 |
delete state.runDetailRequests[`${runId}:heavy`];
|
|
|
|
|
|
|
|
|
|
|
|
|
| 467 |
}
|
| 468 |
if(state.documentCache)delete state.documentCache[runId];
|
| 469 |
if(state.latencyCache)delete state.latencyCache[runId];
|
|
@@ -475,6 +479,44 @@ function activeRunIds(){
|
|
| 475 |
return new Set(validRunsList(state.runsCache||[]).map(r=>r.run_id||r.summary?.run_id).filter(Boolean));
|
| 476 |
}
|
| 477 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 478 |
function associatedSpaceFromDetail(detail={},summaryOverride={}){
|
| 479 |
const summary={...(detail.summary||{}),...(summaryOverride||{})};
|
| 480 |
const candidates=[summary.target_space,summary.target_space_id,detail.target_space,detail.target_space_id,detail.state?.target_space,detail.launch?.target_space,detail.links?.target_space];
|
|
@@ -536,6 +578,7 @@ function renderRunsFromCache(){
|
|
| 536 |
}
|
| 537 |
renderRunStats();renderRunPagination(runs.length);renderRunAggregateStats();
|
| 538 |
document.querySelectorAll('.run-row').forEach(row=>row.classList.toggle('selected',Boolean(selectedId)&&row.dataset.run===selectedId));
|
|
|
|
| 539 |
}
|
| 540 |
|
| 541 |
|
|
@@ -696,6 +739,7 @@ function restoreRunRowStatusLabel(row){
|
|
| 696 |
pill.title=badgeLabel(status||cached.status||'unknown');
|
| 697 |
const tone=statusClass(status||cached.status||'unknown');
|
| 698 |
pill.className=`run-status-pill ${tone}`;
|
|
|
|
| 699 |
}
|
| 700 |
const dot=row.querySelector('.run-list-dot');
|
| 701 |
if(dot)dot.className=`run-list-dot ${statusClass(status||cached.status||'unknown')}`;
|
|
@@ -714,7 +758,11 @@ function setRunSelectionLoading(runId,loading=true){
|
|
| 714 |
document.querySelectorAll('.run-row[data-run]').forEach(row=>{
|
| 715 |
const active=Boolean(next)&&row.dataset.run===next;
|
| 716 |
row.classList.toggle('is-loading',active);
|
| 717 |
-
if(active)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 718 |
else{row.removeAttribute('aria-busy');restoreRunRowStatusLabel(row);}
|
| 719 |
});
|
| 720 |
}
|
|
|
|
| 226 |
<p class="run-list-id" title="${escapeHtml(r.run_id)}">${escapeHtml(r.run_id)}</p>
|
| 227 |
</div>
|
| 228 |
<div class="run-list-status">
|
| 229 |
+
<em class="run-status-pill ${isLoading?'loading':tone}" title="${escapeHtml(isLoading?'Loading details…':badgeLabel(status))}">${escapeHtml(isLoading?'Loading…':runCompactStatusLabel(status))}</em>
|
| 230 |
<time>${escapeHtml(time)}</time>
|
| 231 |
</div>
|
| 232 |
<button class="icon-btn danger run-delete-btn" type="button" data-run-delete="${escapeHtml(r.run_id)}" title="${canDelete?'Delete this finished run':'Delete becomes available after this run finishes'}" aria-label="Delete run ${escapeHtml(r.run_id)}" ${canDelete?'':'disabled aria-disabled="true"'}>×</button>
|
|
|
|
| 464 |
if(state.runDetailRequests){
|
| 465 |
delete state.runDetailRequests[`${runId}:light`];
|
| 466 |
delete state.runDetailRequests[`${runId}:heavy`];
|
| 467 |
+
delete state.runDetailRequests[`${runId}:snapshot:fast`];
|
| 468 |
+
delete state.runDetailRequests[`${runId}:snapshot:logs`];
|
| 469 |
+
if(state.runExplorerHydratedAt)delete state.runExplorerHydratedAt[runId];
|
| 470 |
+
if(state.runExplorerHydrationInFlight)delete state.runExplorerHydrationInFlight[runId];
|
| 471 |
}
|
| 472 |
if(state.documentCache)delete state.documentCache[runId];
|
| 473 |
if(state.latencyCache)delete state.latencyCache[runId];
|
|
|
|
| 479 |
return new Set(validRunsList(state.runsCache||[]).map(r=>r.run_id||r.summary?.run_id).filter(Boolean));
|
| 480 |
}
|
| 481 |
|
| 482 |
+
function runExplorerNeedsBackgroundHydration(run={}){
|
| 483 |
+
run=safeRunObject(run);
|
| 484 |
+
if(isValidationRunSummary(run))return false;
|
| 485 |
+
const runId=run.run_id||run.summary?.run_id;
|
| 486 |
+
if(!runId||isRunLocallyDeleted(runId))return false;
|
| 487 |
+
const canonical=buildEffectiveStatus(run);
|
| 488 |
+
if(['full_inference_success','failed','manual_hardware_required','technical_blocker','technical_blocker_boot_only','auth_refresh_required','stale','stopped','running'].includes(canonical))return false;
|
| 489 |
+
return ['partial_validation','health_only','partial','completed_with_warnings','unknown',''].includes(String(canonical||'').toLowerCase());
|
| 490 |
+
}
|
| 491 |
+
function scheduleRunExplorerBackgroundHydration(runs=[]){
|
| 492 |
+
if(typeof fetchRunViewSnapshotOnce!=='function'||typeof upsertRunExplorerFromProgress!=='function')return;
|
| 493 |
+
state.runExplorerHydrationInFlight=state.runExplorerHydrationInFlight||{};
|
| 494 |
+
state.runExplorerHydratedAt=state.runExplorerHydratedAt||{};
|
| 495 |
+
const now=Date.now();
|
| 496 |
+
const candidates=validRunsList(runs).filter(run=>{
|
| 497 |
+
if(!runExplorerNeedsBackgroundHydration(run))return false;
|
| 498 |
+
const runId=run.run_id||run.summary?.run_id;
|
| 499 |
+
const last=state.runExplorerHydratedAt[runId]||0;
|
| 500 |
+
return now-last>120000;
|
| 501 |
+
}).slice(0,6);
|
| 502 |
+
if(!candidates.length)return;
|
| 503 |
+
window.setTimeout(()=>{
|
| 504 |
+
candidates.forEach((run,index)=>{
|
| 505 |
+
const runId=run.run_id||run.summary?.run_id;
|
| 506 |
+
if(!runId||state.runExplorerHydrationInFlight[runId])return;
|
| 507 |
+
state.runExplorerHydrationInFlight[runId]=Date.now();
|
| 508 |
+
state.runExplorerHydratedAt[runId]=Date.now();
|
| 509 |
+
window.setTimeout(async()=>{
|
| 510 |
+
try{
|
| 511 |
+
const snapshot=await fetchRunViewSnapshotOnce(runId,{includeJobLogs:false});
|
| 512 |
+
if(snapshot&&validRunObject({run_id:snapshot.run_id||snapshot.summary?.run_id||runId}))upsertRunExplorerFromProgress(snapshot);
|
| 513 |
+
}catch(err){console.warn('background Run Explorer hydration failed',runId,err)}
|
| 514 |
+
finally{delete state.runExplorerHydrationInFlight[runId];}
|
| 515 |
+
},index*160);
|
| 516 |
+
});
|
| 517 |
+
},140);
|
| 518 |
+
}
|
| 519 |
+
|
| 520 |
function associatedSpaceFromDetail(detail={},summaryOverride={}){
|
| 521 |
const summary={...(detail.summary||{}),...(summaryOverride||{})};
|
| 522 |
const candidates=[summary.target_space,summary.target_space_id,detail.target_space,detail.target_space_id,detail.state?.target_space,detail.launch?.target_space,detail.links?.target_space];
|
|
|
|
| 578 |
}
|
| 579 |
renderRunStats();renderRunPagination(runs.length);renderRunAggregateStats();
|
| 580 |
document.querySelectorAll('.run-row').forEach(row=>row.classList.toggle('selected',Boolean(selectedId)&&row.dataset.run===selectedId));
|
| 581 |
+
scheduleRunExplorerBackgroundHydration(visible);
|
| 582 |
}
|
| 583 |
|
| 584 |
|
|
|
|
| 739 |
pill.title=badgeLabel(status||cached.status||'unknown');
|
| 740 |
const tone=statusClass(status||cached.status||'unknown');
|
| 741 |
pill.className=`run-status-pill ${tone}`;
|
| 742 |
+
pill.removeAttribute('aria-busy');
|
| 743 |
}
|
| 744 |
const dot=row.querySelector('.run-list-dot');
|
| 745 |
if(dot)dot.className=`run-list-dot ${statusClass(status||cached.status||'unknown')}`;
|
|
|
|
| 758 |
document.querySelectorAll('.run-row[data-run]').forEach(row=>{
|
| 759 |
const active=Boolean(next)&&row.dataset.run===next;
|
| 760 |
row.classList.toggle('is-loading',active);
|
| 761 |
+
if(active){
|
| 762 |
+
row.setAttribute('aria-busy','true');
|
| 763 |
+
const pill=row.querySelector('.run-status-pill');
|
| 764 |
+
if(pill){pill.textContent='Loading…';pill.title='Loading details…';pill.className='run-status-pill loading';pill.setAttribute('aria-busy','true');}
|
| 765 |
+
}
|
| 766 |
else{row.removeAttribute('aria-busy');restoreRunRowStatusLabel(row);}
|
| 767 |
});
|
| 768 |
}
|