rustio-admin 0.30.0

Django Admin, but for Rust. A small, focused admin framework.
Documentation
{% extends "admin/_base.html" %}
{% block content %}
<div class="rio-form-shell">
<nav class="rio-crumbs"><a href="/admin">Home</a><span class="rio-crumb-sep">·</span><a href="/admin/users">Users</a><span class="rio-crumb-sep">·</span><span class="rio-crumb-current">{{ user.email }}</span></nav>

<div class="rio-masthead-top">
  <div><h1>{{ user.full_name }}</h1><p class="rio-masthead-desc">{{ user.email }}</p></div>
  {% if can_edit %}<div class="rio-masthead-cta"><a class="rio-btn rio-btn--primary rio-btn--md" href="/admin/users/{{ user.id }}/edit">{{ icon("pencil") }} Edit</a></div>{% endif %}
</div>

<nav class="rio-tabs" aria-label="Profile sections">
  <a href="/admin/users/{{ user.id }}?tab=overview" class="rio-tab{% if tab == 'overview' %} rio-tab--active{% endif %}">Overview</a>
  <a href="/admin/users/{{ user.id }}?tab=activity" class="rio-tab{% if tab == 'activity' %} rio-tab--active{% endif %}">Activity ({{ activity_count }})</a>
  <a href="/admin/users/{{ user.id }}?tab=permissions" class="rio-tab{% if tab == 'permissions' %} rio-tab--active{% endif %}">Permissions ({{ permission_count }})</a>
  <a href="/admin/users/{{ user.id }}?tab=sessions" class="rio-tab{% if tab == 'sessions' %} rio-tab--active{% endif %}">Sessions ({{ session_count }})</a>
</nav>

{% if tab == "overview" %}
<section class="rio-board rio-detail-card">
  <dl class="rio-dl">
    <dt>Email</dt><dd>{{ user.email }}</dd>
    <dt>Full name</dt><dd>{% if user.full_name_value %}{{ user.full_name_value }}{% else %}<span class="rio-meta"></span>{% endif %}</dd>
    <dt>Role</dt><dd>{{ user.role }}{% if user.is_demo %} <span class="rio-pill rio-pill--badge-warning">demo</span>{% endif %}</dd>
    <dt>Active</dt><dd>{% if user.is_active %}Yes{% else %}No{% endif %}</dd>
    <dt>Created</dt><dd>{{ user.created_at_iso }}</dd>
    <dt>Last login</dt><dd>{{ user.last_login_iso }}</dd>
    <dt>Last seen</dt><dd>{{ user.last_seen_relative }}</dd>
    <dt>Groups</dt><dd>{% if user.groups %}{{ user.groups|join(", ") }}{% else %}<span class="rio-meta">none</span>{% endif %}</dd>
    {% if user.locale %}<dt>Locale</dt><dd>{{ user.locale }}</dd>{% endif %}
    {% if user.timezone %}<dt>Timezone</dt><dd>{{ user.timezone }}</dd>{% endif %}
  </dl>

  {% if recent_events %}
  <h2 class="rio-card-section">Recent activity</h2>
  <ul class="rio-timeline">
    {% for evt in recent_events %}<li class="rio-timeline-item rio-timeline-item--{{ evt.kind }}"><span class="rio-meta">{{ evt.timestamp_relative }}</span>{{ evt.message|safe }}</li>{% endfor %}
  </ul>
  {% endif %}

  {% block project_user_fields %}
  {% if project_fields %}{% for ps in project_fields %}
  <h2 class="rio-card-section">{{ ps.label }}</h2>
  <dl class="rio-dl">{% for r in ps.rows %}<dt>{{ r.label }}</dt><dd>{{ r.value }}</dd>{% endfor %}</dl>
  {% endfor %}{% endif %}
  {% endblock %}
</section>

{% elif tab == "activity" %}
<section class="rio-board rio-detail-card">
  {% if recent_events %}
  <ul class="rio-timeline">
    {% for evt in recent_events %}<li class="rio-timeline-item rio-timeline-item--{{ evt.kind }}"><span class="rio-meta">{{ evt.timestamp_relative }}</span>{{ evt.message|safe }}</li>{% endfor %}
  </ul>
  {% if activity_total_pages > 1 %}
  <nav class="rio-pagination" style="margin-block-start:var(--rio-space-16)">
    {% if activity_page > 1 %}<a class="rio-page" href="?tab=activity&page={{ activity_page - 1 }}">{{ icon("arrow-left") }}</a>{% endif %}
    <span class="rio-page" aria-current="page">{{ activity_page }} / {{ activity_total_pages }}</span>
    {% if activity_page < activity_total_pages %}<a class="rio-page rio-page--next" href="?tab=activity&page={{ activity_page + 1 }}">Next {{ icon("arrow-right") }}</a>{% endif %}
  </nav>
  {% endif %}
  {% else %}
  <div class="rio-empty">{{ icon("clock") }}<div class="rio-empty-title">No activity recorded</div><div>Anything this user does in the admin will appear here.</div></div>
  {% endif %}
</section>

{% elif tab == "permissions" %}
<section class="rio-board">
  {% if permissions %}
  <table class="rio-dtable">
    <thead><tr><th>Permission</th><th>Source</th></tr></thead>
    <tbody>{% for p in permissions %}<tr><td><code>{{ p.name }}</code></td><td>{{ p.source }}</td></tr>{% endfor %}</tbody>
  </table>
  {% else %}
  <div class="rio-empty">{{ icon("key") }}<div class="rio-empty-title">No permissions granted</div><div>Add this user to a group, or grant a direct permission, to see entries here.</div></div>
  {% endif %}
</section>

{% elif tab == "sessions" %}
<section class="rio-board">
  {% if sessions %}
  <div style="overflow:auto">
  <table class="rio-dtable">
    <thead><tr><th>Token</th><th>Created</th><th>Last seen</th><th>IP</th><th>User agent</th><th class="col-act">&nbsp;</th></tr></thead>
    <tbody>
      {% for s in sessions %}
      <tr>
        <td><code>{{ s.token_short }}…</code></td>
        <td>{{ s.created_at_iso }}</td>
        <td>{{ s.last_seen_relative }}</td>
        <td>{{ s.ip|default("—") }}</td>
        <td>{{ s.user_agent|default("—") }}</td>
        <td class="col-act">
          {% if s.is_current %}<span class="rio-meta">Your session</span>
          {% else %}<form method="post" action="/admin/users/{{ user.id }}/sessions/{{ s.session_id }}/revoke" class="rio-form-inline"><input type="hidden" name="_csrf" value="{{ csrf_token }}"><button type="submit" class="rio-btn rio-btn--subtle rio-btn--sm">Revoke</button></form>{% endif %}
        </td>
      </tr>
      {% endfor %}
    </tbody>
  </table>
  </div>
  {% else %}
  <div class="rio-empty">{{ icon("log-out") }}<div class="rio-empty-title">No active sessions</div><div>When this user signs in, their sessions appear here for revocation.</div></div>
  {% endif %}
</section>
{% endif %}

</div>
{% endblock %}