| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 |
- {% extends 'layout.twig' %}
- {% block title %}Users — IRDB{% endblock %}
- {% block content %}
- <div class="mx-auto max-w-5xl">
- <div class="flex items-center justify-between">
- <h1 class="text-2xl font-semibold tracking-tight">Users</h1>
- <span class="text-sm text-slate-500 dark:text-slate-400">{{ list.total|default(0) }} total</span>
- </div>
- <p class="mt-1 text-sm text-slate-500 dark:text-slate-400">
- Disabled users are blocked at the impersonation boundary — neither OIDC nor local sign-in completes for them until re-enabled.
- </p>
- <section class="mt-6 overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm dark:border-slate-800 dark:bg-slate-900">
- <table class="w-full text-sm">
- <thead class="border-b border-slate-200 bg-slate-50 text-left text-xs uppercase tracking-wider text-slate-500 dark:border-slate-800 dark:bg-slate-950 dark:text-slate-400">
- <tr>
- <th class="px-4 py-2 font-medium">ID</th>
- <th class="px-4 py-2 font-medium">Display name</th>
- <th class="px-4 py-2 font-medium">Email</th>
- <th class="px-4 py-2 font-medium">Role</th>
- <th class="px-4 py-2 font-medium">Source</th>
- <th class="px-4 py-2 font-medium">Status</th>
- <th class="px-4 py-2 text-right font-medium">Actions</th>
- </tr>
- </thead>
- <tbody class="divide-y divide-slate-100 dark:divide-slate-800">
- {% for u in list.items|default([]) %}
- <tr>
- <td class="px-4 py-2 font-mono text-xs text-slate-500 dark:text-slate-400">{{ u.id }}</td>
- <td class="px-4 py-2">{{ u.display_name|default('—') }}</td>
- <td class="px-4 py-2 text-slate-600 dark:text-slate-400">{{ u.email|default('—') }}</td>
- <td class="px-4 py-2 font-mono text-xs">{{ u.role }}</td>
- <td class="px-4 py-2 text-xs text-slate-500 dark:text-slate-400">
- {% if u.is_local %}local{% else %}oidc{% endif %}
- </td>
- <td class="px-4 py-2">
- {% if u.disabled %}
- <span class="rounded bg-amber-100 px-1.5 py-0.5 text-xs uppercase text-amber-900 dark:bg-amber-900 dark:text-amber-100"
- title="{{ u.disabled_at|default('') }}">disabled</span>
- {% else %}
- <span class="rounded bg-emerald-100 px-1.5 py-0.5 text-xs uppercase text-emerald-800 dark:bg-emerald-900 dark:text-emerald-100">active</span>
- {% endif %}
- </td>
- <td class="px-4 py-2 text-right">
- {% if u.id == acting_user_id %}
- <span class="text-xs text-slate-400">you</span>
- {% elseif u.is_local %}
- <span class="text-xs text-slate-400" title="The local admin cannot be disabled here. Unset LOCAL_ADMIN_PASSWORD_HASH in the UI's env to disable local sign-in.">protected</span>
- {% elseif u.disabled %}
- {% include 'partials/confirm_form.twig' with {
- action: '/app/users/' ~ u.id ~ '/enable',
- label: 'Enable',
- description: 'Re-enabling this user lets them log in again. Their role is recomputed from OIDC groups on next sign-in.',
- btn_class: 'rounded-md border border-emerald-300 bg-white px-2 py-1 text-xs font-medium text-emerald-700 hover:bg-emerald-50 dark:border-emerald-700 dark:bg-slate-900 dark:text-emerald-300 dark:hover:bg-slate-800'
- } only %}
- {% else %}
- {% include 'partials/confirm_form.twig' with {
- action: '/app/users/' ~ u.id ~ '/disable',
- label: 'Disable',
- description: 'A disabled user cannot impersonate via the UI BFF — every admin call 403s until re-enabled.',
- } only %}
- {% endif %}
- </td>
- </tr>
- {% else %}
- <tr><td colspan="7" class="px-4 py-6 text-center text-slate-400">No users.</td></tr>
- {% endfor %}
- </tbody>
- </table>
- </section>
- </div>
- {% endblock %}
|