feat: add VPS panel (5-column layout), real-time VPS metrics from api.soar-enrich.com
This commit is contained in:
parent
8d9f4e22b0
commit
5cbf66d613
|
|
@ -70,7 +70,7 @@
|
||||||
#date { font-size:12px;color:var(--text3);margin-top:3px;letter-spacing:0.06em; }
|
#date { font-size:12px;color:var(--text3);margin-top:3px;letter-spacing:0.06em; }
|
||||||
#last-checked { text-align:right;font-size:11px;color:var(--text3); }
|
#last-checked { text-align:right;font-size:11px;color:var(--text3); }
|
||||||
|
|
||||||
#middle { display:grid;grid-template-columns:270px 280px 1fr 196px;gap:12px;min-height:0; }
|
#middle { display:grid;grid-template-columns:220px 200px 240px 1fr 180px;gap:10px;min-height:0; }
|
||||||
|
|
||||||
.metric-item { display:flex;flex-direction:column;gap:5px;flex-shrink:0; }
|
.metric-item { display:flex;flex-direction:column;gap:5px;flex-shrink:0; }
|
||||||
.metric-header-row { display:flex;justify-content:space-between;align-items:baseline; }
|
.metric-header-row { display:flex;justify-content:space-between;align-items:baseline; }
|
||||||
|
|
@ -225,7 +225,28 @@
|
||||||
</div>
|
</div>
|
||||||
<a class="open-btn" href="/" target="_blank" rel="noopener"><i data-lucide="terminal"></i>posimai-dev を開く</a>
|
<a class="open-btn" href="/" target="_blank" rel="noopener"><i data-lucide="terminal"></i>posimai-dev を開く</a>
|
||||||
</div>
|
</div>
|
||||||
<!-- Col 2: rings + sparkline -->
|
<!-- Col 2: VPS -->
|
||||||
|
<div class="panel">
|
||||||
|
<div class="panel-title"><i data-lucide="server"></i>VPS</div>
|
||||||
|
<div class="metric-item">
|
||||||
|
<div class="metric-header-row"><span class="metric-label">CPU Load</span><span class="metric-val" id="vps-load">—</span></div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-item">
|
||||||
|
<div class="metric-header-row"><span class="metric-label">Memory</span><span class="metric-val" id="vps-mem">—</span></div>
|
||||||
|
<div class="bin-bar" id="vps-mem-bar"></div>
|
||||||
|
</div>
|
||||||
|
<div class="metric-item">
|
||||||
|
<div class="metric-header-row"><span class="metric-label">Disk (/)</span><span class="metric-val" id="vps-disk">—</span></div>
|
||||||
|
<div class="bin-bar" id="vps-disk-bar"></div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-grid" style="grid-template-columns:1fr 1fr;gap:6px;margin-top:4px">
|
||||||
|
<div class="stat-card"><div class="stat-label">Uptime</div><div class="stat-val" id="vps-uptime">—</div></div>
|
||||||
|
<div class="stat-card"><div class="stat-label">Users</div><div class="stat-val" id="vps-users">—</div></div>
|
||||||
|
<div class="stat-card"><div class="stat-label">Gemini</div><div class="stat-val" id="vps-gemini">—</div></div>
|
||||||
|
<div class="stat-card"><div class="stat-label">Node</div><div class="stat-val" id="vps-node">—</div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Col 3: rings + sparkline -->
|
||||||
<div class="panel rings-panel">
|
<div class="panel rings-panel">
|
||||||
<div class="panel-title"><i data-lucide="activity"></i>Vitals</div>
|
<div class="panel-title"><i data-lucide="activity"></i>Vitals</div>
|
||||||
<div class="ring-group">
|
<div class="ring-group">
|
||||||
|
|
@ -681,7 +702,35 @@ function timeAgo(iso){
|
||||||
return `${Math.floor(diff/1440)}d ago`;
|
return `${Math.floor(diff/1440)}d ago`;
|
||||||
}
|
}
|
||||||
fetchGiteaCommit();
|
fetchGiteaCommit();
|
||||||
setInterval(fetchGiteaCommit, 120000); // 2分ごと
|
setInterval(fetchGiteaCommit, 120000);
|
||||||
|
|
||||||
|
// ── VPS メトリクス ─────────────────────────────────────────────
|
||||||
|
async function fetchVpsHealth(){
|
||||||
|
try{
|
||||||
|
const r=await fetch('https://api.soar-enrich.com/api/health',{signal:AbortSignal.timeout(6000)});
|
||||||
|
const d=await r.json();
|
||||||
|
const memPct=d.mem_total_mb?Math.round(d.mem_used_mb/d.mem_total_mb*100):0;
|
||||||
|
const diskPct=d.disk?.use_pct??0;
|
||||||
|
document.getElementById('vps-load').textContent=d.load_avg?`${d.load_avg[0]} / ${d.load_avg[1]}`:'—';
|
||||||
|
document.getElementById('vps-mem').textContent=d.mem_total_mb?`${d.mem_used_mb}/${d.mem_total_mb}MB (${memPct}%)`:'—';
|
||||||
|
renderBinBar('vps-mem-bar',memPct,65,85);
|
||||||
|
if(d.disk){
|
||||||
|
document.getElementById('vps-disk').textContent=`${d.disk.used_gb}/${d.disk.total_gb}GB (${diskPct}%)`;
|
||||||
|
renderBinBar('vps-disk-bar',diskPct,75,90);
|
||||||
|
}
|
||||||
|
document.getElementById('vps-uptime').textContent=formatUptime(d.uptime_s||0);
|
||||||
|
document.getElementById('vps-users').textContent=String(d.users??'—');
|
||||||
|
const gemEl=document.getElementById('vps-gemini');
|
||||||
|
gemEl.textContent=d.gemini?'ON':'OFF';
|
||||||
|
gemEl.style.color=d.gemini?'var(--ok)':'var(--crit)';
|
||||||
|
document.getElementById('vps-node').textContent=(d.node_version||'—').replace('v','');
|
||||||
|
}catch(e){
|
||||||
|
['vps-load','vps-mem','vps-disk','vps-uptime','vps-users','vps-gemini','vps-node']
|
||||||
|
.forEach(id=>{ const el=document.getElementById(id); if(el) el.textContent='ERR'; });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fetchVpsHealth();
|
||||||
|
setInterval(fetchVpsHealth, 30000);
|
||||||
|
|
||||||
// ── キーボードショートカット ────────────────────────────────────
|
// ── キーボードショートカット ────────────────────────────────────
|
||||||
document.addEventListener('keydown', e => {
|
document.addEventListener('keydown', e => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue