fix: remove duplicate JS block causing SyntaxError in dashboard
This commit is contained in:
@@ -722,189 +722,6 @@ function closeDetail(){
|
||||
q('ne').querySelectorAll('.net-row').forEach(function(r){r.classList.remove('selected');});
|
||||
}
|
||||
// ---- Shared ----
|
||||
function filter(listId,filterId){
|
||||
var f=q(filterId).value.toLowerCase();
|
||||
q(listId).querySelectorAll('.log-+e).toISOString().slice(11,23)}
|
||||
function q(id){return document.getElementById(id)}
|
||||
function loadHistory(){
|
||||
fetch('/logs').then(function(r){return r.json();}).then(function(a){a.forEach(function(e){addLog(e,false);});});
|
||||
fetch('/network').then(function(r){return r.json();}).then(function(a){a.forEach(function(e){addNet(e,false);});});
|
||||
}
|
||||
function startSSE(){
|
||||
var es=new EventSource('/events');
|
||||
es.onopen=function(){q('dot').textContent='● connected';q('dot').className='on';};
|
||||
es.onerror=function(){q('dot').textContent='● disconnected';q('dot').className='off';};
|
||||
es.addEventListener('log',function(e){addLog(JSON.parse(e.data),true);});
|
||||
es.addEventListener('network',function(e){addNet(JSON.parse(e.data),true);});
|
||||
es.addEventListener('network_update',function(e){updateNet(JSON.parse(e.data));});
|
||||
}
|
||||
// ---- Logs ----
|
||||
function addLog(e,live){
|
||||
lc++;
|
||||
var el=document.createElement('div');
|
||||
el.className='log-row '+(e.level||'I');
|
||||
el.textContent='['+ts(e.ts)+'] '+(e.level||'I')+' '+(e.tag||'')+': '+(e.msg||'');
|
||||
el.dataset.t=el.textContent.toLowerCase();
|
||||
applyLogFilter(el);
|
||||
q('le').appendChild(el);
|
||||
if(live&&q('ls').checked)el.scrollIntoView();
|
||||
upd();
|
||||
}
|
||||
function applyLogFilter(el){
|
||||
var f=q('lf').value.toLowerCase();
|
||||
el.style.display=(!f||el.dataset.t.includes(f))?'':'none';
|
||||
}
|
||||
// ---- Network rows ----
|
||||
function methodClass(m){return m||'GET';}
|
||||
function statusSpan(e){
|
||||
if(!e.done)return '<span class="status-pend">…</span>';
|
||||
if(e.status&&e.status>=400)return '<span class="status-err">'+e.status+'</span>';
|
||||
return '<span class="status-ok">'+(e.status||'ok')+'</span>';
|
||||
}
|
||||
function sizeStr(bytes){
|
||||
if(bytes==null)return '';
|
||||
if(bytes<1024)return bytes+'B';
|
||||
return (bytes/1024).toFixed(1)+'K';
|
||||
}
|
||||
function addNet(e,live){
|
||||
nc++;
|
||||
netMap[e.id]=e;
|
||||
var el=document.createElement('div');
|
||||
el.className='net-row';
|
||||
el.id='nr-'+e.id;
|
||||
el.dataset.t=(e.uri||'').toLowerCase();
|
||||
el.innerHTML='<span class="badge '+methodClass(e.method)+'">'+(e.method||'?')+'</span>'+
|
||||
statusSpan(e)+
|
||||
'<span class="net-uri">'+(e.uri||'')+'</span>'+
|
||||
'<span class="net-size" id="ns-'+e.id+'">'+(e.resSize!=null?sizeStr(e.resSize):'')+'</span>';
|
||||
el.onclick=function(){openDetail(e.id);};
|
||||
applyNetFilter(el);
|
||||
q('ne').appendChild(el);
|
||||
if(live&&q('ns').checked)el.scrollIntoView();
|
||||
upd();
|
||||
}
|
||||
function updateNet(e){
|
||||
netMap[e.id]=Object.assign(netMap[e.id]||{},e);
|
||||
var row=q('nr-'+e.id);
|
||||
if(!row)return;
|
||||
var m=netMap[e.id];
|
||||
row.innerHTML='<span class="badge '+methodClass(m.method)+'">'+(m.method||'?')+'</span>'+
|
||||
statusSpan(m)+
|
||||
'<span class="net-uri">'+(m.uri||'')+'</span>'+
|
||||
'<span class="net-size" id="ns-'+m.id+'">'+(m.resSize!=null?sizeStr(m.resSize):'')+'</span>';
|
||||
row.onclick=function(){openDetail(m.id);};
|
||||
if(detailId===e.id)refreshDetail();
|
||||
}
|
||||
function applyNetFilter(el){
|
||||
var f=q('nf').value.toLowerCase();
|
||||
el.style.display=(!f||el.dataset.t.includes(f))?'':'none';
|
||||
}
|
||||
function filterNet(){
|
||||
q('ne').querySelectorAll('.net-row').forEach(applyNetFilter);
|
||||
}
|
||||
// ---- Detail panel ----
|
||||
function openDetail(id){
|
||||
detailId=id;
|
||||
detailFull=null;
|
||||
var sum=netMap[id];
|
||||
if(!sum)return;
|
||||
q('detail').style.display='flex';
|
||||
q('ne').querySelectorAll('.net-row').forEach(function(r){r.classList.remove('selected');});
|
||||
var row=q('nr-'+id);
|
||||
if(row)row.classList.add('selected');
|
||||
renderDetailMeta(sum);
|
||||
q('d-body').textContent='Loading…';
|
||||
fetch('/network/'+id).then(function(r){return r.json();}).then(function(full){
|
||||
detailFull=full;
|
||||
renderDetailMeta(full);
|
||||
renderBody();
|
||||
}).catch(function(){q('d-body').textContent='Failed to load details.';});
|
||||
}
|
||||
function refreshDetail(){
|
||||
if(!detailId)return;
|
||||
var sum=netMap[detailId];
|
||||
if(!sum)return;
|
||||
renderDetailMeta(sum);
|
||||
if(detailFull)renderBody();
|
||||
}
|
||||
function renderDetailMeta(e){
|
||||
var m=e.method||'?';
|
||||
q('d-badge').className='badge '+methodClass(m);
|
||||
q('d-badge').textContent=m;
|
||||
q('d-badge').style.cssText='';
|
||||
q('d-status').textContent=e.status||(e.done?'ok':'…');
|
||||
q('d-status').className=e.status&&e.status>=400?'status-err':'status-ok';
|
||||
q('d-uri').textContent=e.uri||'';
|
||||
}
|
||||
function showTab(tab){
|
||||
detailTab=tab;
|
||||
q('tab-req').className='tab-btn'+(tab==='req'?' active':'');
|
||||
q('tab-res').className='tab-btn'+(tab==='res'?' active':'');
|
||||
renderBody();
|
||||
}
|
||||
function toggleHex(){
|
||||
hexMode=!hexMode;
|
||||
q('btn-hex').className='tab-btn'+(hexMode?' active':'');
|
||||
renderBody();
|
||||
}
|
||||
function renderBody(){
|
||||
if(!detailFull){q('d-body').textContent='Loading…';return;}
|
||||
var b64=detailTab==='res'?detailFull.resBody:detailFull.reqBody;
|
||||
if(!b64){q('d-body').textContent='(empty)';return;}
|
||||
var truncated=b64.endsWith('==TRUNCATED==');
|
||||
if(truncated)b64=b64.slice(0,b64.length-13);
|
||||
var bytes=b64ToBytes(b64);
|
||||
var suffix=truncated?'\n\n[truncated at 48 KB]':'';
|
||||
if(hexMode){q('d-body').textContent=hexDump(bytes)+suffix;return;}
|
||||
var text=tryUtf8(bytes);
|
||||
if(text){
|
||||
var pretty=tryJsonPretty(text);
|
||||
q('d-body').textContent=(pretty||text)+suffix;
|
||||
}else{
|
||||
q('d-body').textContent=hexDump(bytes)+suffix;
|
||||
}
|
||||
}
|
||||
function b64ToBytes(b64){
|
||||
var bin=atob(b64),bytes=new Uint8Array(bin.length);
|
||||
for(var i=0;i<bin.length;i++)bytes[i]=bin.charCodeAt(i);
|
||||
return bytes;
|
||||
}
|
||||
function tryUtf8(bytes){
|
||||
try{
|
||||
var text=new TextDecoder('utf-8',{fatal:true}).decode(bytes);
|
||||
var printable=0;
|
||||
for(var i=0;i<Math.min(text.length,200);i++){var c=text.charCodeAt(i);if(c>=32||c===10||c===13||c===9)printable++;}
|
||||
return(printable/Math.min(text.length,200))>0.85?text:null;
|
||||
}catch(e){return null;}
|
||||
}
|
||||
function tryJsonPretty(text){
|
||||
try{return JSON.stringify(JSON.parse(text),null,2);}catch(e){return null;}
|
||||
}
|
||||
function hexDump(bytes){
|
||||
var lines=[];
|
||||
for(var i=0;i<bytes.length;i+=16){
|
||||
var chunk=Array.from(bytes.slice(i,i+16));
|
||||
var hex=chunk.map(function(b){return b.toString(16).padStart(2,'0');}).join(' ');
|
||||
var asc=chunk.map(function(b){return b>=32&&b<127?String.fromCharCode(b):'.';}).join('');
|
||||
lines.push(i.toString(16).padStart(8,'0')+' '+hex.padEnd(48)+' '+asc);
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
function copyBody(){
|
||||
if(!detailFull)return;
|
||||
var b64=detailTab==='res'?detailFull.resBody:detailFull.reqBody;
|
||||
if(!b64)return;
|
||||
if(b64.endsWith('==TRUNCATED=='))b64=b64.slice(0,b64.length-13);
|
||||
var text=tryUtf8(b64ToBytes(b64))||b64;
|
||||
navigator.clipboard&&navigator.clipboard.writeText(text);
|
||||
}
|
||||
function closeDetail(){
|
||||
detailId=null;
|
||||
detailFull=null;
|
||||
q('detail').style.display='none';
|
||||
q('ne').querySelectorAll('.net-row').forEach(function(r){r.classList.remove('selected');});
|
||||
}
|
||||
// ---- Shared ----
|
||||
function filter(listId,filterId){
|
||||
var f=q(filterId).value.toLowerCase();
|
||||
q(listId).querySelectorAll('.log-row').forEach(function(el){
|
||||
|
||||
Reference in New Issue
Block a user