fix: atlas mixed-content, station footer URL, service card uptime+latency bar
- atlas: skip http:// health_url from https context - station: dashboard footer link → posimai.soar-enrich.com - station: service cards add uptime %, latency bar, updateLatencyBar fn Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
0bd747ebd2
commit
eb2d8877c5
|
|
@ -139,6 +139,12 @@
|
||||||
.svc-dot { width:5px;height:5px;border-radius:50%;background:var(--text3);opacity:0.25; }
|
.svc-dot { width:5px;height:5px;border-radius:50%;background:var(--text3);opacity:0.25; }
|
||||||
.svc-dot.ok { background:var(--ok); opacity:0.85; }
|
.svc-dot.ok { background:var(--ok); opacity:0.85; }
|
||||||
.svc-dot.crit { background:var(--crit); opacity:0.85; }
|
.svc-dot.crit { background:var(--crit); opacity:0.85; }
|
||||||
|
.service-uptime { font-family:'JetBrains Mono',monospace;font-size:10px;font-weight:600; }
|
||||||
|
.service-uptime.full { color:var(--ok); }
|
||||||
|
.service-uptime.partial { color:#FB923C; }
|
||||||
|
.service-uptime.down { color:var(--crit); }
|
||||||
|
.latency-bar-wrap { height:3px;border-radius:2px;background:rgba(255,255,255,0.07);overflow:hidden;margin-top:4px; }
|
||||||
|
.latency-bar { height:100%;border-radius:2px;transition:width 0.6s ease; }
|
||||||
|
|
||||||
/* stream */
|
/* stream */
|
||||||
#stream-feed { flex:1;overflow:hidden;display:flex;flex-direction:column;gap:0; }
|
#stream-feed { flex:1;overflow:hidden;display:flex;flex-direction:column;gap:0; }
|
||||||
|
|
@ -298,7 +304,7 @@
|
||||||
<div class="bottom-links">
|
<div class="bottom-links">
|
||||||
<a class="bottom-link" href="/" target="_blank" rel="noopener"><i data-lucide="terminal"></i>dev</a>
|
<a class="bottom-link" href="/" target="_blank" rel="noopener"><i data-lucide="terminal"></i>dev</a>
|
||||||
<a class="bottom-link" href="https://posimai-atlas.vercel.app" target="_blank" rel="noopener"><i data-lucide="network"></i>atlas</a>
|
<a class="bottom-link" href="https://posimai-atlas.vercel.app" target="_blank" rel="noopener"><i data-lucide="network"></i>atlas</a>
|
||||||
<a class="bottom-link" href="https://posimai-dashboard.vercel.app" target="_blank" rel="noopener"><i data-lucide="layout-dashboard"></i>dashboard</a>
|
<a class="bottom-link" href="https://posimai.soar-enrich.com" target="_blank" rel="noopener"><i data-lucide="layout-dashboard"></i>dashboard</a>
|
||||||
</div>
|
</div>
|
||||||
<div id="refresh-countdown">次の更新まで <span id="countdown">30</span>s</div>
|
<div id="refresh-countdown">次の更新まで <span id="countdown">30</span>s</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -440,11 +446,19 @@ function buildServiceCards(){
|
||||||
SERVICES.forEach(svc=>{
|
SERVICES.forEach(svc=>{
|
||||||
const card=document.createElement('div'); card.className='service-card'; card.id=`svc-${svc.id}`;
|
const card=document.createElement('div'); card.className='service-card'; card.id=`svc-${svc.id}`;
|
||||||
const dots=Array(5).fill(0).map((_,i)=>`<div class="svc-dot" id="dot-${svc.id}-${i}"></div>`).join('');
|
const dots=Array(5).fill(0).map((_,i)=>`<div class="svc-dot" id="dot-${svc.id}-${i}"></div>`).join('');
|
||||||
card.innerHTML=`<div class="service-card-top"><span class="service-name">${svc.name}</span><span class="service-badge checking" id="badge-${svc.id}">...</span></div><span class="service-desc">${svc.desc}</span><div class="service-footer"><div class="service-dots">${dots}</div><span class="service-latency" id="lat-${svc.id}"></span></div>`;
|
card.innerHTML=`<div class="service-card-top"><span class="service-name">${svc.name}</span><span class="service-badge checking" id="badge-${svc.id}">...</span></div><span class="service-desc">${svc.desc}</span><div class="latency-bar-wrap"><div class="latency-bar" id="lbar-${svc.id}" style="width:0%;background:var(--ok)"></div></div><div class="service-footer"><div class="service-dots">${dots}</div><span class="service-uptime" id="upt-${svc.id}"></span><span class="service-latency" id="lat-${svc.id}"></span></div>`;
|
||||||
grid.appendChild(card);
|
grid.appendChild(card);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateLatencyBar(id,ms){
|
||||||
|
const bar=document.getElementById(`lbar-${id}`); if(!bar)return;
|
||||||
|
if(ms===null){bar.style.width='100%';bar.style.background='var(--crit)';return;}
|
||||||
|
const w=ms<=50?100:ms<=200?80:ms<=500?55:35;
|
||||||
|
const color=ms<=200?'var(--ok)':ms<=500?'#FB923C':'var(--crit)';
|
||||||
|
bar.style.width=w+'%'; bar.style.background=color;
|
||||||
|
}
|
||||||
|
|
||||||
function pushSvcHistory(id,ok){
|
function pushSvcHistory(id,ok){
|
||||||
svcHist[id].push(ok); if(svcHist[id].length>5)svcHist[id].shift();
|
svcHist[id].push(ok); if(svcHist[id].length>5)svcHist[id].shift();
|
||||||
const h=svcHist[id];
|
const h=svcHist[id];
|
||||||
|
|
@ -453,6 +467,13 @@ function pushSvcHistory(id,ok){
|
||||||
const idx=i-(5-h.length); if(idx<0){dot.className='svc-dot';continue;}
|
const idx=i-(5-h.length); if(idx<0){dot.className='svc-dot';continue;}
|
||||||
dot.className='svc-dot '+(h[idx]?'ok':'crit');
|
dot.className='svc-dot '+(h[idx]?'ok':'crit');
|
||||||
}
|
}
|
||||||
|
// 稼働率表示
|
||||||
|
const uptEl=document.getElementById(`upt-${id}`);
|
||||||
|
if(uptEl&&h.length>0){
|
||||||
|
const pct=Math.round(h.filter(Boolean).length/h.length*100);
|
||||||
|
uptEl.textContent=`${pct}%`;
|
||||||
|
uptEl.className='service-uptime '+(pct===100?'full':pct>=60?'partial':'down');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkService(svc){
|
async function checkService(svc){
|
||||||
|
|
@ -462,20 +483,23 @@ async function checkService(svc){
|
||||||
try{
|
try{
|
||||||
const ctrl=new AbortController(),timer=setTimeout(()=>ctrl.abort(),7000);
|
const ctrl=new AbortController(),timer=setTimeout(()=>ctrl.abort(),7000);
|
||||||
if(svc.proxy){
|
if(svc.proxy){
|
||||||
// サーバー経由プロキシチェック(mixed-content 回避)
|
|
||||||
const r=await fetch(svc.url,{signal:ctrl.signal});
|
const r=await fetch(svc.url,{signal:ctrl.signal});
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
const data=await r.json();
|
const data=await r.json();
|
||||||
const ok=data.ok||(data.status&&data.status<500);
|
const ok=data.ok||(data.status&&data.status<500);
|
||||||
|
const ms=data.latency_ms||0;
|
||||||
badge.className='service-badge '+(ok?'ok':'crit');
|
badge.className='service-badge '+(ok?'ok':'crit');
|
||||||
badge.textContent=ok?'OK':'DOWN';
|
badge.textContent=ok?'OK':'DOWN';
|
||||||
latEl.textContent=data.latency_ms?`${data.latency_ms}ms`:'';
|
latEl.textContent=ms?`${ms}ms`:'';
|
||||||
|
updateLatencyBar(svc.id,ok?ms:null);
|
||||||
pushSvcHistory(svc.id,!!ok);
|
pushSvcHistory(svc.id,!!ok);
|
||||||
}else{
|
}else{
|
||||||
await fetch(svc.url,{method:'HEAD',mode:'no-cors',signal:ctrl.signal});
|
await fetch(svc.url,{method:'HEAD',mode:'no-cors',signal:ctrl.signal});
|
||||||
clearTimeout(timer);
|
clearTimeout(timer);
|
||||||
|
const ms=Date.now()-t0;
|
||||||
badge.className='service-badge ok'; badge.textContent='OK';
|
badge.className='service-badge ok'; badge.textContent='OK';
|
||||||
latEl.textContent=`${Date.now()-t0}ms`;
|
latEl.textContent=`${ms}ms`;
|
||||||
|
updateLatencyBar(svc.id,ms);
|
||||||
pushSvcHistory(svc.id,true);
|
pushSvcHistory(svc.id,true);
|
||||||
}
|
}
|
||||||
}catch(e){
|
}catch(e){
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue