Ghaymah SRE exam submission - Mohamed Adel

هذا الالتزام موجود في:
amohamedadel29
2026-07-28 03:54:42 +03:00
التزام 9bf0dfa0e8
18 ملفات معدلة مع 1184 إضافات و0 حذوفات

عرض الملف

@@ -0,0 +1,212 @@
<!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 SRE Exam</title>
<style>
:root{
--bg:#0b0f0d;
--panel:#101512;
--line:#1e2a24;
--amber:#ffb454;
--green:#5fd88a;
--red:#ff6b6b;
--text:#d7e0da;
--dim:#7c8f85;
--mono: "IBM Plex Mono","SFMono-Regular",Consolas,monospace;
}
*{box-sizing:border-box;}
body{
margin:0;
background:
radial-gradient(circle at 20% -10%, #142019 0%, transparent 60%),
var(--bg);
color:var(--text);
font-family:var(--mono);
padding:28px 20px 60px;
direction:rtl;
}
.wrap{max-width:980px;margin:0 auto;}
header{
display:flex;justify-content:space-between;align-items:flex-end;
border-bottom:1px solid var(--line);
padding-bottom:16px;margin-bottom:22px;flex-wrap:wrap;gap:10px;
}
h1{font-size:20px;margin:0;font-weight:600;letter-spacing:.5px;}
h1 span{color:var(--green);}
.sub{color:var(--dim);font-size:12px;margin-top:4px;}
.controls{display:flex;gap:8px;align-items:center;}
input[type=text]{
background:var(--panel);border:1px solid var(--line);color:var(--text);
padding:8px 10px;border-radius:6px;font-family:var(--mono);font-size:12px;width:260px;
}
button{
background:var(--green);color:#04150a;border:none;border-radius:6px;
padding:8px 14px;font-family:var(--mono);font-weight:600;font-size:12px;cursor:pointer;
}
button:hover{filter:brightness(1.08);}
.grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-bottom:20px;}
@media(max-width:760px){.grid{grid-template-columns:1fr;}}
.card{
background:var(--panel);border:1px solid var(--line);border-radius:10px;
padding:18px;position:relative;overflow:hidden;
}
.card .label{color:var(--dim);font-size:11px;text-transform:uppercase;letter-spacing:1px;}
.card .value{font-size:30px;font-weight:700;margin-top:8px;}
.status-up{color:var(--green);}
.status-down{color:var(--red);}
.dot{display:inline-block;width:9px;height:9px;border-radius:50%;margin-left:8px;}
.dot.up{background:var(--green);box-shadow:0 0 8px var(--green);}
.dot.down{background:var(--red);box-shadow:0 0 8px var(--red);}
.panel{
background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:18px;margin-bottom:16px;
}
.panel h2{font-size:13px;color:var(--dim);text-transform:uppercase;letter-spacing:1px;margin:0 0 14px;}
#chart{width:100%;height:160px;display:block;}
table{width:100%;border-collapse:collapse;font-size:12px;}
th,td{text-align:right;padding:8px 6px;border-bottom:1px solid var(--line);}
th{color:var(--dim);font-weight:500;}
.pill{padding:2px 8px;border-radius:20px;font-size:11px;font-weight:600;}
.pill.up{background:rgba(95,216,138,.12);color:var(--green);}
.pill.down{background:rgba(255,107,107,.12);color:var(--red);}
footer{color:var(--dim);font-size:11px;text-align:center;margin-top:30px;}
</style>
</head>
<body>
<div class="wrap">
<header>
<div>
<h1>لوحة <span>مراقبة</span> التطبيق</h1>
<div class="sub">Ghaymah SRE Exam — Q1 · يقرأ من /metrics و /health كل 5 ثوانٍ</div>
</div>
<div class="controls">
<input type="text" id="apiUrl" placeholder="https://your-app.ghaymah.systems" value="https://ghaymah-exam-app-06b532d0a81b.hosted.ghaymah.systems">
<button onclick="setUrl()">اتصال</button>
</div>
</header>
<div class="grid">
<div class="card">
<div class="label">الحالة</div>
<div class="value" id="statusValue"><span class="dot up"></span><span id="statusText">جاري التحميل...</span></div>
</div>
<div class="card">
<div class="label">زمن الاستجابة</div>
<div class="value" id="latencyValue"></div>
</div>
<div class="card">
<div class="label">عدد الطلبات</div>
<div class="value" id="requestsValue"></div>
</div>
</div>
<div class="panel">
<h2>زمن الاستجابة — آخر 20 فحص</h2>
<svg id="chart" viewBox="0 0 900 160" preserveAspectRatio="none"></svg>
</div>
<div class="panel">
<h2>سجل الفحوصات</h2>
<table>
<thead><tr><th>الوقت</th><th>الحالة</th><th>زمن الاستجابة</th></tr></thead>
<tbody id="logBody"></tbody>
</table>
</div>
<footer>يعمل الفحص كل 5 ثوانٍ في المتصفح · مصدر البيانات: نفس تطبيق Q1 (endpoint: /metrics)</footer>
</div>
<script>
let API_URL = "";
let history = []; // {t, ok, ms}
const MAX_POINTS = 20;
function setUrl(){
API_URL = document.getElementById('apiUrl').value.trim().replace(/\/$/, '');
history = [];
poll();
}
function fmtTime(d){
return d.toLocaleTimeString('ar-EG', {hour:'2-digit', minute:'2-digit', second:'2-digit'});
}
async function poll(){
const statusText = document.getElementById('statusText');
const statusValue = document.getElementById('statusValue');
const latencyValue = document.getElementById('latencyValue');
const requestsValue = document.getElementById('requestsValue');
if(!API_URL){
statusText.textContent = "أدخل رابط التطبيق فوق";
return;
}
const t0 = performance.now();
let ok = false, ms = 0, reqCount = '—';
try{
const res = await fetch(API_URL + '/metrics', {cache:'no-store'});
ms = Math.round(performance.now() - t0);
if(res.ok){
const data = await res.json();
ok = true;
reqCount = data.request_count ?? '—';
}
}catch(e){
ms = Math.round(performance.now() - t0);
ok = false;
}
statusValue.innerHTML = `<span class="dot ${ok?'up':'down'}"></span><span class="${ok?'status-up':'status-down'}">${ok?'يعمل':'متوقف'}</span>`;
latencyValue.textContent = ms + ' ms';
requestsValue.textContent = reqCount;
const now = new Date();
history.push({t: now, ok, ms});
if(history.length > MAX_POINTS) history.shift();
drawChart();
drawLog();
setTimeout(poll, 5000);
}
function drawChart(){
const svg = document.getElementById('chart');
if(history.length < 2){ svg.innerHTML=''; return; }
const w = 900, h = 160, pad = 10;
const maxMs = Math.max(...history.map(p=>p.ms), 50);
const step = (w - pad*2) / (MAX_POINTS - 1);
let points = history.map((p,i)=>{
const x = pad + i*step;
const y = h - pad - ((p.ms / maxMs) * (h - pad*2));
return `${x},${y}`;
}).join(' ');
svg.innerHTML = `
<polyline fill="none" stroke="#5fd88a" stroke-width="2" points="${points}" />
${history.map((p,i)=>{
const x = pad + i*step;
const y = h - pad - ((p.ms / maxMs) * (h - pad*2));
return `<circle cx="${x}" cy="${y}" r="3" fill="${p.ok?'#5fd88a':'#ff6b6b'}" />`;
}).join('')}
`;
}
function drawLog(){
const body = document.getElementById('logBody');
body.innerHTML = history.slice().reverse().slice(0,10).map(p=>`
<tr>
<td>${fmtTime(p.t)}</td>
<td><span class="pill ${p.ok?'up':'down'}">${p.ok?'UP':'DOWN'}</span></td>
<td>${p.ms} ms</td>
</tr>
`).join('');
}
// Auto-connect on load using the pre-filled deployed URL
window.addEventListener('DOMContentLoaded', setUrl);
</script>
</body>
</html>