fffiloni commited on
Commit
6f6ec9a
·
verified ·
1 Parent(s): 21834d9

Upload 8 files

Browse files
Files changed (1) hide show
  1. 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)row.setAttribute('aria-busy','true');
 
 
 
 
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
  }