147 lines
11 KiB
HTML
147 lines
11 KiB
HTML
{% extends "sidebar.html" %}
|
|
|
|
{% block title %}AstraOS — Role Management{% endblock %}
|
|
|
|
{% block head %}
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div x-data="{ showAddRoleModal: false, showDeleteModal: false, roleToDelete: null, roleToEdit: null }">
|
|
<main class="flex-1 p-8 space-y-10" id="mainContent">
|
|
<!-- FLASH MESSAGES -->
|
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
|
{% if messages %}
|
|
<div class="toast-container">
|
|
{% for category, message in messages %}
|
|
<div x-data="{ show: true }" x-init="setTimeout(() => show = false, 5000)" x-show="show"
|
|
x-transition:enter="toast transition ease-out duration-300"
|
|
x-transition:enter-start="opacity-0 translate-x-8"
|
|
x-transition:enter-end="opacity-100 translate-x-0"
|
|
x-transition:leave="toast transition ease-in duration-300"
|
|
x-transition:leave-start="opacity-100"
|
|
x-transition:leave-end="opacity-0"
|
|
class="max-w-md w-full bg-gray-800 shadow-lg rounded-lg pointer-events-auto ring-1 ring-black ring-opacity-5 overflow-hidden border border-{{ 'red' if category == 'danger' else ('green' if category == 'success' else ('blue' if category == 'info' else 'gray')) }}-500/40">
|
|
<div class="p-4">
|
|
<div class="flex items-start">
|
|
<div class="flex-shrink-0">
|
|
{% if category == 'success' %}
|
|
<svg class="h-6 w-6 text-green-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
|
{% elif category == 'danger' %}
|
|
<svg class="h-6 w-6 text-red-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
|
{% else %}
|
|
<svg class="h-6 w-6 text-blue-400" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
|
|
{% endif %}
|
|
</div>
|
|
<div class="ml-3 w-0 flex-1 pt-0.5">
|
|
<p class="text-sm font-medium text-gray-100">{{ message }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
{% endwith %}
|
|
<!-- HEADER -->
|
|
<header class="flex justify-between items-center mb-10">
|
|
<h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Rollen verwalten</h2>
|
|
<button @click="showAddRoleModal = true" class="font-bold py-2 px-4 rounded-lg transition text-white
|
|
{% if maintenance_active %}bg-yellow-600 hover:bg-yellow-700{% else %}bg-purple-600 hover:bg-purple-700{% endif %}">
|
|
+ Neue Rolle hinzufügen
|
|
</button>
|
|
</header>
|
|
<!-- ROLE TABLE -->
|
|
<div class="bg-black/40 rounded-xl backdrop-blur-lg overflow-hidden
|
|
{% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
|
|
<table class="min-w-full divide-y {% if maintenance_active %}divide-yellow-500/30{% else %}divide-purple-500/20{% endif %}">
|
|
<thead class="bg-black/20">
|
|
<tr>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">Rollenname</th>
|
|
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-300 uppercase tracking-wider">Berechtigungen</th>
|
|
<th scope="col" class="relative px-6 py-3">
|
|
<span class="sr-only">Aktionen</span>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y {% if maintenance_active %}divide-yellow-500/30{% else %}divide-purple-500/30{% endif %}">
|
|
{% for role in roles %}
|
|
<tr class="transition {% if maintenance_active %}hover:bg-yellow-500/5{% else %}hover:bg-purple-500/5{% endif %}">
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-white">{{ role.name }}</td>
|
|
<td class="px-6 py-4 text-sm text-gray-300">
|
|
<div class="flex flex-wrap gap-2">
|
|
{% for perm in role.permissions %}
|
|
<span class="px-2 py-1 inline-flex text-xs leading-5 font-semibold rounded-full
|
|
{% if maintenance_active %}bg-yellow-500/20 text-yellow-300{% else %}bg-purple-500/20 text-purple-300{% endif %}">{{ perm }}</span>
|
|
{% endfor %}
|
|
</div>
|
|
</td>
|
|
<td class="px-6 py-4 text-right text-sm font-medium">
|
|
<div class="flex items-center justify-end gap-4">
|
|
<button @click='roleToEdit = {{ role | tojson }}; showAddRoleModal = true' class="flex-shrink-0
|
|
{% if maintenance_active %}text-yellow-400 hover:text-yellow-300{% else %}text-indigo-400 hover:text-indigo-300{% endif %}">Bearbeiten</button>
|
|
{% if role.is_deletable %}
|
|
<button @click="roleToDelete = '{{ role._id }}'; showDeleteModal = true" class="flex-shrink-0 text-red-400 hover:text-red-300">Löschen</button>
|
|
{% endif %}
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</main>
|
|
|
|
<!-- ADD/EDIT ROLE MODAL -->
|
|
<div x-show="showAddRoleModal" @keydown.escape.window="showAddRoleModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;">
|
|
<div @click.away="showAddRoleModal = false" class="bg-gray-900 rounded-xl shadow-2xl p-8 w-full max-w-lg
|
|
{% if maintenance_active %}border border-yellow-500/50{% else %}border border-purple-500/50{% endif %}">
|
|
<h3 class="text-2xl font-bold mb-6 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}" x-text="roleToEdit ? 'Rolle bearbeiten' : 'Neue Rolle erstellen'"></h3>
|
|
<form :action="roleToEdit ? '/edit_role/' + roleToEdit._id : '/add_role'" method="POST" class="space-y-4">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
|
<div>
|
|
<label for="role_name" class="block text-sm font-medium text-gray-300">Rollenname</label>
|
|
<input type="text" name="role_name" id="role_name" :value="roleToEdit ? roleToEdit.name : ''" required
|
|
class="mt-1 w-full px-3 py-2 bg-gray-800 border border-gray-700 rounded-lg text-white focus:outline-none focus:ring-2
|
|
{% if maintenance_active %}focus:ring-yellow-500{% else %}focus:ring-purple-500{% endif %}">
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-300">Berechtigungen</label>
|
|
<div class="mt-2 grid grid-cols-2 gap-2 max-h-60 overflow-y-auto pr-2">
|
|
{% for perm in available_permissions %}
|
|
<label class="custom-checkbox-label {% if maintenance_active %}maintenance{% endif %}">
|
|
<input type="checkbox" name="permissions" value="{{ perm }}"
|
|
:checked="roleToEdit && roleToEdit.permissions.includes('{{ perm }}')">
|
|
<span class="custom-checkbox-box">
|
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="3" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" />
|
|
</svg>
|
|
</span>
|
|
<span class="text-gray-300">{{ perm }}</span>
|
|
</label>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
<div class="flex justify-end gap-4 pt-4">
|
|
<button type="button" @click="showAddRoleModal = false; roleToEdit = null" class="px-4 py-2 rounded-lg text-gray-300 hover:bg-gray-700 transition">Abbrechen</button>
|
|
<button type="submit" class="px-4 py-2 font-semibold rounded-lg transition text-white
|
|
{% if maintenance_active %}bg-yellow-600 hover:bg-yellow-700{% else %}bg-purple-600 hover:bg-purple-700{% endif %}"
|
|
x-text="roleToEdit ? 'Änderungen speichern' : 'Rolle erstellen'"></button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<!-- DELETE CONFIRMATION MODAL -->
|
|
<div x-show="showDeleteModal" @keydown.escape.window="showDeleteModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;">
|
|
<div @click.away="showDeleteModal = false" class="bg-gray-900 border border-red-500/50 rounded-xl shadow-2xl p-8 w-full max-w-md">
|
|
<h3 class="text-2xl font-bold text-red-400 mb-4">Rolle löschen</h3>
|
|
<p class="text-gray-300 mb-6">Möchten Sie diese Rolle wirklich endgültig löschen? Benutzer, die diese Rolle haben, verlieren ihre Berechtigungen.</p>
|
|
<form :action="'/delete_role/' + roleToDelete" method="POST" class="flex justify-end gap-4">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
|
<button type="button" @click="showDeleteModal = false" class="px-4 py-2 rounded-lg text-gray-300 hover:bg-gray-700 transition">Abbrechen</button>
|
|
<button type="submit" class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white font-semibold rounded-lg transition">Löschen</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|