Skip to main content
Glama
permissions.html•19 kB
<!-- Template pour la gestion des permissions --> <div class="permissions-management"> <div class="flex justify-between items-center mb-6"> <h2 class="text-2xl font-bold">Gestion des permissions</h2> <div class="flex gap-3"> <button class="btn btn-secondary" id="export-permissions">📤 Exporter</button> <button class="btn btn-primary" id="add-permission">➕ Nouvelle permission</button> </div> </div> <!-- Filtres --> <div class="card mb-6"> <div class="card-body"> <div class="grid grid-cols-1 md:grid-cols-4 gap-4"> <div class="form-group"> <label class="form-label">Utilisateur</label> <select class="form-input" id="filter-user"> <option value="">Tous les utilisateurs</option> </select> </div> <div class="form-group"> <label class="form-label">Resource</label> <input type="text" class="form-input" id="filter-resource" placeholder="Filtrer par resource..."> </div> <div class="form-group"> <label class="form-label">Type</label> <select class="form-input" id="filter-type"> <option value="">Tous les types</option> <option value="read">Lecture</option> <option value="write">Écriture</option> <option value="execute">Exécution</option> </select> </div> <div class="form-group"> <label class="form-label">&nbsp;</label> <button class="btn btn-secondary w-full" id="clear-filters">🗑️ Effacer filtres</button> </div> </div> </div> </div> <!-- Tableau des permissions --> <div class="card"> <div class="card-header"> <h3 class="card-title">Permissions configurées</h3> <div class="flex items-center gap-2"> <span class="text-sm text-secondary" id="permissions-count">0 permissions</span> </div> </div> <div class="card-body p-0"> <div class="table-container"> <table class="table"> <thead> <tr> <th>Permission</th> <th>Catégorie</th> <th>Statut</th> <th>ID</th> <th>Actions</th> </tr> </thead> <tbody id="permissions-table-body"> <!-- Les permissions seront ajoutées dynamiquement --> </tbody> </table> </div> </div> </div> </div> <!-- Modal pour ajouter/éditer une permission --> <div id="permission-modal" class="modal hidden"> <div class="modal-content"> <div class="modal-header"> <h3 class="modal-title" id="modal-title">Nouvelle permission</h3> <button class="modal-close" id="close-modal">✕</button> </div> <div class="modal-body"> <form id="permission-form"> <input type="hidden" id="permission-id" value=""> <div class="form-group"> <label class="form-label required">Utilisateur</label> <select class="form-input" id="permission-user" required> <option value="">Sélectionner un utilisateur</option> </select> </div> <div class="form-group"> <label class="form-label required">Resource</label> <input type="text" class="form-input" id="permission-resource" placeholder="ex: tools.*, config.database, etc." required> <p class="form-help"> Utiliser * pour tous les éléments. Exemples: tools.*, config.database, logs.read </p> </div> <div class="form-group"> <label class="form-label">Types de permission</label> <div class="checkbox-group"> <label class="checkbox-item"> <input type="checkbox" id="perm-read" value="read"> <span class="checkmark"></span> Lecture (READ) </label> <label class="checkbox-item"> <input type="checkbox" id="perm-write" value="write"> <span class="checkmark"></span> Écriture (WRITE) </label> <label class="checkbox-item"> <input type="checkbox" id="perm-execute" value="execute"> <span class="checkmark"></span> Exécution (EXECUTE) </label> </div> </div> <div class="form-group"> <label class="form-label">Description (optionnel)</label> <textarea class="form-input" id="permission-description" rows="3" placeholder="Description de cette permission..."></textarea> </div> </form> </div> <div class="modal-footer"> <button class="btn btn-secondary" id="cancel-permission">Annuler</button> <button class="btn btn-primary" id="save-permission">Enregistrer</button> </div> </div> </div> <script> class PermissionsManager { constructor() { this.permissions = []; this.users = []; this.editingId = null; this.init(); } init() { this.loadUsers(); this.loadPermissions(); this.setupEventListeners(); } setupEventListeners() { // Boutons principaux document.getElementById('add-permission').addEventListener('click', () => { this.showPermissionModal(); }); document.getElementById('export-permissions').addEventListener('click', () => { this.exportPermissions(); }); // Modal document.getElementById('close-modal').addEventListener('click', () => { this.hidePermissionModal(); }); document.getElementById('cancel-permission').addEventListener('click', () => { this.hidePermissionModal(); }); document.getElementById('save-permission').addEventListener('click', () => { this.savePermission(); }); // Filtres document.getElementById('filter-user').addEventListener('change', () => { this.applyFilters(); }); document.getElementById('filter-resource').addEventListener('input', () => { this.applyFilters(); }); document.getElementById('filter-type').addEventListener('change', () => { this.applyFilters(); }); document.getElementById('clear-filters').addEventListener('click', () => { this.clearFilters(); }); // Fermer modal en cliquant sur l'overlay document.getElementById('permission-modal').addEventListener('click', (e) => { if (e.target.id === 'permission-modal') { this.hidePermissionModal(); } }); } async loadUsers() { try { const response = await fetch('/api/users'); const data = await response.json(); // Extraire le tableau users de la réponse this.users = data.users || []; const userSelects = [ document.getElementById('filter-user'), document.getElementById('permission-user') ]; userSelects.forEach(select => { // Garder la première option const firstOption = select.firstElementChild; select.innerHTML = ''; select.appendChild(firstOption); this.users.forEach(user => { const option = document.createElement('option'); option.value = user.username; option.textContent = `${user.full_name || user.username} (${user.role})`; select.appendChild(option); }); }); } catch (error) { console.error('Erreur lors du chargement des utilisateurs:', error); this.users = []; } } async loadPermissions() { try { const response = await fetch('/api/permissions'); const data = await response.json(); // Extraire le tableau permissions de la réponse this.permissions = data.permissions || []; this.renderPermissions(); } catch (error) { console.error('Erreur lors du chargement des permissions:', error); this.permissions = []; } } renderPermissions(filteredPermissions = null) { const permissions = filteredPermissions || this.permissions; const tbody = document.getElementById('permissions-table-body'); const countEl = document.getElementById('permissions-count'); tbody.innerHTML = ''; countEl.textContent = `${permissions.length} permission${permissions.length !== 1 ? 's' : ''}`; if (permissions.length === 0) { tbody.innerHTML = ` <tr> <td colspan="5" class="text-center text-secondary py-8"> Aucune permission trouvée </td> </tr> `; return; } permissions.forEach(permission => { const row = document.createElement('tr'); row.innerHTML = ` <td> <div class="flex items-center gap-2"> <div class="permission-icon">🔑</div> <div> <div class="font-medium">${permission.name}</div> <div class="text-sm text-secondary">${permission.description}</div> </div> </div> </td> <td> <span class="badge badge-${permission.category === 'homeassistant' ? 'primary' : permission.category === 'system' ? 'warning' : 'secondary'}">${permission.category}</span> </td> <td> <div class="flex gap-1"> <span class="badge badge-${permission.enabled ? 'success' : 'secondary'}"> ${permission.enabled ? 'Activée' : 'Désactivée'} </span> </div> </td> <td class="text-sm text-secondary"> ID: ${permission.id} </td> <td> <div class="flex gap-2"> <button class="btn btn-secondary btn-sm" onclick="permissionsManager.editPermission(${permission.id})"> ✏️ </button> <button class="btn btn-danger btn-sm" onclick="permissionsManager.deletePermission(${permission.id})"> 🗑️ </button> </div> </td> `; tbody.appendChild(row); }); } showPermissionModal(permission = null) { const modal = document.getElementById('permission-modal'); const title = document.getElementById('modal-title'); if (permission) { title.textContent = 'Éditer la permission'; this.editingId = permission.id; // Remplir le formulaire document.getElementById('permission-id').value = permission.id; document.getElementById('permission-user').value = permission.username; document.getElementById('permission-resource').value = permission.resource; document.getElementById('permission-description').value = permission.description || ''; // Cocher les permissions ['read', 'write', 'execute'].forEach(perm => { document.getElementById(`perm-${perm}`).checked = permission.permissions.includes(perm); }); } else { title.textContent = 'Nouvelle permission'; this.editingId = null; document.getElementById('permission-form').reset(); } modal.classList.remove('hidden'); } hidePermissionModal() { document.getElementById('permission-modal').classList.add('hidden'); this.editingId = null; } async savePermission() { const formData = new FormData(); const username = document.getElementById('permission-user').value; const resource = document.getElementById('permission-resource').value; const description = document.getElementById('permission-description').value; const permissions = []; ['read', 'write', 'execute'].forEach(perm => { if (document.getElementById(`perm-${perm}`).checked) { permissions.push(perm); } }); if (!username || !resource || permissions.length === 0) { alert('Veuillez remplir tous les champs requis'); return; } const data = { username, resource, permissions, description }; try { const url = this.editingId ? `/api/permissions/${this.editingId}` : '/api/permissions'; const method = this.editingId ? 'PUT' : 'POST'; const response = await fetch(url, { method, headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(data) }); if (response.ok) { this.hidePermissionModal(); this.loadPermissions(); window.showToast( this.editingId ? 'Permission modifiée avec succès' : 'Permission créée avec succès', 'success' ); } else { const error = await response.json(); alert(`Erreur: ${error.detail || 'Erreur inconnue'}`); } } catch (error) { console.error('Erreur lors de l\'enregistrement:', error); alert('Erreur lors de l\'enregistrement de la permission'); } } editPermission(id) { const permission = this.permissions.find(p => p.id === id); if (permission) { this.showPermissionModal(permission); } } async deletePermission(id) { if (!confirm('Êtes-vous sûr de vouloir supprimer cette permission ?')) { return; } try { const response = await fetch(`/api/permissions/${id}`, { method: 'DELETE' }); if (response.ok) { this.loadPermissions(); window.showToast('Permission supprimée avec succès', 'success'); } else { const error = await response.json(); alert(`Erreur: ${error.detail || 'Erreur inconnue'}`); } } catch (error) { console.error('Erreur lors de la suppression:', error); alert('Erreur lors de la suppression de la permission'); } } applyFilters() { const userFilter = document.getElementById('filter-user').value; const resourceFilter = document.getElementById('filter-resource').value.toLowerCase(); const typeFilter = document.getElementById('filter-type').value; let filtered = this.permissions; if (userFilter) { filtered = filtered.filter(p => p.username === userFilter); } if (resourceFilter) { filtered = filtered.filter(p => p.resource.toLowerCase().includes(resourceFilter) ); } if (typeFilter) { filtered = filtered.filter(p => p.permissions.includes(typeFilter) ); } this.renderPermissions(filtered); } clearFilters() { document.getElementById('filter-user').value = ''; document.getElementById('filter-resource').value = ''; document.getElementById('filter-type').value = ''; this.renderPermissions(); } exportPermissions() { const data = this.permissions.map(p => ({ username: p.username, resource: p.resource, permissions: p.permissions.join(','), description: p.description || '', granted_at: p.granted_at })); const csv = this.arrayToCSV(data); this.downloadCSV(csv, 'permissions.csv'); } arrayToCSV(array) { if (array.length === 0) return ''; const headers = Object.keys(array[0]); const csvHeaders = headers.join(','); const csvRows = array.map(row => headers.map(header => `"${row[header] || ''}"`).join(',') ); return [csvHeaders, ...csvRows].join('\n'); } downloadCSV(csv, filename) { const blob = new Blob([csv], { type: 'text/csv' }); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; a.click(); window.URL.revokeObjectURL(url); } getPermissionColor(permission) { const colors = { read: 'info', write: 'warning', execute: 'danger' }; return colors[permission] || 'secondary'; } formatDate(dateString) { return new Date(dateString).toLocaleString('fr-FR'); } } // Initialiser le gestionnaire de permissions const permissionsManager = new PermissionsManager(); </script>

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Jonathan97480/McpHomeAssistant'

If you have feedback or need assistance with the MCP directory API, please join our Discord server