الملفات
ghaymah-exam--Yousifhamdyam…/q1-deploy-monitor/dashboard.html

99 أسطر
4.1 KiB
HTML

<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ghaymah App Dashboard</title>
<style>
:root{
--bg:#0b0f14; --card:#121821; --line:#212a36;
--ok:#22c55e; --bad:#ef4444; --text:#e6edf3; --muted:#8b98a8; --accent:#3b82f6;
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--text);font-family:-apple-system,Segoe UI,Tahoma,Arial,sans-serif;padding:24px}
h1{font-size:20px;margin:0 0 20px}
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px;margin-bottom:20px}
.card{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:18px}
.label{color:var(--muted);font-size:13px;margin-bottom:8px}
.value{font-size:28px;font-weight:700}
.status-dot{display:inline-block;width:12px;height:12px;border-radius:50%;margin-left:8px}
.up{background:var(--ok)} .down{background:var(--bad)}
table{width:100%;border-collapse:collapse;background:var(--card);border:1px solid var(--line);border-radius:12px;overflow:hidden}
th,td{padding:10px 14px;text-align:right;border-bottom:1px solid var(--line);font-size:13px}
th{color:var(--muted);font-weight:600}
tr:last-child td{border-bottom:none}
.pill{padding:2px 8px;border-radius:6px;font-size:12px}
.pill.ok{background:rgba(34,197,94,.15);color:var(--ok)}
.pill.bad{background:rgba(239,68,68,.15);color:var(--bad)}
.footer{color:var(--muted);font-size:12px;margin-top:14px}
</style>
</head>
<body>
<h1>📊 لوحة مراقبة التطبيق — myapp.ghaymah.systems</h1>
<div class="grid">
<div class="card">
<div class="label">الحالة الحالية</div>
<div class="value" id="statusValue">--<span class="status-dot" id="statusDot"></span></div>
</div>
<div class="card">
<div class="label">آخر زمن استجابة</div>
<div class="value" id="latencyValue">-- ms</div>
</div>
<div class="card">
<div class="label">إجمالي الطلبات</div>
<div class="value" id="requestsValue">--</div>
</div>
<div class="card">
<div class="label">آخر تحديث</div>
<div class="value" id="lastCheckValue" style="font-size:16px">--</div>
</div>
</div>
<table>
<thead>
<tr><th>الوقت</th><th>الحالة</th><th>Status Code</th><th>زمن الاستجابة (ms)</th></tr>
</thead>
<tbody id="historyBody"></tbody>
</table>
<div class="footer">يقرأ هذا الـ dashboard البيانات من <code>status.json</code> الذي يولّده <code>health-check.sh</code>. يُحدَّث تلقائياً كل 15 ثانية.</div>
<script>
const STATE_URL = "status.json"; // same-origin file written by health-check.sh
const POLL_MS = 15000;
async function refresh() {
try {
const res = await fetch(STATE_URL + "?_=" + Date.now(), { cache: "no-store" });
const data = await res.json();
const last = data.last_check || (data.history || []).slice(-1)[0];
if (!last) return;
document.getElementById("statusValue").innerHTML =
(last.healthy ? "متصل" : "متعطل") +
`<span class="status-dot ${last.healthy ? "up" : "down"}"></span>`;
document.getElementById("latencyValue").textContent = `${last.latency_ms.toFixed(0)} ms`;
document.getElementById("requestsValue").textContent = last.request_count ?? "--";
document.getElementById("lastCheckValue").textContent = new Date(last.timestamp).toLocaleString("ar-EG");
const rows = (data.history || []).slice(-10).reverse().map(h => `
<tr>
<td>${new Date(h.timestamp).toLocaleTimeString("ar-EG")}</td>
<td><span class="pill ${h.healthy ? "ok" : "bad"}">${h.healthy ? "OK" : "FAIL"}</span></td>
<td>${h.status_code}</td>
<td>${h.latency_ms.toFixed(0)}</td>
</tr>`).join("");
document.getElementById("historyBody").innerHTML = rows;
} catch (e) {
document.getElementById("statusValue").innerHTML = `تعذر التحميل<span class="status-dot down"></span>`;
console.error(e);
}
}
refresh();
setInterval(refresh, POLL_MS);
</script>
</body>
</html>