last_edit / frontend /status.html
Alinabil1's picture
feat: add system status page and full test script
7646e5b
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>حالة النظام - Moharek</title>
<link href="https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;700;800&display=swap" rel="stylesheet">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Cairo', sans-serif;
background: linear-gradient(135deg, #071f21 0%, #0F4246 100%);
color: #fff;
min-height: 100vh;
padding: 40px 20px;
}
.container {
max-width: 1200px;
margin: 0 auto;
}
h1 {
font-size: 48px;
font-weight: 900;
text-align: center;
margin-bottom: 20px;
background: linear-gradient(135deg, #c8f04e, #5fd4dc);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.subtitle {
text-align: center;
color: rgba(255,255,255,0.7);
margin-bottom: 60px;
font-size: 18px;
}
.section {
background: rgba(255,255,255,0.05);
border: 1px solid rgba(255,255,255,0.1);
border-radius: 24px;
padding: 32px;
margin-bottom: 32px;
backdrop-filter: blur(10px);
}
.section h2 {
font-size: 28px;
margin-bottom: 24px;
color: #c8f04e;
}
.route-list {
display: grid;
gap: 16px;
}
.route-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px 20px;
background: rgba(0,0,0,0.2);
border-radius: 12px;
border: 1px solid rgba(255,255,255,0.05);
transition: all 0.3s;
}
.route-item:hover {
background: rgba(255,255,255,0.08);
border-color: #c8f04e;
}
.route-info {
flex: 1;
}
.route-name {
font-size: 18px;
font-weight: 700;
margin-bottom: 4px;
}
.route-url {
font-size: 14px;
color: rgba(255,255,255,0.5);
font-family: monospace;
}
.route-status {
padding: 8px 16px;
border-radius: 100px;
font-size: 14px;
font-weight: 700;
}
.status-checking {
background: rgba(251,191,36,0.2);
color: #fbbf24;
}
.status-online {
background: rgba(74,222,128,0.2);
color: #4ade80;
}
.status-offline {
background: rgba(239,68,68,0.2);
color: #ef4444;
}
.btn {
display: inline-block;
padding: 14px 32px;
background: #c8f04e;
color: #071f21;
text-decoration: none;
border-radius: 100px;
font-weight: 800;
font-size: 16px;
transition: all 0.3s;
margin: 8px;
}
.btn:hover {
transform: scale(1.05);
box-shadow: 0 8px 24px rgba(200,240,78,0.4);
}
.actions {
text-align: center;
margin-top: 40px;
}
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 40px;
}
.stat-card {
background: rgba(255,255,255,0.05);
border: 1px solid rgba(255,255,255,0.1);
border-radius: 16px;
padding: 24px;
text-align: center;
}
.stat-value {
font-size: 36px;
font-weight: 900;
color: #c8f04e;
margin-bottom: 8px;
}
.stat-label {
font-size: 14px;
color: rgba(255,255,255,0.6);
}
</style>
</head>
<body>
<div class="container">
<h1>🚀 حالة نظام محرك</h1>
<p class="subtitle">Moharek GEO Platform - System Status</p>
<div class="stats">
<div class="stat-card">
<div class="stat-value" id="totalRoutes">0</div>
<div class="stat-label">إجمالي المسارات</div>
</div>
<div class="stat-card">
<div class="stat-value" id="onlineRoutes">0</div>
<div class="stat-label">المسارات النشطة</div>
</div>
<div class="stat-card">
<div class="stat-value" id="offlineRoutes">0</div>
<div class="stat-label">المسارات المعطلة</div>
</div>
<div class="stat-card">
<div class="stat-value" id="uptime">--</div>
<div class="stat-label">وقت التشغيل</div>
</div>
</div>
<div class="section">
<h2>🌐 واجهات المستخدم</h2>
<div class="route-list">
<div class="route-item" data-url="/">
<div class="route-info">
<div class="route-name">الصفحة الرئيسية</div>
<div class="route-url">/</div>
</div>
<div class="route-status status-checking">جاري الفحص...</div>
</div>
<div class="route-item" data-url="/gradio">
<div class="route-info">
<div class="route-name">واجهة Gradio</div>
<div class="route-url">/gradio</div>
</div>
<div class="route-status status-checking">جاري الفحص...</div>
</div>
<div class="route-item" data-url="/app/login.html">
<div class="route-info">
<div class="route-name">صفحة تسجيل الدخول</div>
<div class="route-url">/app/login.html</div>
</div>
<div class="route-status status-checking">جاري الفحص...</div>
</div>
<div class="route-item" data-url="/app/portal.html">
<div class="route-info">
<div class="route-name">لوحة التحكم</div>
<div class="route-url">/app/portal.html</div>
</div>
<div class="route-status status-checking">جاري الفحص...</div>
</div>
</div>
</div>
<div class="section">
<h2>📡 نقاط API الرئيسية</h2>
<div class="route-list">
<div class="route-item" data-url="/api/health">
<div class="route-info">
<div class="route-name">فحص الصحة</div>
<div class="route-url">/api/health</div>
</div>
<div class="route-status status-checking">جاري الفحص...</div>
</div>
<div class="route-item" data-url="/api/docs">
<div class="route-info">
<div class="route-name">توثيق API</div>
<div class="route-url">/api/docs</div>
</div>
<div class="route-status status-checking">جاري الفحص...</div>
</div>
<div class="route-item" data-url="/api/users/login">
<div class="route-info">
<div class="route-name">تسجيل الدخول</div>
<div class="route-url">POST /api/users/login</div>
</div>
<div class="route-status status-checking">جاري الفحص...</div>
</div>
<div class="route-item" data-url="/api/jobs">
<div class="route-info">
<div class="route-name">قائمة الوظائف</div>
<div class="route-url">/api/jobs</div>
</div>
<div class="route-status status-checking">جاري الفحص...</div>
</div>
</div>
</div>
<div class="actions">
<a href="/app/login.html" class="btn">تسجيل الدخول</a>
<a href="/app/portal.html" class="btn">لوحة التحكم</a>
<a href="/api/docs" class="btn">توثيق API</a>
</div>
</div>
<script>
const BASE_URL = window.location.origin;
let totalRoutes = 0;
let onlineRoutes = 0;
let offlineRoutes = 0;
async function checkRoute(item) {
const url = item.dataset.url;
const statusEl = item.querySelector('.route-status');
try {
const response = await fetch(BASE_URL + url, { method: 'GET' });
if (response.ok || response.status === 405) { // 405 = Method Not Allowed (but route exists)
statusEl.textContent = 'نشط';
statusEl.className = 'route-status status-online';
onlineRoutes++;
} else {
statusEl.textContent = 'معطل';
statusEl.className = 'route-status status-offline';
offlineRoutes++;
}
} catch (error) {
statusEl.textContent = 'معطل';
statusEl.className = 'route-status status-offline';
offlineRoutes++;
}
updateStats();
}
function updateStats() {
document.getElementById('totalRoutes').textContent = totalRoutes;
document.getElementById('onlineRoutes').textContent = onlineRoutes;
document.getElementById('offlineRoutes').textContent = offlineRoutes;
const percentage = totalRoutes > 0 ? Math.round((onlineRoutes / totalRoutes) * 100) : 0;
document.getElementById('uptime').textContent = percentage + '%';
}
async function checkAllRoutes() {
const items = document.querySelectorAll('.route-item');
totalRoutes = items.length;
onlineRoutes = 0;
offlineRoutes = 0;
for (const item of items) {
await checkRoute(item);
}
}
// Start checking routes
checkAllRoutes();
// Refresh every 30 seconds
setInterval(checkAllRoutes, 30000);
</script>
</body>
</html>