From eb2d8877c59ad4d56ab22c1fb6bf39365144a222 Mon Sep 17 00:00:00 2001 From: posimai Date: Tue, 31 Mar 2026 21:42:58 +0900 Subject: [PATCH] fix: atlas mixed-content, station footer URL, service card uptime+latency bar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- posimai-dev/station.html | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/posimai-dev/station.html b/posimai-dev/station.html index 059ab7aa..d1f8fad4 100644 --- a/posimai-dev/station.html +++ b/posimai-dev/station.html @@ -139,6 +139,12 @@ .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.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-feed { flex:1;overflow:hidden;display:flex;flex-direction:column;gap:0; } @@ -298,7 +304,7 @@
次の更新まで 30s
@@ -440,11 +446,19 @@ function buildServiceCards(){ SERVICES.forEach(svc=>{ const card=document.createElement('div'); card.className='service-card'; card.id=`svc-${svc.id}`; const dots=Array(5).fill(0).map((_,i)=>`
`).join(''); - card.innerHTML=`
${svc.name}...
${svc.desc}`; + card.innerHTML=`
${svc.name}...
${svc.desc}
`; 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){ svcHist[id].push(ok); if(svcHist[id].length>5)svcHist[id].shift(); 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;} 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){ @@ -462,20 +483,23 @@ async function checkService(svc){ try{ const ctrl=new AbortController(),timer=setTimeout(()=>ctrl.abort(),7000); if(svc.proxy){ - // サーバー経由プロキシチェック(mixed-content 回避) const r=await fetch(svc.url,{signal:ctrl.signal}); clearTimeout(timer); const data=await r.json(); const ok=data.ok||(data.status&&data.status<500); + const ms=data.latency_ms||0; badge.className='service-badge '+(ok?'ok':'crit'); 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); }else{ await fetch(svc.url,{method:'HEAD',mode:'no-cors',signal:ctrl.signal}); clearTimeout(timer); + const ms=Date.now()-t0; 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); } }catch(e){