users.html 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. {% extends "layout.html" %}
  2. {% block content %}
  3. <div class="flex justify-between items-center mb-10">
  4. <div>
  5. <h2 class="text-4xl font-black text-white tracking-tighter italic">User Management</h2>
  6. <p class="text-gray-500 font-bold uppercase text-[10px] tracking-widest mt-2">Manage access and RBAC roles</p>
  7. </div>
  8. <button onclick="openAddUser()" class="bg-blue-600 hover:bg-blue-500 px-8 py-3 rounded-xl font-black shadow-2xl transition transform hover:scale-105 text-white uppercase text-xs tracking-widest">+ Create User</button>
  9. </div>
  10. <div class="bg-[#12161f] border border-gray-800 rounded-3xl overflow-hidden shadow-2xl">
  11. <table class="w-full text-left">
  12. <thead class="bg-black/20 text-[10px] font-black text-gray-500 uppercase tracking-widest border-b border-gray-800">
  13. <tr>
  14. <th class="p-6">Username</th>
  15. <th class="p-6">Role</th>
  16. <th class="p-6">Templates</th>
  17. <th class="p-6 text-right">Actions</th>
  18. </tr>
  19. </thead>
  20. <tbody class="divide-y divide-gray-800">
  21. {% for u, data in users.items() %}
  22. <tr class="hover:bg-white/[0.02] transition">
  23. <td class="p-6 font-bold text-white">{{ u }}</td>
  24. <td class="p-6">
  25. <span class="px-3 py-1 rounded-full text-[9px] font-black uppercase border {% if data.role=='admin' %}border-red-500/30 text-red-400 bg-red-500/10{% else %}border-blue-500/30 text-blue-400 bg-blue-500/10{% endif %}">
  26. {{ data.role }}
  27. </span>
  28. </td>
  29. <td class="p-6 text-xs text-gray-500">{{ data.assigned_templates|join(', ') or 'None' }}</td>
  30. <td class="p-6 text-right">
  31. <button onclick="editUser('{{u}}', '{{data.role}}', {{data.assigned_templates|tojson}})" class="text-blue-500 hover:text-blue-400 text-[10px] font-black uppercase mr-4">Edit</button>
  32. {% if u != 'admin' %}
  33. <a href="/users/delete/{{ u }}" onclick="return confirm('Delete user?')" class="text-red-500 hover:text-red-400 text-[10px] font-black uppercase">Delete</a>
  34. {% endif %}
  35. </td>
  36. </tr>
  37. {% endfor %}
  38. </tbody>
  39. </table>
  40. </div>
  41. <div id="userModal" class="hidden fixed inset-0 bg-black/90 backdrop-blur-md flex items-center justify-center z-50 p-4">
  42. <div class="bg-[#12161f] border border-gray-800 w-full max-w-md rounded-3xl p-8 shadow-2xl">
  43. <h3 id="modalTitle" class="text-xl font-black text-white mb-6 uppercase">Add User</h3>
  44. <form action="/users/save" method="POST" class="space-y-4">
  45. <input type="hidden" name="action" id="userAction" value="add">
  46. <input type="hidden" name="old_username" id="oldUsername">
  47. <input type="text" name="username" id="userName" placeholder="Username" required class="w-full bg-[#0b0e14] border border-gray-800 rounded-xl p-3 text-sm font-bold text-white outline-none">
  48. <input type="password" name="password" id="userPass" placeholder="Password" class="w-full bg-[#0b0e14] border border-gray-800 rounded-xl p-3 text-sm font-bold text-white outline-none">
  49. <select name="role" id="userRole" class="w-full bg-[#0b0e14] border border-gray-800 rounded-xl p-3 text-sm font-bold text-white outline-none">
  50. <option value="user">User (Restricted)</option>
  51. <option value="admin">Administrator</option>
  52. </select>
  53. <div class="bg-black/20 p-4 rounded-xl border border-gray-800">
  54. <label class="text-[10px] font-black text-gray-500 uppercase block mb-3">Assigned Templates</label>
  55. <div class="grid grid-cols-2 gap-2">
  56. {% for t in all_templates %}
  57. <label class="flex items-center gap-2 text-xs text-gray-400 cursor-pointer hover:text-white">
  58. <input type="checkbox" name="assigned_templates[]" value="{{ t }}" class="template-check rounded border-gray-700 bg-gray-900 text-blue-600">
  59. {{ t }}
  60. </label>
  61. {% endfor %}
  62. </div>
  63. </div>
  64. <div class="flex gap-4 pt-4">
  65. <button type="button" onclick="closeUserModal()" class="flex-1 bg-gray-800 text-gray-400 font-bold py-3 rounded-xl uppercase text-xs">Cancel</button>
  66. <button type="submit" class="flex-1 bg-blue-600 text-white font-black py-3 rounded-xl uppercase text-xs">Save</button>
  67. </div>
  68. </form>
  69. </div>
  70. </div>
  71. <script>
  72. function openAddUser() {
  73. document.getElementById('userModal').classList.remove('hidden');
  74. document.getElementById('userAction').value = 'add';
  75. document.getElementById('modalTitle').innerText = 'Add User';
  76. document.getElementById('userName').value = '';
  77. document.querySelectorAll('.template-check').forEach(c => c.checked = false);
  78. }
  79. function editUser(u, role, templates) {
  80. document.getElementById('userModal').classList.remove('hidden');
  81. document.getElementById('userAction').value = 'edit';
  82. document.getElementById('oldUsername').value = u;
  83. document.getElementById('userName').value = u;
  84. document.getElementById('userRole').value = role;
  85. document.getElementById('modalTitle').innerText = 'Edit User';
  86. document.querySelectorAll('.template-check').forEach(c => {
  87. c.checked = templates.includes(c.value);
  88. });
  89. }
  90. function closeUserModal() { document.getElementById('userModal').classList.add('hidden'); }
  91. </script>
  92. {% endblock %}