{#- dashboard_admin.html — the admin role's dashboard. Inherits layout_app. Backend: GET /dashboard -> render_template("dashboard_admin.html", **_admin_context()) when current_role() == 'admin' (app.py). Same shell as the client dashboard; only the topbar + content differ. CONTEXT (all real, no placeholders): users : list[dict] from db.list_users(limit=10) — id, email, role, status, created_at, updated_at. Never password_hash (db.py selects columns explicitly so a hash cannot reach a template). counts : db.user_counts() -> {total, status{...}, role{...}}, zero-filled. queue : worker.queue_stats() -> {counts{...}, pending, stale, healthy}. The routes behind the buttons are POST /admin/invite and GET /admin/users, both gated by @auth.require_role("admin") and called through fabbro.request() (which sends CSRF + `Accept: application/json`, so a lapsed session returns a 401 instead of the login page's HTML). -#} {% extends "layout_app.html" %} {% block title %}Admin{% endblock %} {#- One definition of a user row, used by the initial server render. The JS mirror (renderRows) builds the same structure from JSON. Status drives the badge colour: active=success, pending=warning, disabled=neutral. -#} {% macro user_row(u) %}
{{ counts.total }}
{{ counts.status.active }} active · {{ counts.status.pending }} pending
{{ queue.pending }}
{{ queue.counts.queued }} queued · {{ queue.counts.running }} running {%- if queue.counts.failed %} · {{ queue.counts.failed }} failed{% endif %}
{% if queue.healthy %} Operational {% else %} Attention {% endif %}
{% if queue.healthy %}Workers healthy {% elif queue.stale %}{{ queue.stale }} stale job(s) — worker may have died {% else %}{{ queue.counts.failed }} job(s) in dead-letter{% endif %}
| Role | Status | Joined | ||
|---|---|---|---|---|
| No users yet. | ||||