diff --git a/dashboard/js/core.js b/dashboard/js/core.js index c85e2df..8e38ac2 100644 --- a/dashboard/js/core.js +++ b/dashboard/js/core.js @@ -24,7 +24,7 @@ const DELIVERY_EVIDENCE_FILTERS=['all','comparable','spend_only','git_only','una let deliveryRange=localStorage.getItem('tm_delivery_range')||'30'; if(!DELIVERY_RANGES.includes(deliveryRange)){deliveryRange='30';localStorage.setItem('tm_delivery_range',deliveryRange);} let deliveryProject=localStorage.getItem('tm_delivery_project')||''; -let deliveryPayload=null,deliveryRequest=0,deliverySelectedDay='',deliveryLastLoadedAt=0; +let deliveryPayload=null,deliveryRequest=0,deliveryLoading=false,deliverySelectedDay='',deliveryLastLoadedAt=0; let deliverySort={key:'covered_cost',direction:'desc'}; let deliveryModelSort={key:'covered_cost',direction:'desc'}; let deliveryEvidenceFilter='all'; @@ -130,7 +130,7 @@ const countWord=(n,one,many=one+'s')=>Number(n)===1?one:many; const speedFmt=n=>{n=Number(n)||0;if(n<=0)return'--';if(n>=100)return n.toFixed(0);if(n>=10)return n.toFixed(1);return n.toFixed(2);}; const esc=s=>String(s??'').replace(/[&<>"']/g,c=>({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); // Work page state is declared early: the initial hash route can run before later definitions. -let WORK=null,workRequest=0,workLastLoadedAt=0,workMonths='6',workRuntime='',workProject=''; +let WORK=null,workRequest=0,workLoading=false,workLastLoadedAt=0,workMonths='6',workRuntime='',workProject=''; let workSupported=null; // Declared before the first route runs: a deep link schedules its scroll during startup. let pendingSettingsScroll=null; diff --git a/dashboard/js/live.js b/dashboard/js/live.js index 32b5c54..b57b527 100644 --- a/dashboard/js/live.js +++ b/dashboard/js/live.js @@ -143,8 +143,8 @@ function applyLiveState(state){ if($('view-capabilities').classList.contains('on'))renderCapabilities(LATEST.xsession?.capabilities); if($('view-efficiency').classList.contains('on'))renderActiveEfficiency(); if(['view-daily','view-efficiency','view-git','view-work'].some(id=>$(id).classList.contains('on'))&&Date.now()-goalsLoadedAt>30000)loadGoals(true); - if($('view-git').classList.contains('on')&&Date.now()-deliveryLastLoadedAt>60000)loadDelivery(); - if($('view-work').classList.contains('on')&&Date.now()-workLastLoadedAt>15000)loadWork(); + if($('view-git').classList.contains('on')&&!deliveryLoading&&Date.now()-deliveryLastLoadedAt>60000)loadDelivery(); + if($('view-work').classList.contains('on')&&!workLoading&&Date.now()-workLastLoadedAt>15000)loadWork(); if($('view-settings').classList.contains('on'))renderSettings(LATEST.xsession); if($('view-learn').classList.contains('on'))renderLearn(LATEST); if($('welcome-dialog').open)renderWelcome(LATEST); diff --git a/dashboard/js/work-insights.js b/dashboard/js/work-insights.js index 4cc6295..932a50a 100644 --- a/dashboard/js/work-insights.js +++ b/dashboard/js/work-insights.js @@ -215,6 +215,7 @@ function renderWork(payload){ } async function loadWork(){ const request=++workRequest,query=new URLSearchParams({months:workMonths}); + workLoading=true; if(workRuntime)query.set('runtime',workRuntime);if(workProject)query.set('project',workProject); try{ const response=await fetch(`/work?${query}`,{cache:'no-store'}); @@ -228,7 +229,7 @@ async function loadWork(){ if(request!==workRequest)return; $('w-state').dataset.state='storage_error';$('w-state').textContent='Error'; $('w-status-title').textContent='Work insights are unavailable';$('w-status-detail').textContent='Token Meter will try again shortly.'; - } + }finally{if(request===workRequest)workLoading=false;} } async function postWorkAction(path,payload){ const token=agentActionToken(); @@ -354,6 +355,7 @@ async function applyWorkSessionFilter(params){ } async function loadDelivery(){ const request=++deliveryRequest,query=new URLSearchParams({range:deliveryRange});if(deliveryProject)query.set('project',deliveryProject); + deliveryLoading=true; try{ const response=await fetch(`/git-delivery?${query}`,{cache:'no-store'});if(!response.ok)throw new Error('Git data unavailable'); const payload=await response.json();if(request!==deliveryRequest)return; @@ -370,7 +372,7 @@ async function loadDelivery(){ $('d-shape').innerHTML='