index.twig 4.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. {% extends 'layout.twig' %}
  2. {% block title %}Users — IRDB{% endblock %}
  3. {% block content %}
  4. <div class="mx-auto max-w-5xl">
  5. <div class="flex items-center justify-between">
  6. <h1 class="text-2xl font-semibold tracking-tight">Users</h1>
  7. <span class="text-sm text-slate-500 dark:text-slate-400">{{ list.total|default(0) }} total</span>
  8. </div>
  9. <p class="mt-1 text-sm text-slate-500 dark:text-slate-400">
  10. Disabled users are blocked at the impersonation boundary — neither OIDC nor local sign-in completes for them until re-enabled.
  11. </p>
  12. <section class="mt-6 overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-sm dark:border-slate-800 dark:bg-slate-900">
  13. <table class="w-full text-sm">
  14. <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">
  15. <tr>
  16. <th class="px-4 py-2 font-medium">ID</th>
  17. <th class="px-4 py-2 font-medium">Display name</th>
  18. <th class="px-4 py-2 font-medium">Email</th>
  19. <th class="px-4 py-2 font-medium">Role</th>
  20. <th class="px-4 py-2 font-medium">Source</th>
  21. <th class="px-4 py-2 font-medium">Status</th>
  22. <th class="px-4 py-2 text-right font-medium">Actions</th>
  23. </tr>
  24. </thead>
  25. <tbody class="divide-y divide-slate-100 dark:divide-slate-800">
  26. {% for u in list.items|default([]) %}
  27. <tr>
  28. <td class="px-4 py-2 font-mono text-xs text-slate-500 dark:text-slate-400">{{ u.id }}</td>
  29. <td class="px-4 py-2">{{ u.display_name|default('—') }}</td>
  30. <td class="px-4 py-2 text-slate-600 dark:text-slate-400">{{ u.email|default('—') }}</td>
  31. <td class="px-4 py-2 font-mono text-xs">{{ u.role }}</td>
  32. <td class="px-4 py-2 text-xs text-slate-500 dark:text-slate-400">
  33. {% if u.is_local %}local{% else %}oidc{% endif %}
  34. </td>
  35. <td class="px-4 py-2">
  36. {% if u.disabled %}
  37. <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"
  38. title="{{ u.disabled_at|default('') }}">disabled</span>
  39. {% else %}
  40. <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>
  41. {% endif %}
  42. </td>
  43. <td class="px-4 py-2 text-right">
  44. {% if u.id == acting_user_id %}
  45. <span class="text-xs text-slate-400">you</span>
  46. {% elseif u.is_local %}
  47. <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>
  48. {% elseif u.disabled %}
  49. {% include 'partials/confirm_form.twig' with {
  50. action: '/app/users/' ~ u.id ~ '/enable',
  51. label: 'Enable',
  52. description: 'Re-enabling this user lets them log in again. Their role is recomputed from OIDC groups on next sign-in.',
  53. 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'
  54. } only %}
  55. {% else %}
  56. {% include 'partials/confirm_form.twig' with {
  57. action: '/app/users/' ~ u.id ~ '/disable',
  58. label: 'Disable',
  59. description: 'A disabled user cannot impersonate via the UI BFF — every admin call 403s until re-enabled.',
  60. } only %}
  61. {% endif %}
  62. </td>
  63. </tr>
  64. {% else %}
  65. <tr><td colspan="7" class="px-4 py-6 text-center text-slate-400">No users.</td></tr>
  66. {% endfor %}
  67. </tbody>
  68. </table>
  69. </section>
  70. </div>
  71. {% endblock %}