fix: make Analysis tab robust when no snapshot data exists

- showView() now tracks _curView, scrolls to top, forces visibility
- loadAnalysis() shows clear "No data yet" message when API returns null
  instead of silently leaving static placeholder text
- forceRefreshAnalysis() added: POSTs /api/refresh then reloads analysis
- ↻ Refresh button added at top of Analysis view with live timestamp
- Auto-refresh analysis every 30s when Analysis tab is active

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Manohar 2026-06-19 14:20:59 +05:30
parent dca5fea679
commit 02cc8ed9b3

View file

@ -302,6 +302,10 @@
</div> </div>
</div><!-- end view-dashboard --> </div><!-- end view-dashboard -->
<div data-view="analysis" id="view-analysis" style="display:none"> <div data-view="analysis" id="view-analysis" style="display:none">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px">
<span style="font-size:.7rem;color:var(--text3)" id="a-asof-top"></span>
<button class="ibtn" id="a-refresh-btn" onclick="forceRefreshAnalysis()" style="font-size:.72rem;padding:5px 12px;border-radius:9px;border:1px solid var(--border2)">&#8635; Refresh</button>
</div>
<div style="display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:16px" class="a-sum-grid"> <div style="display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:16px" class="a-sum-grid">
<div class="card pcard pu"><div class="plbl">Net Delta</div><div class="pval fl" id="a-delta">&#8212;</div><div class="psub">Directional exposure</div></div> <div class="card pcard pu"><div class="plbl">Net Delta</div><div class="pval fl" id="a-delta">&#8212;</div><div class="psub">Directional exposure</div></div>
<div class="card pcard" style="--ca:#F5A623;--cb:#E67E22"><div class="plbl">Net Theta / day</div><div class="pval fl" id="a-theta">&#8212;</div><div class="psub">Daily time decay (&#8377;)</div></div> <div class="card pcard" style="--ca:#F5A623;--cb:#E67E22"><div class="plbl">Net Theta / day</div><div class="pval fl" id="a-theta">&#8212;</div><div class="psub">Daily time decay (&#8377;)</div></div>
@ -818,21 +822,46 @@ function setExpiry(btn,exp){
var _CAT_COLOR={DANGER_SHORT:'#E74C3C',DEAD_WEIGHT:'#F5A623',UNDER_PRESSURE:'#E67E22',HEDGE:'#3498DB',WORKING:'#2ECC71'}; var _CAT_COLOR={DANGER_SHORT:'#E74C3C',DEAD_WEIGHT:'#F5A623',UNDER_PRESSURE:'#E67E22',HEDGE:'#3498DB',WORKING:'#2ECC71'};
var _CAT_EMOJI={DANGER_SHORT:'🔴',DEAD_WEIGHT:'🟡',UNDER_PRESSURE:'🟠',HEDGE:'🔵',WORKING:'🟢'}; var _CAT_EMOJI={DANGER_SHORT:'🔴',DEAD_WEIGHT:'🟡',UNDER_PRESSURE:'🟠',HEDGE:'🔵',WORKING:'🟢'};
var _RISK_COL={LOW:'var(--green)',MODERATE:'var(--amber)',HIGH:'#E67E22',CRITICAL:'var(--red)'}; var _RISK_COL={LOW:'var(--green)',MODERATE:'var(--amber)',HIGH:'#E67E22',CRITICAL:'var(--red)'};
var _curView='dashboard';
function showView(name){ function showView(name){
_curView=name;
document.querySelectorAll('[data-view]').forEach(function(el){el.style.display='none';}); document.querySelectorAll('[data-view]').forEach(function(el){el.style.display='none';});
var el=document.getElementById('view-'+name);if(el)el.style.display='block'; var el=document.getElementById('view-'+name);
if(el){el.style.display='block';el.style.visibility='visible';}
document.querySelectorAll('.nav-tab').forEach(function(t){t.classList.remove('active');}); document.querySelectorAll('.nav-tab').forEach(function(t){t.classList.remove('active');});
var tab=document.querySelector('.nav-tab[data-target="'+name+'"]');if(tab)tab.classList.add('active'); var tab=document.querySelector('.nav-tab[data-target="'+name+'"]');if(tab)tab.classList.add('active');
window.scrollTo(0,0);
if(name==='analysis')loadAnalysis(); if(name==='analysis')loadAnalysis();
} }
async function forceRefreshAnalysis(){
var btn=document.getElementById('a-refresh-btn');
if(btn){btn.textContent='Refreshing…';btn.disabled=true;}
try{
await fetch('/api/refresh',{method:'POST'});
}catch(e){}
await loadAnalysis();
if(btn){btn.textContent='↻ Refresh';btn.disabled=false;}
}
async function loadAnalysis(){ async function loadAnalysis(){
var tbody=document.getElementById('a-class-body');
var rBody=document.getElementById('a-risk-body');
var sBody=document.getElementById('a-scen-body');
try{ try{
var res=await fetch('/api/analysis').then(function(r){return r.json();}); var res=await fetch('/api/analysis').then(function(r){return r.json();});
if(!res.ok||!res.data)return; if(!res||!res.ok||!res.data){
if(tbody)tbody.innerHTML='<tr><td colspan="8" style="text-align:center;padding:36px;color:var(--text3)">No analysis data yet — click ↻ Refresh above to trigger a poll</td></tr>';
if(rBody)rBody.innerHTML='<div style="color:var(--text3);font-size:.8rem;padding:14px 20px">No data yet</div>';
if(sBody)sBody.innerHTML='<div style="color:var(--text3);font-size:.8rem;padding:14px 20px">No data yet</div>';
return;
}
renderAnalysis(res.data,res.asOf); renderAnalysis(res.data,res.asOf);
}catch(e){console.error('loadAnalysis:',e);} }catch(e){
console.error('loadAnalysis:',e);
if(tbody)tbody.innerHTML='<tr><td colspan="8" style="text-align:center;padding:36px;color:var(--red)">Error: '+(e&&e.message?e.message:String(e))+'</td></tr>';
}
} }
function renderAnalysis(d,asOf){ function renderAnalysis(d,asOf){
@ -932,13 +961,15 @@ function renderAnalysis(d,asOf){
return '<td class="mono" style="color:'+c+';font-weight:600">'+(pt.totalPnl>=0?'+':'')+'₹'+Math.round(pt.totalPnl).toLocaleString('en-IN')+'</td>';}).join('')+ return '<td class="mono" style="color:'+c+';font-weight:600">'+(pt.totalPnl>=0?'+':'')+'₹'+Math.round(pt.totalPnl).toLocaleString('en-IN')+'</td>';}).join('')+
'</tr></tbody></table></div></div>';}).join('');}} '</tr></tbody></table></div></div>';}).join('');}}
var asofEl=document.getElementById('a-asof'); var asofStr=asOf?'Updated: '+toIST(asOf):'';
if(asofEl&&asOf)asofEl.textContent='Updated: '+toIST(asOf); var asofEl=document.getElementById('a-asof');if(asofEl)asofEl.textContent=asofStr;
var asofTop=document.getElementById('a-asof-top');if(asofTop)asofTop.textContent=asofStr;
} }
/* ── End Analysis Tab ─────────────────────────────────────────────────── */ /* ── End Analysis Tab ─────────────────────────────────────────────────── */
loadConfig();refresh(); loadConfig();refresh();
setInterval(refresh,60000); setInterval(refresh,60000);
setInterval(loadMarket,15000); setInterval(loadMarket,15000);
setInterval(function(){if(_curView==='analysis')loadAnalysis();},30000);
</script> </script>
</body> </body>
</html> </html>