reorganize templates into pages/ and modals/ directories for better structure update includes to reference new paths, maintaining functionality
91 lines
5.1 KiB
HTML
91 lines
5.1 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}Roles{% endblock %}
|
|
{% block breadcrumb %}
|
|
<nav class="mb-4" aria-label="Breadcrumb">
|
|
<ol class="flex items-center gap-1.5 text-xs text-gray-500 dark:text-gray-400">
|
|
<li><a href="{% url 'dashboard' %}" class="hover:text-gray-700 dark:hover:text-gray-300">Dashboard</a></li>
|
|
<li class="text-gray-300 dark:text-gray-600">/</li>
|
|
<li class="text-gray-900 dark:text-white font-medium" aria-current="page">Roles</li>
|
|
</ol>
|
|
</nav>
|
|
{% endblock %}
|
|
{% block content %}
|
|
<div class="mb-6 flex flex-col sm:flex-row sm:items-center justify-between gap-4">
|
|
<div>
|
|
<h1 class="text-2xl font-bold">Roles</h1>
|
|
<p class="text-gray-500 dark:text-gray-400 text-sm mt-1">{{ roles.count }} role{{ roles.count|pluralize }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
{% if request.user.is_admin %}
|
|
<div class="dk-card divide-y divide-gray-200 dark:divide-gray-600 mb-6">
|
|
<div class="px-6 py-4"><h3 class="text-sm font-semibold text-gray-900 dark:text-gray-100">Create Custom Role</h3><p class="text-xs text-gray-500 mt-0.5">Define a new role for your organization</p></div>
|
|
<div class="px-6 py-5">
|
|
<form method="post" action="{% url 'role-add' %}" class="flex items-end gap-3">
|
|
{% csrf_token %}
|
|
<div>
|
|
<label class="block text-xs font-medium text-gray-500 mb-1">Name</label>
|
|
<input type="text" name="name" required placeholder="e.g. Senior Developer"
|
|
class="w-60 text-sm border border-gray-200 dark:border-gray-600 rounded-lg px-3 py-2 bg-white dark:bg-gray-950 focus:outline-none focus:ring-2 focus:ring-blue-500">
|
|
</div>
|
|
<button type="submit" class="dk-btn dk-btn-primary"><i class="fas fa-plus"></i> Create</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="dk-card overflow-hidden divide-y divide-gray-200 dark:divide-gray-600">
|
|
<div class="px-6 py-4"><h3 class="text-sm font-semibold text-gray-900 dark:text-gray-100">All Roles</h3><p class="text-xs text-gray-500 mt-0.5">System roles cannot be deleted</p></div>
|
|
<div class="overflow-x-auto">
|
|
<table class="w-full text-sm">
|
|
<thead>
|
|
<tr class="border-b border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-800">
|
|
<th class="text-left px-4 py-3 font-semibold text-xs text-gray-500 dark:text-gray-400">Name</th>
|
|
<th class="text-left px-4 py-3 font-semibold text-xs text-gray-500 dark:text-gray-400">Slug</th>
|
|
<th class="text-left px-4 py-3 font-semibold text-xs text-gray-500 dark:text-gray-400">Type</th>
|
|
<th class="text-left px-4 py-3 font-semibold text-xs text-gray-500 dark:text-gray-400">Users</th>
|
|
{% if request.user.is_admin %}
|
|
<th class="text-right px-4 py-3 font-semibold text-xs text-gray-500 dark:text-gray-400">Actions</th>
|
|
{% endif %}
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for r in roles %}
|
|
<tr class="border-b border-gray-100 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800/50">
|
|
<td class="px-4 py-3 font-medium text-gray-900 dark:text-white">
|
|
{{ r.name }}
|
|
{% if r.slug in admin_roles %}
|
|
<span class="inline-flex items-center px-1.5 py-0.5 rounded text-[10px] font-medium bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400 ml-1.5">System</span>
|
|
{% endif %}
|
|
</td>
|
|
<td class="px-4 py-3 text-gray-500 dark:text-gray-400 font-mono text-xs">{{ r.slug }}</td>
|
|
<td class="px-4 py-3">
|
|
{% if r.slug in admin_roles %}
|
|
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-purple-100 text-purple-700 dark:bg-purple-900/30 dark:text-purple-400">Hardcoded — full access</span>
|
|
{% else %}
|
|
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400">Custom — follows rules</span>
|
|
{% endif %}
|
|
</td>
|
|
<td class="px-4 py-3 text-gray-500 dark:text-gray-400">{{ r.users.count }}</td>
|
|
{% if request.user.is_admin %}
|
|
<td class="px-4 py-3 text-right">
|
|
{% if not r.is_system %}
|
|
<form method="post" action="{% url 'role-delete' r.id %}" class="inline">
|
|
{% csrf_token %}
|
|
<button type="button" @click="confirmAction({title:'Delete Role', message:'Delete role <strong>{{ r.name|escapejs }}</strong>? Users with this role will become unassigned.', confirmText:'Delete', danger:true, onConfirm:function(){ $el.closest('form').submit() }})" class="inline-flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium text-red-600 dark:text-red-400 bg-white dark:bg-gray-900 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors shadow-sm">Delete</button>
|
|
</form>
|
|
{% else %}
|
|
<span class="text-xs text-gray-400 italic">Protected</span>
|
|
{% endif %}
|
|
</td>
|
|
{% endif %}
|
|
</tr>
|
|
{% empty %}
|
|
<tr><td colspan="5" class="text-center py-12 text-gray-400">No roles defined</td></tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|