WEB_DEV / templates /admin.html
Binta26's picture
Update templates/admin.html
27fb30a verified
Raw
History Blame Contribute Delete
6.6 kB
{% extends "base.html" %}
{% block title %}Admin — IrisAI{% endblock %}
{% block head %}
<style>
/* ── Stats grid ── */
.stats-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
margin-bottom: 2rem;
}
@media (max-width: 700px) { .stats-grid { grid-template-columns: 1fr 1fr; } }
.stat-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 1.25rem 1.5rem;
text-align: center;
}
.stat-card .val {
font-family: 'DM Serif Display', serif;
font-size: 2.8rem;
background: linear-gradient(135deg, var(--accent), var(--accent2));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.stat-card .lbl {
font-size: .80rem;
text-transform: uppercase;
letter-spacing: .05em;
color: var(--muted);
margin-top: .2rem;
}
.stat-card.active-card { border-color: #4ade80; }
.stat-card.active-card .val { background: linear-gradient(135deg, #4ade80, #22d3ee); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
/* ── Section title ── */
.section-title {
font-size: .80rem;
text-transform: uppercase;
letter-spacing: .08em;
color: var(--muted);
margin-bottom: .75rem;
font-weight: 700;
}
/* ── Status dot ── */
.dot {
display: inline-block;
width: 8px; height: 8px;
border-radius: 50%;
margin-right: 6px;
vertical-align: middle;
}
.dot-green { background: #4ade80; box-shadow: 0 0 6px #4ade8088; animation: pulse 1.5s infinite; }
.dot-gray { background: var(--muted); }
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: .4; }
}
/* ── Refresh badge ── */
.refresh-badge {
font-family: 'DM Mono', monospace;
font-size: .80rem;
background: var(--surface2);
border: 1px solid var(--border);
color: var(--muted);
padding: .2rem .7rem;
border-radius: 20px;
}
#countdown { color: var(--accent); }
/* ── Table overrides ── */
.admin-table th { white-space: nowrap; }
.admin-table td { font-size: .82rem; white-space: nowrap; }
.overflow-x { overflow-x: auto; }
input[type="email"] {
width: 100%; padding: .75rem 1rem;
background: var(--surface2); border: 1px solid var(--border);
border-radius: var(--radius); color: var(--text);
font-family: inherit; font-size: .95rem; outline: none;
transition: border-color .2s, box-shadow .2s;
}
input[type="email"]:focus {
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(124,111,255,.15);
}
</style>
{% endblock %}
{% block body %}
<div class="page">
<div class="container" style="max-width:1100px">
<!-- Header -->
<div class="page-header" style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:1rem">
<div>
<h1>🛠 Admin Dashboard</h1>
<p>Real-time database</p>
</div>
<span class="refresh-badge">Refresh in <span id="countdown">5</span>s</span>
</div>
<!-- Stats -->
<div class="stats-grid">
<div class="stat-card">
<div class="val">{{ stats.total_users }}</div>
<div class="lbl">Users</div>
</div>
<div class="stat-card active-card">
<div class="val">{{ stats.active_now }}</div>
<div class="lbl">Currently online</div>
</div>
<div class="stat-card">
<div class="val">{{ stats.total_sessions }}</div>
<div class="lbl">Total sessions</div>
</div>
<div class="stat-card">
<div class="val">{{ stats.total_preds }}</div>
<div class="lbl">Prédictions</div>
</div>
</div>
<!-- Table users -->
<div class="card" style="margin-bottom:1.5rem">
<p class="section-title">👤 Users Table</p>
<div class="overflow-x">
<table class="admin-table">
<thead>
<tr>
<th>ID</th>
<th>Username</th>
<th>Email</th>
<th>Create at </th>
</tr>
</thead>
<tbody>
{% for u in users %}
<tr>
<td class="mono muted">{{ u.id }}</td>
<td><strong>{{ u.username }}</strong></td>
<td class="muted">{{ u.email }}</td>
<td class="muted">{{ u.created[:19].replace('T', ' ') }}</td>
</tr>
{% else %}
<tr><td colspan="4" class="muted" style="text-align:center;padding:1.5rem">No users</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<!-- Table sessions -->
<div class="card">
<p class="section-title">🔐 Table sessions — logins/logouts (last 50)</p>
<div class="overflow-x">
<table class="admin-table">
<thead>
<tr>
<th>ID</th>
<th>User</th>
<th>Email</th>
<th>Last logged in on</th>
<th>Logged out on</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{% for s in sessions_log %}
<tr>
<td class="mono muted">{{ s.id }}</td>
<td><strong>{{ s.username }}</strong></td>
<td class="muted">{{ s.email }}</td>
<td class="muted">{{ s.login_at[:19].replace('T', ' ') }}</td>
<td class="muted">
{% if s.logout_at %}
{{ s.logout_at[:19].replace('T', ' ') }}
{% else %}
<span class="muted"></span>
{% endif %}
</td>
<td>
{% if s.logout_at %}
<span class="dot dot-gray"></span><span class="muted" style="font-size:.8rem">Disconnect</span>
{% else %}
<span class="dot dot-green"></span><span style="color:#4ade80;font-size:.8rem">On line</span>
{% endif %}
</td>
</tr>
{% else %}
<tr><td colspan="6" class="muted" style="text-align:center;padding:1.5rem">No sessions saved</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
<script>
// Rafraîchissement automatique toutes les 5 secondes
let count = 5;
const el = document.getElementById('countdown');
setInterval(() => {
count--;
el.textContent = count;
if (count <= 0) {
window.location.reload();
}
}, 1000);
</script>
{% endblock %}