Update - Lions User Manager - Client (Quarkus PrimeFaces Freya)
This commit is contained in:
@@ -0,0 +1,272 @@
|
||||
<!DOCTYPE html>
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:param name="page" value="#{auditConsultationBean}"/>
|
||||
<ui:define name="title">Journal d'Audit - Lions User Manager</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/layout/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-history text-orange-500" />
|
||||
<ui:param name="title" value="Journal d'Audit" />
|
||||
<ui:param name="description" value="Consultation des logs d'audit et statistiques" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsAudit">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/shared/buttons/button-user-action.xhtml">
|
||||
<ui:param name="value" value="Exporter CSV" />
|
||||
<ui:param name="icon" value="pi pi-download" />
|
||||
<ui:param name="hasAction" value="true" />
|
||||
<ui:param name="action" value="#{auditConsultationBean.exportToCSV}" />
|
||||
<ui:param name="severity" value="success" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Statistiques avec composants réutilisables -->
|
||||
<ui:include src="/templates/components/shared/dashboard/kpi-group.xhtml">
|
||||
<ui:param name="title" value="Statistiques d'Audit" />
|
||||
<ui:param name="columns" value="4" />
|
||||
<ui:define name="kpi-content">
|
||||
<ui:include src="/templates/components/shared/cards/kpi-card.xhtml">
|
||||
<ui:param name="title" value="Total Actions" />
|
||||
<ui:param name="value" value="#{auditConsultationBean.totalRecords}" />
|
||||
<ui:param name="icon" value="pi-history" />
|
||||
<ui:param name="iconColor" value="blue-600" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/shared/cards/kpi-card.xhtml">
|
||||
<ui:param name="title" value="Actions Réussies" />
|
||||
<ui:param name="value" value="#{auditConsultationBean.successCount}" />
|
||||
<ui:param name="icon" value="pi-check-circle" />
|
||||
<ui:param name="iconColor" value="green-600" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/shared/cards/kpi-card.xhtml">
|
||||
<ui:param name="title" value="Actions Échouées" />
|
||||
<ui:param name="value" value="#{auditConsultationBean.failureCount}" />
|
||||
<ui:param name="icon" value="pi-times-circle" />
|
||||
<ui:param name="iconColor" value="red-600" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/shared/cards/kpi-card.xhtml">
|
||||
<ui:param name="title" value="Taux de Réussite" />
|
||||
<ui:param name="value" value="#{auditConsultationBean.totalRecords > 0 ? (auditConsultationBean.successCount * 100 / auditConsultationBean.totalRecords) : 0}%" />
|
||||
<ui:param name="icon" value="pi-percentage" />
|
||||
<ui:param name="iconColor" value="purple-600" />
|
||||
</ui:include>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Filtres de recherche -->
|
||||
<div class="card mb-3">
|
||||
<h:form id="formFilters">
|
||||
<p:panelGrid columns="3" styleClass="w-full" columnClasses="col-12 md:col-4">
|
||||
<p:outputLabel for="acteurFilter" value="Acteur" />
|
||||
<p:inputText id="acteurFilter"
|
||||
value="#{auditConsultationBean.acteurUsername}"
|
||||
placeholder="Nom d'utilisateur..."
|
||||
styleClass="w-full" />
|
||||
|
||||
<p:outputLabel for="typeActionFilter" value="Type d'action" />
|
||||
<p:selectOneMenu id="typeActionFilter"
|
||||
value="#{auditConsultationBean.selectedTypeAction}"
|
||||
styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous les types" itemValue="" />
|
||||
<f:selectItems value="#{auditConsultationBean.typeActionOptions}" />
|
||||
</p:selectOneMenu>
|
||||
|
||||
<p:outputLabel for="succesFilter" value="Résultat" />
|
||||
<p:selectOneMenu id="succesFilter"
|
||||
value="#{auditConsultationBean.succes}"
|
||||
styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous" itemValue="" />
|
||||
<f:selectItem itemLabel="Succès" itemValue="true" />
|
||||
<f:selectItem itemLabel="Échec" itemValue="false" />
|
||||
</p:selectOneMenu>
|
||||
|
||||
<p:outputLabel for="dateDebutFilter" value="Date début" />
|
||||
<p:calendar id="dateDebutFilter"
|
||||
value="#{auditConsultationBean.dateDebut}"
|
||||
pattern="dd/MM/yyyy"
|
||||
styleClass="w-full" />
|
||||
|
||||
<p:outputLabel for="dateFinFilter" value="Date fin" />
|
||||
<p:calendar id="dateFinFilter"
|
||||
value="#{auditConsultationBean.dateFin}"
|
||||
pattern="dd/MM/yyyy"
|
||||
styleClass="w-full" />
|
||||
|
||||
<p:outputLabel for="ressourceFilter" value="Type ressource" />
|
||||
<p:inputText id="ressourceFilter"
|
||||
value="#{auditConsultationBean.ressourceType}"
|
||||
placeholder="USER, ROLE..."
|
||||
styleClass="w-full" />
|
||||
</p:panelGrid>
|
||||
|
||||
<div class="flex gap-2 justify-content-end mt-3">
|
||||
<p:commandButton
|
||||
value="Rechercher"
|
||||
icon="pi pi-search"
|
||||
styleClass="p-button-primary"
|
||||
action="#{auditConsultationBean.searchLogs}"
|
||||
update="formAuditLogs:auditLogsTable" />
|
||||
<p:commandButton
|
||||
value="Réinitialiser"
|
||||
icon="pi pi-refresh"
|
||||
styleClass="p-button-secondary"
|
||||
action="#{auditConsultationBean.resetFilters}"
|
||||
update="formAuditLogs:auditLogsTable @form" />
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Liste des logs avec p:dataTable -->
|
||||
<div class="card">
|
||||
<h:form id="formAuditLogs">
|
||||
<h5>Logs d'Audit</h5>
|
||||
<p:dataTable
|
||||
id="auditLogsTable"
|
||||
value="#{auditConsultationBean.auditLogs}"
|
||||
var="log"
|
||||
rowKey="#{log.id}"
|
||||
paginator="true"
|
||||
rows="20"
|
||||
rowsPerPageTemplate="10,20,50,100"
|
||||
emptyMessage="Aucun log d'audit trouvé"
|
||||
styleClass="w-full">
|
||||
|
||||
<!-- Colonne Statut -->
|
||||
<p:column headerText="Statut" style="width: 5rem">
|
||||
<p:tag
|
||||
value="#{log.succes ? 'Succès' : 'Échec'}"
|
||||
severity="#{log.succes ? 'success' : 'danger'}"
|
||||
styleClass="text-xs" />
|
||||
</p:column>
|
||||
|
||||
<!-- Colonne Type d'action -->
|
||||
<p:column headerText="Type d'action" sortBy="#{log.typeAction}" style="width: 15%">
|
||||
<strong class="text-900">#{log.typeAction}</strong>
|
||||
</p:column>
|
||||
|
||||
<!-- Colonne Acteur -->
|
||||
<p:column headerText="Acteur" sortBy="#{log.acteurUsername}" style="width: 15%">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-user text-color-secondary"></i>
|
||||
<span>#{log.acteurUsername}</span>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<!-- Colonne Ressource -->
|
||||
<p:column headerText="Ressource" style="width: 12%">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-database text-color-secondary"></i>
|
||||
<span>#{log.ressourceType}</span>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<!-- Colonne Date -->
|
||||
<p:column headerText="Date" sortBy="#{log.dateAction}" style="width: 15%">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-calendar text-color-secondary"></i>
|
||||
<span>#{log.dateAction}</span>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<!-- Colonne Détails -->
|
||||
<p:column headerText="Détails" style="width: 20%">
|
||||
<c:if test="#{not empty log.details}">
|
||||
<span class="text-color-secondary text-sm">#{log.details}</span>
|
||||
</c:if>
|
||||
<c:if test="#{empty log.details}">
|
||||
<span class="text-color-secondary text-sm">-</span>
|
||||
</c:if>
|
||||
</p:column>
|
||||
|
||||
<!-- Colonne IP -->
|
||||
<p:column headerText="IP" style="width: 10%">
|
||||
<c:if test="#{not empty log.adresseIp}">
|
||||
<span class="text-color-secondary text-sm">#{log.adresseIp}</span>
|
||||
</c:if>
|
||||
<c:if test="#{empty log.adresseIp}">
|
||||
<span class="text-color-secondary text-sm">-</span>
|
||||
</c:if>
|
||||
</p:column>
|
||||
|
||||
<!-- Colonne Actions -->
|
||||
<p:column headerText="Actions" style="width: 8%">
|
||||
<p:commandButton
|
||||
icon="pi pi-eye"
|
||||
styleClass="p-button-text p-button-sm"
|
||||
title="Voir les détails"
|
||||
onclick="PF('auditLogDetailsDialog').show()">
|
||||
<f:setPropertyActionListener target="#{auditConsultationBean.selectedLog}" value="#{log}" />
|
||||
</p:commandButton>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Dialog de détails -->
|
||||
<p:dialog
|
||||
id="auditLogDetailsDialog"
|
||||
widgetVar="auditLogDetailsDialog"
|
||||
header="Détails du Log d'Audit"
|
||||
modal="true"
|
||||
resizable="false"
|
||||
styleClass="w-full md:w-30rem">
|
||||
<h:form id="formAuditLogDetails">
|
||||
<c:if test="#{not empty auditConsultationBean.selectedLog}">
|
||||
<div class="flex flex-column gap-3">
|
||||
<div>
|
||||
<strong>Type d'action:</strong>
|
||||
<p>#{auditConsultationBean.selectedLog.typeAction}</p>
|
||||
</div>
|
||||
<div>
|
||||
<strong>Acteur:</strong>
|
||||
<p>#{auditConsultationBean.selectedLog.acteurUsername}</p>
|
||||
</div>
|
||||
<div>
|
||||
<strong>Ressource:</strong>
|
||||
<p>#{auditConsultationBean.selectedLog.ressourceType} - #{auditConsultationBean.selectedLog.ressourceId}</p>
|
||||
</div>
|
||||
<div>
|
||||
<strong>Date:</strong>
|
||||
<p>#{auditConsultationBean.selectedLog.dateAction}</p>
|
||||
</div>
|
||||
<c:if test="#{not empty auditConsultationBean.selectedLog.details}">
|
||||
<div>
|
||||
<strong>Détails:</strong>
|
||||
<p>#{auditConsultationBean.selectedLog.details}</p>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="#{not empty auditConsultationBean.selectedLog.adresseIp}">
|
||||
<div>
|
||||
<strong>Adresse IP:</strong>
|
||||
<p>#{auditConsultationBean.selectedLog.adresseIp}</p>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="#{not empty auditConsultationBean.selectedLog.userAgent}">
|
||||
<div>
|
||||
<strong>User Agent:</strong>
|
||||
<p>#{auditConsultationBean.selectedLog.userAgent}</p>
|
||||
</div>
|
||||
</c:if>
|
||||
<c:if test="#{not empty auditConsultationBean.selectedLog.messageErreur}">
|
||||
<div>
|
||||
<strong class="text-red-600">Message d'erreur:</strong>
|
||||
<p class="text-red-600">#{auditConsultationBean.selectedLog.messageErreur}</p>
|
||||
</div>
|
||||
</c:if>
|
||||
</div>
|
||||
</c:if>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
@@ -0,0 +1,175 @@
|
||||
<!DOCTYPE html>
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">Tableau de Bord - Lions User Manager</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<h:form id="formDashboard">
|
||||
<div class="grid">
|
||||
<!-- En-tête -->
|
||||
<div class="col-12">
|
||||
<ui:include src="/templates/components/layout/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-home text-blue-500" />
|
||||
<ui:param name="title" value="Tableau de Bord" />
|
||||
<ui:param name="description" value="Vue d'ensemble de la gestion des utilisateurs Keycloak" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formRefresh">
|
||||
<p:commandButton
|
||||
value="Rafraîchir"
|
||||
icon="pi pi-refresh"
|
||||
styleClass="p-button-secondary"
|
||||
action="#{dashboardBean.refreshStatistics}"
|
||||
update=":formDashboard" />
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- KPIs Principaux avec composant réutilisable -->
|
||||
<div class="col-12">
|
||||
<ui:include src="/templates/components/shared/dashboard/kpi-group.xhtml">
|
||||
<ui:param name="title" value="Statistiques Principales" />
|
||||
<ui:param name="columns" value="4" />
|
||||
<ui:define name="kpi-content">
|
||||
<!-- KPI 1: Utilisateurs Actifs -->
|
||||
<ui:include src="/templates/components/shared/cards/kpi-card.xhtml">
|
||||
<ui:param name="title" value="Utilisateurs Actifs" />
|
||||
<ui:param name="value" value="#{dashboardBean.totalUsersDisplay}" />
|
||||
<ui:param name="icon" value="pi-users" />
|
||||
<ui:param name="iconColor" value="blue-600" />
|
||||
<ui:param name="subtitle" value="Total utilisateurs" />
|
||||
<ui:param name="clickable" value="true" />
|
||||
<ui:param name="clickOutcome" value="/pages/user-manager/users/list" />
|
||||
</ui:include>
|
||||
|
||||
<!-- KPI 2: Rôles Realm -->
|
||||
<ui:include src="/templates/components/shared/cards/kpi-card.xhtml">
|
||||
<ui:param name="title" value="Rôles Realm" />
|
||||
<ui:param name="value" value="#{dashboardBean.totalRolesDisplay}" />
|
||||
<ui:param name="icon" value="pi-shield" />
|
||||
<ui:param name="iconColor" value="green-600" />
|
||||
<ui:param name="subtitle" value="Rôles configurés" />
|
||||
<ui:param name="clickable" value="true" />
|
||||
<ui:param name="clickOutcome" value="/pages/user-manager/roles/list" />
|
||||
</ui:include>
|
||||
|
||||
<!-- KPI 3: Actions Récentes -->
|
||||
<ui:include src="/templates/components/shared/cards/kpi-card.xhtml">
|
||||
<ui:param name="title" value="Actions Récentes" />
|
||||
<ui:param name="value" value="#{dashboardBean.recentActionsDisplay}" />
|
||||
<ui:param name="icon" value="pi-history" />
|
||||
<ui:param name="iconColor" value="orange-600" />
|
||||
<ui:param name="subtitle" value="Dernières 24h" />
|
||||
<ui:param name="clickable" value="true" />
|
||||
<ui:param name="clickOutcome" value="/pages/user-manager/audit/logs" />
|
||||
</ui:include>
|
||||
|
||||
<!-- KPI 4: Rôles Client -->
|
||||
<ui:include src="/templates/components/shared/cards/kpi-card.xhtml">
|
||||
<ui:param name="title" value="Rôles Client" />
|
||||
<ui:param name="value" value="-" />
|
||||
<ui:param name="icon" value="pi-key" />
|
||||
<ui:param name="iconColor" value="purple-600" />
|
||||
<ui:param name="subtitle" value="Rôles clients configurés" />
|
||||
<ui:param name="clickable" value="true" />
|
||||
<ui:param name="clickOutcome" value="/pages/user-manager/roles/list" />
|
||||
</ui:include>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
|
||||
<!-- Actions Rapides -->
|
||||
<ui:include src="/templates/components/shared/dashboard/dashboard-section.xhtml">
|
||||
<ui:param name="title" value="Actions Rapides" />
|
||||
<ui:param name="icon" value="pi-bolt" />
|
||||
<ui:param name="colSize" value="col-12 lg:col-6" />
|
||||
<ui:define name="section-content">
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6">
|
||||
<h:form>
|
||||
<p:commandButton
|
||||
value="Nouvel Utilisateur"
|
||||
icon="pi pi-user-plus"
|
||||
styleClass="w-full p-button-success"
|
||||
outcome="/pages/user-manager/users/create" />
|
||||
</h:form>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<h:form>
|
||||
<p:commandButton
|
||||
value="Liste des Utilisateurs"
|
||||
icon="pi pi-users"
|
||||
styleClass="w-full p-button-primary"
|
||||
outcome="/pages/user-manager/users/list" />
|
||||
</h:form>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<h:form>
|
||||
<p:commandButton
|
||||
value="Gestion des Rôles"
|
||||
icon="pi pi-shield"
|
||||
styleClass="w-full p-button-info"
|
||||
outcome="/pages/user-manager/roles/list" />
|
||||
</h:form>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<h:form>
|
||||
<p:commandButton
|
||||
value="Journal d'Audit"
|
||||
icon="pi pi-history"
|
||||
styleClass="w-full p-button-help"
|
||||
outcome="/pages/user-manager/audit/logs" />
|
||||
</h:form>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Informations Système -->
|
||||
<ui:include src="/templates/components/shared/dashboard/dashboard-section.xhtml">
|
||||
<ui:param name="title" value="Informations Système" />
|
||||
<ui:param name="icon" value="pi-info-circle" />
|
||||
<ui:param name="colSize" value="col-12 lg:col-6" />
|
||||
<ui:define name="section-content">
|
||||
<div class="flex flex-column gap-2">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span class="text-600">Version</span>
|
||||
<span class="font-semibold">1.0.0</span>
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span class="text-600">Realm Keycloak</span>
|
||||
<span class="font-semibold">lions-user-manager</span>
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span class="text-600">Statut</span>
|
||||
<p:tag value="Opérationnel" severity="success" />
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span class="text-600">Application</span>
|
||||
<span class="font-semibold">Lions User Manager</span>
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span class="text-600">Environnement</span>
|
||||
<span class="font-semibold">Développement</span>
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span class="text-600">Base de données</span>
|
||||
<span class="font-semibold">Keycloak Admin API</span>
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span class="text-600">Framework</span>
|
||||
<span class="font-semibold">Quarkus, PrimeFaces Freya</span>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
@@ -0,0 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:param name="page" value="#{userProfilBean}"/>
|
||||
<ui:define name="title">Attribution de Rôles - Lions User Manager</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/layout/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-key text-purple-500" />
|
||||
<ui:param name="title" value="Attribution de Rôles" />
|
||||
<ui:param name="description" value="Gérer les rôles de l'utilisateur" />
|
||||
</ui:include>
|
||||
|
||||
<!-- Attribution de rôles -->
|
||||
<div class="card">
|
||||
<ui:include src="/templates/components/role-management/role-assignment.xhtml">
|
||||
<ui:param name="user" value="#{userProfilBean.user}" />
|
||||
<ui:param name="availableRoles" value="#{roleGestionBean.allRoles}" />
|
||||
<ui:param name="userRoles" value="#{roleGestionBean.getUserRolesDTOs(userProfilBean.user)}" />
|
||||
<ui:param name="update" value="@form" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
<!DOCTYPE html>
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:param name="page" value="#{roleGestionBean}"/>
|
||||
<ui:define name="title">Gestion des Rôles - Lions User Manager</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/layout/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-shield text-purple-500" />
|
||||
<ui:param name="title" value="Gestion des Rôles" />
|
||||
<ui:param name="description" value="Gestion des rôles Realm et Client Keycloak" />
|
||||
<ui:define name="actions">
|
||||
<h:form id="formActionsRoles">
|
||||
<div class="flex gap-2">
|
||||
<ui:include src="/templates/components/shared/buttons/button-user-action.xhtml">
|
||||
<ui:param name="value" value="Nouveau Rôle Realm" />
|
||||
<ui:param name="icon" value="pi pi-plus" />
|
||||
<ui:param name="hasAction" value="false" />
|
||||
<ui:param name="hasOutcome" value="false" />
|
||||
<ui:param name="onclick" value="PF('createRealmRoleDialog').show()" />
|
||||
<ui:param name="severity" value="success" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/shared/buttons/button-user-action.xhtml">
|
||||
<ui:param name="value" value="Nouveau Rôle Client" />
|
||||
<ui:param name="icon" value="pi pi-plus-circle" />
|
||||
<ui:param name="hasAction" value="false" />
|
||||
<ui:param name="hasOutcome" value="false" />
|
||||
<ui:param name="onclick" value="PF('createClientRoleDialog').show()" />
|
||||
<ui:param name="severity" value="info" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</h:form>
|
||||
</ui:define>
|
||||
</ui:include>
|
||||
|
||||
<!-- Filtres -->
|
||||
<div class="card mb-3">
|
||||
<h:form id="formFilters">
|
||||
<p:panelGrid columns="3" styleClass="w-full" columnClasses="col-12 md:col-4">
|
||||
<p:outputLabel for="realmFilter" value="Realm" />
|
||||
<p:selectOneMenu id="realmFilter"
|
||||
value="#{roleGestionBean.realmName}"
|
||||
styleClass="w-full">
|
||||
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
|
||||
<f:selectItems value="#{roleGestionBean.availableRealms}" />
|
||||
<p:ajax event="change"
|
||||
listener="#{roleGestionBean.loadRealmRoles}"
|
||||
update=":formRealmRoles:realmRolesPanel :formClientRoles:clientRolesPanel" />
|
||||
</p:selectOneMenu>
|
||||
|
||||
<p:outputLabel for="clientFilter" value="Client" />
|
||||
<p:selectOneMenu id="clientFilter"
|
||||
value="#{roleGestionBean.clientName}"
|
||||
styleClass="w-full">
|
||||
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
|
||||
<f:selectItems value="#{roleGestionBean.availableClients}" />
|
||||
<p:ajax event="change"
|
||||
listener="#{roleGestionBean.loadClientRoles}"
|
||||
update=":formClientRoles:clientRolesPanel" />
|
||||
</p:selectOneMenu>
|
||||
|
||||
<p:outputLabel for="typeFilter" value="Type" />
|
||||
<p:selectOneMenu id="typeFilter"
|
||||
value="#{roleGestionBean.selectedTypeRole}"
|
||||
styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous les types" itemValue="" />
|
||||
<f:selectItems value="#{roleGestionBean.typeRoleOptions}" />
|
||||
</p:selectOneMenu>
|
||||
</p:panelGrid>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Rôles Realm -->
|
||||
<div class="card mb-3">
|
||||
<h:form id="formRealmRoles">
|
||||
<p:panel id="realmRolesPanel" header="Rôles Realm" toggleable="true" collapsed="false">
|
||||
<div class="grid">
|
||||
<c:forEach var="role" items="#{roleGestionBean.realmRoles}">
|
||||
<div class="col-12 md:col-6 lg:col-4">
|
||||
<ui:include src="/templates/components/role-management/role-card.xhtml">
|
||||
<ui:param name="role" value="#{role}" />
|
||||
<ui:param name="showActions" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</c:forEach>
|
||||
<c:if test="#{empty roleGestionBean.realmRoles}">
|
||||
<div class="col-12">
|
||||
<p class="text-center text-color-secondary">Aucun rôle Realm trouvé</p>
|
||||
</div>
|
||||
</c:if>
|
||||
</div>
|
||||
</p:panel>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Rôles Client -->
|
||||
<div class="card">
|
||||
<h:form id="formClientRoles">
|
||||
<p:panel id="clientRolesPanel" header="Rôles Client" toggleable="true" collapsed="false">
|
||||
<div class="grid">
|
||||
<c:forEach var="role" items="#{roleGestionBean.clientRoles}">
|
||||
<div class="col-12 md:col-6 lg:col-4">
|
||||
<ui:include src="/templates/components/role-management/role-card.xhtml">
|
||||
<ui:param name="role" value="#{role}" />
|
||||
<ui:param name="showActions" value="true" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</c:forEach>
|
||||
<c:if test="#{empty roleGestionBean.clientRoles}">
|
||||
<div class="col-12">
|
||||
<p class="text-center text-color-secondary">Aucun rôle Client trouvé</p>
|
||||
</div>
|
||||
</c:if>
|
||||
</div>
|
||||
</p:panel>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- Dialog Création Rôle Realm -->
|
||||
<p:dialog id="createRealmRoleDialog"
|
||||
header="Nouveau Rôle Realm"
|
||||
widgetVar="createRealmRoleDialog"
|
||||
modal="true"
|
||||
styleClass="w-full md:w-6">
|
||||
<h:form id="formCreateRealmRole">
|
||||
<ui:include src="/templates/components/role-management/role-form.xhtml">
|
||||
<ui:param name="role" value="#{roleGestionBean.newRole}" />
|
||||
<ui:param name="mode" value="create" />
|
||||
<ui:param name="showClientSelector" value="false" />
|
||||
<ui:param name="submitAction" value="#{roleGestionBean.createRealmRole}" />
|
||||
<ui:param name="hasSubmitAction" value="true" />
|
||||
<ui:param name="update" value=":formRealmRoles:realmRolesPanel" />
|
||||
<ui:param name="useParentForm" value="true" />
|
||||
</ui:include>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
|
||||
<!-- Dialog Création Rôle Client -->
|
||||
<p:dialog id="createClientRoleDialog"
|
||||
header="Nouveau Rôle Client"
|
||||
widgetVar="createClientRoleDialog"
|
||||
modal="true"
|
||||
styleClass="w-full md:w-6">
|
||||
<h:form id="formCreateClientRole">
|
||||
<ui:include src="/templates/components/role-management/role-form.xhtml">
|
||||
<ui:param name="role" value="#{roleGestionBean.newRole}" />
|
||||
<ui:param name="mode" value="create" />
|
||||
<ui:param name="showClientSelector" value="true" />
|
||||
<ui:param name="submitAction" value="#{roleGestionBean.createClientRole}" />
|
||||
<ui:param name="hasSubmitAction" value="true" />
|
||||
<ui:param name="update" value=":formClientRoles:clientRolesPanel" />
|
||||
<ui:param name="useParentForm" value="true" />
|
||||
</ui:include>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
<!DOCTYPE html>
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:param name="page" value="#{settingsBean}"/>
|
||||
<ui:define name="title">Paramètres - Lions User Manager</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/layout/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-cog text-blue-500" />
|
||||
<ui:param name="title" value="Paramètres" />
|
||||
<ui:param name="description" value="Gérer vos préférences et paramètres de compte" />
|
||||
</ui:include>
|
||||
|
||||
<div class="grid">
|
||||
<!-- Informations du compte -->
|
||||
<div class="col-12 lg:col-8">
|
||||
<div class="card">
|
||||
<h5>Informations du compte</h5>
|
||||
<h:form id="formAccountInfo">
|
||||
<p:panelGrid columns="2" styleClass="w-full" columnClasses="col-12 md:col-4, col-12 md:col-8">
|
||||
<p:outputLabel for="username" value="Nom d'utilisateur" />
|
||||
<p:inputText id="username"
|
||||
value="#{userSessionBean.username}"
|
||||
readonly="true"
|
||||
styleClass="w-full" />
|
||||
|
||||
<p:outputLabel for="email" value="Email" />
|
||||
<p:inputText id="email"
|
||||
value="#{userSessionBean.email}"
|
||||
readonly="true"
|
||||
styleClass="w-full" />
|
||||
|
||||
<p:outputLabel for="fullName" value="Nom complet" />
|
||||
<p:inputText id="fullName"
|
||||
value="#{userSessionBean.fullName}"
|
||||
readonly="true"
|
||||
styleClass="w-full" />
|
||||
|
||||
<p:outputLabel for="mainRole" value="Rôle principal" />
|
||||
<p:inputText id="mainRole"
|
||||
value="#{userSessionBean.mainRole}"
|
||||
readonly="true"
|
||||
styleClass="w-full" />
|
||||
</p:panelGrid>
|
||||
</h:form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Préférences -->
|
||||
<div class="col-12 lg:col-4">
|
||||
<div class="card">
|
||||
<h5>Préférences</h5>
|
||||
<h:form id="formPreferences">
|
||||
<div class="flex flex-column gap-3">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span class="text-600">Thème des composants</span>
|
||||
<p:selectOneMenu value="#{guestPreferences.componentTheme}"
|
||||
styleClass="w-12rem">
|
||||
<f:selectItems value="#{guestPreferences.componentThemes}"
|
||||
var="theme"
|
||||
itemLabel="#{theme.name}"
|
||||
itemValue="#{theme.file}" />
|
||||
<p:ajax event="change" update="@form" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span class="text-600">Mode sombre</span>
|
||||
<p:selectOneMenu value="#{guestPreferences.darkMode}"
|
||||
styleClass="w-12rem">
|
||||
<f:selectItem itemLabel="Clair" itemValue="light" />
|
||||
<f:selectItem itemLabel="Sombre" itemValue="dark" />
|
||||
<p:ajax event="change" update="@form" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<span class="text-600">Style d'input</span>
|
||||
<p:selectOneMenu value="#{guestPreferences.inputStyle}"
|
||||
styleClass="w-12rem">
|
||||
<f:selectItem itemLabel="Outlined" itemValue="outlined" />
|
||||
<f:selectItem itemLabel="Filled" itemValue="filled" />
|
||||
<p:ajax event="change" update="@form" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<h5>Actions</h5>
|
||||
<div class="flex gap-2">
|
||||
<h:form>
|
||||
<p:commandButton
|
||||
value="Rafraîchir les informations"
|
||||
icon="pi pi-refresh"
|
||||
styleClass="p-button-secondary"
|
||||
action="#{userSessionBean.loadUserInfo}"
|
||||
update="formAccountInfo" />
|
||||
</h:form>
|
||||
<h:form>
|
||||
<p:commandButton
|
||||
value="Changer le mot de passe"
|
||||
icon="pi pi-key"
|
||||
styleClass="p-button-info"
|
||||
outcome="/pages/user-manager/users/profile" />
|
||||
</h:form>
|
||||
<h:form>
|
||||
<p:commandButton
|
||||
value="Sauvegarder les préférences"
|
||||
icon="pi pi-save"
|
||||
styleClass="p-button-success"
|
||||
action="#{settingsBean.savePreferences}"
|
||||
update="@form" />
|
||||
</h:form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:define name="title">Synchronisation Keycloak - Lions User Manager</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/layout/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-sync text-blue-500" />
|
||||
<ui:param name="title" value="Synchronisation Keycloak" />
|
||||
<ui:param name="description" value="Synchronisation et vérification de l'état de Keycloak" />
|
||||
</ui:include>
|
||||
|
||||
<!-- Health Checks -->
|
||||
<div class="grid mb-4">
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="card">
|
||||
<h5>État de Keycloak</h5>
|
||||
<p:outputLabel value="Vérification de la connexion..." />
|
||||
<!-- TODO: Intégrer SyncServiceClient pour afficher le statut -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="card">
|
||||
<h5>Actions de Synchronisation</h5>
|
||||
<div class="flex flex-column gap-2">
|
||||
<ui:include src="/templates/components/shared/buttons/button-user-action.xhtml">
|
||||
<ui:param name="value" value="Synchroniser Utilisateurs" />
|
||||
<ui:param name="icon" value="pi pi-users" />
|
||||
<ui:param name="severity" value="primary" />
|
||||
</ui:include>
|
||||
<ui:include src="/templates/components/shared/buttons/button-user-action.xhtml">
|
||||
<ui:param name="value" value="Synchroniser Rôles" />
|
||||
<ui:param name="icon" value="pi pi-shield" />
|
||||
<ui:param name="severity" value="info" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
|
||||
@@ -0,0 +1,333 @@
|
||||
<!DOCTYPE html>
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:param name="page" value="#{userCreationBean}"/>
|
||||
<ui:define name="title">Nouvel Utilisateur - Lions User Manager</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<!-- ================================================================
|
||||
EN-TÊTE DE LA PAGE
|
||||
================================================================ -->
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-user-plus text-green-500" style="font-size: 2rem"></i>
|
||||
<div>
|
||||
<h3 class="m-0 mb-1">Nouvel Utilisateur</h3>
|
||||
<p class="text-600 m-0">Créer un nouvel utilisateur dans Keycloak</p>
|
||||
</div>
|
||||
</div>
|
||||
<h:link outcome="/pages/user-manager/users/list" styleClass="p-button p-button-text">
|
||||
<i class="pi pi-arrow-left mr-2"></i>
|
||||
Retour à la liste
|
||||
</h:link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
FORMULAIRE DE CRÉATION
|
||||
================================================================ -->
|
||||
<h:form id="formUserCreation">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<h3 class="text-900 font-semibold text-lg mb-4 flex align-items-center gap-2">
|
||||
<i class="pi pi-info-circle text-blue-500"></i>
|
||||
Informations de l'Utilisateur
|
||||
</h3>
|
||||
|
||||
<div class="grid">
|
||||
<!-- Colonne gauche: Informations de base -->
|
||||
<div class="col-12 lg:col-6">
|
||||
<div class="surface-50 border-round p-3 mb-3">
|
||||
<h4 class="text-900 font-semibold mb-3 flex align-items-center gap-2">
|
||||
<i class="pi pi-user text-blue-500"></i>
|
||||
<span>Informations de Base</span>
|
||||
</h4>
|
||||
|
||||
<!-- Nom d'utilisateur -->
|
||||
<div class="field mb-3">
|
||||
<label for="username" class="block text-900 font-medium mb-2">
|
||||
Nom d'utilisateur <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<p:inputText id="username"
|
||||
value="#{userCreationBean.newUser.username}"
|
||||
styleClass="w-full"
|
||||
required="true"
|
||||
placeholder="ex: jdupont">
|
||||
<f:validateLength minimum="3" maximum="50" />
|
||||
</p:inputText>
|
||||
<small class="text-500">Identifiant unique de connexion</small>
|
||||
</div>
|
||||
|
||||
<!-- Email -->
|
||||
<div class="field mb-3">
|
||||
<label for="email" class="block text-900 font-medium mb-2">
|
||||
Adresse email <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<p:inputText id="email"
|
||||
value="#{userCreationBean.newUser.email}"
|
||||
styleClass="w-full"
|
||||
required="true"
|
||||
type="email"
|
||||
placeholder="ex: jean.dupont@example.com">
|
||||
<f:validateRegex pattern="^[A-Za-z0-9+_.-]+@(.+)$" />
|
||||
</p:inputText>
|
||||
</div>
|
||||
|
||||
<!-- Prénom -->
|
||||
<div class="field mb-3">
|
||||
<label for="prenom" class="block text-900 font-medium mb-2">
|
||||
Prénom <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<p:inputText id="prenom"
|
||||
value="#{userCreationBean.newUser.prenom}"
|
||||
styleClass="w-full"
|
||||
required="true"
|
||||
placeholder="ex: Jean">
|
||||
<f:validateLength minimum="2" maximum="100" />
|
||||
</p:inputText>
|
||||
</div>
|
||||
|
||||
<!-- Nom -->
|
||||
<div class="field mb-0">
|
||||
<label for="nom" class="block text-900 font-medium mb-2">
|
||||
Nom <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<p:inputText id="nom"
|
||||
value="#{userCreationBean.newUser.nom}"
|
||||
styleClass="w-full"
|
||||
required="true"
|
||||
placeholder="ex: Dupont">
|
||||
<f:validateLength minimum="2" maximum="100" />
|
||||
</p:inputText>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Colonne droite: Mot de passe et Configuration -->
|
||||
<div class="col-12 lg:col-6">
|
||||
<!-- Section Mot de passe -->
|
||||
<div class="surface-50 border-round p-3 mb-3">
|
||||
<h4 class="text-900 font-semibold mb-3 flex align-items-center gap-2">
|
||||
<i class="pi pi-key text-orange-500"></i>
|
||||
<span>Mot de Passe</span>
|
||||
</h4>
|
||||
|
||||
<!-- Mot de passe -->
|
||||
<div class="field mb-3">
|
||||
<label for="password" class="block text-900 font-medium mb-2">
|
||||
Mot de passe <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<p:password id="password"
|
||||
value="#{userCreationBean.password}"
|
||||
styleClass="w-full"
|
||||
required="true"
|
||||
feedback="true"
|
||||
toggleMask="true"
|
||||
placeholder="Minimum 8 caractères">
|
||||
<f:validateLength minimum="8" maximum="100" />
|
||||
</p:password>
|
||||
<small class="text-500">Au moins 8 caractères</small>
|
||||
</div>
|
||||
|
||||
<!-- Confirmation mot de passe -->
|
||||
<div class="field mb-0">
|
||||
<label for="passwordConfirm" class="block text-900 font-medium mb-2">
|
||||
Confirmer le mot de passe <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<p:password id="passwordConfirm"
|
||||
value="#{userCreationBean.passwordConfirm}"
|
||||
styleClass="w-full"
|
||||
required="true"
|
||||
feedback="false"
|
||||
toggleMask="true"
|
||||
placeholder="Confirmer le mot de passe">
|
||||
</p:password>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Section Configuration -->
|
||||
<div class="surface-50 border-round p-3">
|
||||
<h4 class="text-900 font-semibold mb-3 flex align-items-center gap-2">
|
||||
<i class="pi pi-cog text-purple-500"></i>
|
||||
<span>Configuration</span>
|
||||
</h4>
|
||||
|
||||
<!-- Realm -->
|
||||
<div class="field mb-3">
|
||||
<label for="realm" class="block text-900 font-medium mb-2">
|
||||
Realm Keycloak
|
||||
</label>
|
||||
<p:selectOneMenu id="realm"
|
||||
value="#{userCreationBean.realmName}"
|
||||
styleClass="w-full">
|
||||
<f:selectItems value="#{userCreationBean.availableRealms}"
|
||||
var="realm"
|
||||
itemLabel="#{realm}"
|
||||
itemValue="#{realm}" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
<!-- Options de configuration -->
|
||||
<div class="flex flex-column gap-2">
|
||||
<!-- Compte activé -->
|
||||
<div class="field-checkbox mb-0">
|
||||
<p:selectBooleanCheckbox id="enabled"
|
||||
value="#{userCreationBean.newUser.enabled}">
|
||||
</p:selectBooleanCheckbox>
|
||||
<label for="enabled" class="ml-2">Compte activé</label>
|
||||
</div>
|
||||
|
||||
<!-- Email vérifié -->
|
||||
<div class="field-checkbox mb-0">
|
||||
<p:selectBooleanCheckbox id="emailVerified"
|
||||
value="#{userCreationBean.newUser.emailVerified}">
|
||||
</p:selectBooleanCheckbox>
|
||||
<label for="emailVerified" class="ml-2">Email vérifié</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
ACTIONS
|
||||
================================================================ -->
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<h3 class="text-900 font-semibold text-lg mb-4 flex align-items-center gap-2">
|
||||
<i class="pi pi-check-circle text-green-500"></i>
|
||||
Actions
|
||||
</h3>
|
||||
|
||||
<div class="flex flex-wrap gap-2 align-items-center">
|
||||
<!-- Bouton Créer -->
|
||||
<p:commandButton value="Créer l'utilisateur"
|
||||
icon="pi pi-check"
|
||||
styleClass="p-button-success"
|
||||
action="#{userCreationBean.createUser}"
|
||||
update=":formUserCreation"
|
||||
validateClient="true">
|
||||
</p:commandButton>
|
||||
|
||||
<!-- Bouton Réinitialiser -->
|
||||
<p:commandButton value="Réinitialiser"
|
||||
icon="pi pi-refresh"
|
||||
styleClass="p-button-outlined p-button-secondary"
|
||||
action="#{userCreationBean.resetForm}"
|
||||
update=":formUserCreation"
|
||||
immediate="true">
|
||||
<p:confirm header="Confirmation"
|
||||
message="Voulez-vous vraiment réinitialiser le formulaire ?"
|
||||
icon="pi pi-exclamation-triangle" />
|
||||
</p:commandButton>
|
||||
|
||||
<!-- Bouton Annuler -->
|
||||
<p:commandButton value="Annuler"
|
||||
icon="pi pi-times"
|
||||
styleClass="p-button-outlined"
|
||||
action="#{userCreationBean.cancel}"
|
||||
immediate="true">
|
||||
<p:confirm header="Confirmation"
|
||||
message="Voulez-vous vraiment annuler la création ?"
|
||||
icon="pi pi-exclamation-triangle" />
|
||||
</p:commandButton>
|
||||
|
||||
<div class="flex-grow-1"></div>
|
||||
|
||||
<!-- Aide -->
|
||||
<p:commandButton value="Aide"
|
||||
icon="pi pi-question-circle"
|
||||
styleClass="p-button-outlined p-button-help"
|
||||
type="button"
|
||||
onclick="PF('helpDialog').show();">
|
||||
</p:commandButton>
|
||||
</div>
|
||||
|
||||
<!-- Message d'information -->
|
||||
<p:messages id="messages" showDetail="true" closable="true" styleClass="mt-3">
|
||||
<p:autoUpdate />
|
||||
</p:messages>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
DIALOG DE CONFIRMATION
|
||||
================================================================ -->
|
||||
<p:confirmDialog global="true" showEffect="fade" hideEffect="fade"
|
||||
responsive="true" width="400">
|
||||
<p:commandButton value="Non" type="button"
|
||||
styleClass="p-button-text"
|
||||
icon="pi pi-times" />
|
||||
<p:commandButton value="Oui" type="button"
|
||||
styleClass="p-button-primary"
|
||||
icon="pi pi-check" />
|
||||
</p:confirmDialog>
|
||||
|
||||
<!-- ================================================================
|
||||
DIALOG D'AIDE
|
||||
================================================================ -->
|
||||
<p:dialog header="Aide - Création d'Utilisateur"
|
||||
widgetVar="helpDialog"
|
||||
modal="true"
|
||||
responsive="true"
|
||||
width="600"
|
||||
showEffect="fade"
|
||||
hideEffect="fade">
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<h4 class="text-900 font-semibold flex align-items-center gap-2 mb-3">
|
||||
<i class="pi pi-info-circle text-blue-500"></i>
|
||||
Informations Requises
|
||||
</h4>
|
||||
<ul class="text-700 line-height-3 mb-4">
|
||||
<li><strong>Nom d'utilisateur</strong> : Identifiant unique (3-50 caractères)</li>
|
||||
<li><strong>Email</strong> : Adresse email valide</li>
|
||||
<li><strong>Mot de passe</strong> : Au moins 8 caractères</li>
|
||||
</ul>
|
||||
|
||||
<h4 class="text-900 font-semibold flex align-items-center gap-2 mb-3">
|
||||
<i class="pi pi-shield text-purple-500"></i>
|
||||
Sécurité
|
||||
</h4>
|
||||
<ul class="text-700 line-height-3 mb-4">
|
||||
<li>Le mot de passe doit contenir au moins 8 caractères</li>
|
||||
<li>Utilisez une combinaison de lettres, chiffres et caractères spéciaux</li>
|
||||
<li>L'utilisateur pourra modifier son mot de passe après la première connexion</li>
|
||||
</ul>
|
||||
|
||||
<h4 class="text-900 font-semibold flex align-items-center gap-2 mb-3">
|
||||
<i class="pi pi-cog text-orange-500"></i>
|
||||
Configuration
|
||||
</h4>
|
||||
<ul class="text-700 line-height-3 mb-0">
|
||||
<li><strong>Compte activé</strong> : L'utilisateur peut se connecter immédiatement</li>
|
||||
<li><strong>Email vérifié</strong> : L'email est considéré comme vérifié</li>
|
||||
<li><strong>Realm</strong> : Espace d'administration Keycloak</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<f:facet name="footer">
|
||||
<p:commandButton value="Fermer"
|
||||
icon="pi pi-times"
|
||||
styleClass="p-button-text"
|
||||
onclick="PF('helpDialog').hide();"
|
||||
type="button" />
|
||||
</f:facet>
|
||||
</p:dialog>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
@@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:param name="page" value="#{userProfilBean}"/>
|
||||
<ui:define name="title">Modifier Utilisateur - Lions User Manager</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<!-- En-tête -->
|
||||
<ui:include src="/templates/components/layout/page-header.xhtml">
|
||||
<ui:param name="icon" value="pi pi-pencil text-warning-500" />
|
||||
<ui:param name="title" value="Modifier Utilisateur" />
|
||||
<ui:param name="description" value="Modifier les informations de l'utilisateur" />
|
||||
</ui:include>
|
||||
|
||||
<!-- Formulaire d'édition -->
|
||||
<div class="card">
|
||||
<ui:include src="/templates/components/user-management/user-form.xhtml">
|
||||
<ui:param name="user" value="#{userProfilBean.user}" />
|
||||
<ui:param name="mode" value="edit" />
|
||||
<ui:param name="showPasswordFields" value="false" />
|
||||
<ui:param name="submitAction" value="#{userProfilBean.updateUser}" />
|
||||
<ui:param name="cancelOutcome" value="/pages/user-manager/users/list" />
|
||||
</ui:include>
|
||||
</div>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
|
||||
@@ -0,0 +1,429 @@
|
||||
<!DOCTYPE html>
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:param name="page" value="#{userListBean}"/>
|
||||
<ui:define name="title">Liste des Utilisateurs - Lions User Manager</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<h:form id="formUserList">
|
||||
<div class="grid">
|
||||
<!-- ================================================================
|
||||
EN-TÊTE DE LA PAGE
|
||||
================================================================ -->
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-users text-blue-500" style="font-size: 2rem"></i>
|
||||
<div>
|
||||
<h3 class="m-0 mb-1">Gestion des Utilisateurs</h3>
|
||||
<p class="text-600 m-0">Gestion centralisée des utilisateurs Keycloak - Recherche, création, modification et suppression</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<p:commandButton
|
||||
value="Rafraîchir"
|
||||
icon="pi pi-refresh"
|
||||
styleClass="p-button-secondary"
|
||||
action="#{userListBean.refreshData}"
|
||||
update=":formUserList"
|
||||
process="@this" />
|
||||
<p:commandButton
|
||||
value="Nouvel Utilisateur"
|
||||
icon="pi pi-user-plus"
|
||||
styleClass="p-button-success"
|
||||
outcome="/pages/user-manager/users/create" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
STATISTIQUES KPI (4 CARTES)
|
||||
================================================================ -->
|
||||
<div class="col-12">
|
||||
<h5 class="mb-3">Statistiques des Utilisateurs</h5>
|
||||
</div>
|
||||
|
||||
<!-- KPI 1: Total Utilisateurs -->
|
||||
<div class="col-12 md:col-6 lg:col-3">
|
||||
<div class="card surface-0 border-round-lg">
|
||||
<div class="flex align-items-start justify-content-between mb-3">
|
||||
<div>
|
||||
<div class="text-500 font-medium mb-1">Total Utilisateurs</div>
|
||||
<div class="text-900 font-bold text-2xl">#{userListBean.totalRecords}</div>
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-center bg-blue-100 border-circle"
|
||||
style="width: 2.5rem; height: 2.5rem">
|
||||
<i class="pi pi-users text-blue-600 text-xl"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-500 text-sm">
|
||||
<i class="pi pi-database text-600"></i>
|
||||
<span class="ml-2">Utilisateurs dans le realm</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- KPI 2: Utilisateurs Actifs -->
|
||||
<div class="col-12 md:col-6 lg:col-3">
|
||||
<div class="card surface-0 border-round-lg">
|
||||
<div class="flex align-items-start justify-content-between mb-3">
|
||||
<div>
|
||||
<div class="text-500 font-medium mb-1">Utilisateurs Actifs</div>
|
||||
<div class="text-900 font-bold text-2xl">#{userListBean.activeUsersCount}</div>
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-center bg-green-100 border-circle"
|
||||
style="width: 2.5rem; height: 2.5rem">
|
||||
<i class="pi pi-check-circle text-green-600 text-xl"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<span class="text-green-600 font-semibold">
|
||||
<i class="pi pi-arrow-up text-xs"></i>
|
||||
#{userListBean.activeUsersPercentage}%
|
||||
</span>
|
||||
<span class="text-500 text-sm">Taux d'activation</span>
|
||||
</div>
|
||||
<p:progressBar value="#{userListBean.activeUsersPercentage}"
|
||||
styleClass="mt-2"
|
||||
style="height: 4px"
|
||||
showValue="false" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- KPI 3: Utilisateurs Désactivés -->
|
||||
<div class="col-12 md:col-6 lg:col-3">
|
||||
<div class="card surface-0 border-round-lg">
|
||||
<div class="flex align-items-start justify-content-between mb-3">
|
||||
<div>
|
||||
<div class="text-500 font-medium mb-1">Utilisateurs Désactivés</div>
|
||||
<div class="text-900 font-bold text-2xl">#{userListBean.disabledUsersCount}</div>
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-center bg-red-100 border-circle"
|
||||
style="width: 2.5rem; height: 2.5rem">
|
||||
<i class="pi pi-times-circle text-red-600 text-xl"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<span class="text-red-600 font-semibold">
|
||||
<i class="pi pi-arrow-down text-xs"></i>
|
||||
#{userListBean.disabledUsersPercentage}%
|
||||
</span>
|
||||
<span class="text-500 text-sm">Taux de désactivation</span>
|
||||
</div>
|
||||
<p:progressBar value="#{userListBean.disabledUsersPercentage}"
|
||||
styleClass="mt-2"
|
||||
style="height: 4px"
|
||||
showValue="false" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- KPI 4: Realm Actuel -->
|
||||
<div class="col-12 md:col-6 lg:col-3">
|
||||
<div class="card surface-0 border-round-lg">
|
||||
<div class="flex align-items-start justify-content-between mb-3">
|
||||
<div style="max-width: 150px;">
|
||||
<div class="text-500 font-medium mb-1">Realm Actuel</div>
|
||||
<div class="text-900 font-bold text-xl" style="word-break: break-word;">#{userListBean.realmName}</div>
|
||||
</div>
|
||||
<div class="flex align-items-center justify-content-center bg-purple-100 border-circle"
|
||||
style="width: 2.5rem; height: 2.5rem">
|
||||
<i class="pi pi-globe text-purple-600 text-xl"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-500 text-sm">
|
||||
<i class="pi pi-server text-600"></i>
|
||||
<span class="ml-2">Realm Keycloak</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
SECTION RECHERCHE ET FILTRES
|
||||
================================================================ -->
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="flex align-items-center gap-2 mb-3">
|
||||
<i class="pi pi-search text-blue-500" style="font-size: 1.5rem"></i>
|
||||
<h5 class="m-0">Recherche et Filtres</h5>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6 lg:col-4">
|
||||
<label for="searchText" class="block text-900 font-medium mb-2">Recherche</label>
|
||||
<p:inputText id="searchText"
|
||||
value="#{userListBean.searchText}"
|
||||
placeholder="Nom, email..."
|
||||
styleClass="w-full">
|
||||
<p:ajax event="keyup"
|
||||
delay="500"
|
||||
update=":formUserList:userTable"
|
||||
listener="#{userListBean.search}" />
|
||||
</p:inputText>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6 lg:col-3">
|
||||
<label for="realmSelect" class="block text-900 font-medium mb-2">Realm</label>
|
||||
<p:selectOneMenu id="realmSelect"
|
||||
value="#{userListBean.realmName}"
|
||||
styleClass="w-full">
|
||||
<f:selectItem itemLabel="lions-user-manager" itemValue="lions-user-manager" />
|
||||
<f:selectItem itemLabel="master" itemValue="master" />
|
||||
<p:ajax update=":formUserList:userTable"
|
||||
listener="#{userListBean.search}" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6 lg:col-3">
|
||||
<label for="statusSelect" class="block text-900 font-medium mb-2">Statut</label>
|
||||
<p:selectOneMenu id="statusSelect"
|
||||
value="#{userListBean.selectedStatut}"
|
||||
styleClass="w-full">
|
||||
<f:selectItem itemLabel="Tous" itemValue="#{null}" />
|
||||
<f:selectItems value="#{userListBean.statutOptions}" />
|
||||
<p:ajax update=":formUserList:userTable"
|
||||
listener="#{userListBean.search}" />
|
||||
</p:selectOneMenu>
|
||||
</div>
|
||||
|
||||
<div class="col-12 lg:col-2 flex align-items-end">
|
||||
<p:commandButton
|
||||
value="Réinitialiser"
|
||||
icon="pi pi-refresh"
|
||||
styleClass="p-button-secondary w-full"
|
||||
action="#{userListBean.resetSearch}"
|
||||
update=":formUserList:userTable @form" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
TABLEAU DES UTILISATEURS
|
||||
================================================================ -->
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="flex align-items-center justify-content-between mb-3">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-list text-blue-500" style="font-size: 1.5rem"></i>
|
||||
<h5 class="m-0">Liste des Utilisateurs</h5>
|
||||
</div>
|
||||
<p:tag value="#{userListBean.totalRecords} utilisateur(s)"
|
||||
severity="info"
|
||||
icon="pi pi-users" />
|
||||
</div>
|
||||
|
||||
<p:dataTable
|
||||
id="userTable"
|
||||
value="#{userListBean.users}"
|
||||
var="user"
|
||||
rowKey="#{user.id}"
|
||||
paginator="true"
|
||||
rows="#{userListBean.pageSize}"
|
||||
rowsPerPageTemplate="10,20,50"
|
||||
paginatorTemplate="{CurrentPageReport} {FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}"
|
||||
currentPageReportTemplate="Affichage {startRecord}-{endRecord} sur {totalRecords}"
|
||||
styleClass="w-full"
|
||||
emptyMessage="Aucun utilisateur trouvé"
|
||||
reflow="true">
|
||||
|
||||
<p:ajax event="page" listener="#{userListBean.onPageChange}" update=":formUserList:userTable" />
|
||||
|
||||
<!-- Colonne Avatar + Username -->
|
||||
<p:column headerText="Utilisateur" sortBy="#{user.username}" style="width: 250px">
|
||||
<div class="flex align-items-center gap-3">
|
||||
<div class="border-circle bg-primary text-white flex align-items-center justify-content-center"
|
||||
style="width: 42px; height: 42px; flex-shrink: 0;">
|
||||
<span class="font-bold">
|
||||
#{user.prenom != null ? user.prenom.substring(0,1).toUpperCase() : 'U'}#{user.nom != null ? user.nom.substring(0,1).toUpperCase() : 'U'}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex flex-column">
|
||||
<span class="font-semibold text-900">#{user.username}</span>
|
||||
<span class="text-600 text-sm">#{user.prenom} #{user.nom}</span>
|
||||
</div>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<!-- Colonne Email -->
|
||||
<p:column headerText="Email" sortBy="#{user.email}" style="width: 250px">
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-envelope text-500"></i>
|
||||
<span class="text-900">#{user.email}</span>
|
||||
<p:outputPanel rendered="#{user.emailVerified}">
|
||||
<i class="pi pi-check-circle text-green-500" title="Email vérifié"></i>
|
||||
</p:outputPanel>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<!-- Colonne Statut -->
|
||||
<p:column headerText="Statut" sortBy="#{user.enabled}" style="width: 120px; text-align: center">
|
||||
<p:tag value="#{user.enabled ? 'ACTIF' : 'INACTIF'}"
|
||||
severity="#{user.enabled ? 'success' : 'danger'}" />
|
||||
</p:column>
|
||||
|
||||
<!-- Colonne Rôles -->
|
||||
<p:column headerText="Rôles" style="width: 250px">
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<h:outputText value="Aucun rôle" styleClass="text-500 text-sm"
|
||||
rendered="#{user.realmRoles == null or user.realmRoles.size() == 0}" />
|
||||
|
||||
<ui:fragment rendered="#{user.realmRoles != null and user.realmRoles.size() > 0}">
|
||||
<ui:repeat value="#{user.realmRoles}" var="role" varStatus="status">
|
||||
<p:tag value="#{role}" severity="info"
|
||||
rendered="#{status.index lt 3}"
|
||||
styleClass="mr-1" />
|
||||
</ui:repeat>
|
||||
<p:tag value="+#{user.realmRoles.size() - 3}" severity="secondary"
|
||||
rendered="#{user.realmRoles.size() > 3}" />
|
||||
</ui:fragment>
|
||||
</div>
|
||||
</p:column>
|
||||
|
||||
<!-- Colonne Actions -->
|
||||
<p:column headerText="Actions" style="width: 180px; text-align: center">
|
||||
<div class="flex gap-1 justify-content-center">
|
||||
<!-- Bouton Modifier -->
|
||||
<p:commandButton icon="pi pi-pencil"
|
||||
styleClass="p-button-rounded p-button-text p-button-sm"
|
||||
title="Modifier"
|
||||
outcome="/pages/user-manager/users/edit">
|
||||
<f:param name="userId" value="#{user.id}" />
|
||||
</p:commandButton>
|
||||
|
||||
<!-- Bouton Désactiver (si actif) -->
|
||||
<p:commandButton icon="pi pi-ban"
|
||||
styleClass="p-button-rounded p-button-text p-button-sm p-button-warning"
|
||||
title="Désactiver"
|
||||
action="#{userListBean.deactivateUser(user.id)}"
|
||||
update=":formUserList"
|
||||
rendered="#{user.enabled}">
|
||||
<p:confirm header="Confirmation"
|
||||
message="Voulez-vous vraiment désactiver cet utilisateur ?"
|
||||
icon="pi pi-exclamation-triangle" />
|
||||
</p:commandButton>
|
||||
|
||||
<!-- Bouton Activer (si inactif) -->
|
||||
<p:commandButton icon="pi pi-check"
|
||||
styleClass="p-button-rounded p-button-text p-button-sm p-button-success"
|
||||
title="Activer"
|
||||
action="#{userListBean.activateUser(user.id)}"
|
||||
update=":formUserList"
|
||||
rendered="#{not user.enabled}" />
|
||||
|
||||
<!-- Bouton Supprimer -->
|
||||
<p:commandButton icon="pi pi-trash"
|
||||
styleClass="p-button-rounded p-button-text p-button-sm p-button-danger"
|
||||
title="Supprimer"
|
||||
action="#{userListBean.deleteUser(user.id)}"
|
||||
update=":formUserList">
|
||||
<p:confirm header="Confirmation"
|
||||
message="Voulez-vous vraiment supprimer cet utilisateur ?"
|
||||
icon="pi pi-exclamation-triangle" />
|
||||
</p:commandButton>
|
||||
</div>
|
||||
</p:column>
|
||||
</p:dataTable>
|
||||
|
||||
<p:confirmDialog global="true" showEffect="fade" hideEffect="fade"
|
||||
responsive="true" width="350">
|
||||
<p:commandButton value="Non" type="button"
|
||||
styleClass="p-button-text"
|
||||
onclick="PF('confirmDialog').hide()" />
|
||||
<p:commandButton value="Oui" type="button"
|
||||
styleClass="p-button-primary"
|
||||
onclick="PF('confirmDialog').hide()" />
|
||||
</p:confirmDialog>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
ACTIONS RAPIDES
|
||||
================================================================ -->
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="flex align-items-center gap-2 mb-3">
|
||||
<i class="pi pi-bolt text-orange-500" style="font-size: 1.5rem"></i>
|
||||
<h5 class="m-0">Actions Rapides</h5>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6 lg:col-3">
|
||||
<p:commandButton
|
||||
value="Créer un Utilisateur"
|
||||
icon="pi pi-user-plus"
|
||||
styleClass="w-full p-button-success"
|
||||
outcome="/pages/user-manager/users/create" />
|
||||
</div>
|
||||
<div class="col-12 md:col-6 lg:col-3">
|
||||
<p:commandButton
|
||||
value="Exporter la Liste"
|
||||
icon="pi pi-download"
|
||||
styleClass="w-full p-button-secondary"
|
||||
action="#{userListBean.exportToCSV}"
|
||||
ajax="false" />
|
||||
</div>
|
||||
<div class="col-12 md:col-6 lg:col-3">
|
||||
<p:commandButton
|
||||
value="Importer des Utilisateurs"
|
||||
icon="pi pi-upload"
|
||||
styleClass="w-full p-button-info"
|
||||
onclick="PF('importUsersDialog').show()"
|
||||
type="button" />
|
||||
</div>
|
||||
<div class="col-12 md:col-6 lg:col-3">
|
||||
<p:commandButton
|
||||
value="Gestion des Rôles"
|
||||
icon="pi pi-shield"
|
||||
styleClass="w-full p-button-primary"
|
||||
outcome="/pages/user-manager/roles/list" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
|
||||
<!-- ================================================================
|
||||
DIALOG D'IMPORT
|
||||
================================================================ -->
|
||||
<p:dialog id="importUsersDialog"
|
||||
widgetVar="importUsersDialog"
|
||||
header="Importer des Utilisateurs"
|
||||
modal="true"
|
||||
resizable="false"
|
||||
styleClass="w-full md:w-30rem">
|
||||
<h:form id="formImportUsers">
|
||||
<div class="flex flex-column gap-3">
|
||||
<p class="text-600">
|
||||
Importez des utilisateurs depuis un fichier CSV ou JSON.
|
||||
</p>
|
||||
<p:fileUpload mode="simple"
|
||||
skinSimple="true"
|
||||
accept=".csv,.json"
|
||||
label="Sélectionner un fichier" />
|
||||
<div class="flex justify-content-end gap-2 mt-3">
|
||||
<p:commandButton value="Annuler"
|
||||
icon="pi pi-times"
|
||||
styleClass="p-button-secondary"
|
||||
onclick="PF('importUsersDialog').hide()"
|
||||
type="button" />
|
||||
<p:commandButton value="Importer"
|
||||
icon="pi pi-upload"
|
||||
styleClass="p-button-success"
|
||||
action="#{userListBean.importUsers}"
|
||||
update=":formUserList"
|
||||
oncomplete="PF('importUsersDialog').hide()" />
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</p:dialog>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
@@ -0,0 +1,421 @@
|
||||
<!DOCTYPE html>
|
||||
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:h="http://xmlns.jcp.org/jsf/html"
|
||||
xmlns:f="http://xmlns.jcp.org/jsf/core"
|
||||
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
|
||||
xmlns:p="http://primefaces.org/ui"
|
||||
xmlns:c="http://xmlns.jcp.org/jsp/jstl/core"
|
||||
template="/templates/main-template.xhtml">
|
||||
|
||||
<ui:param name="page" value="#{userSessionBean}"/>
|
||||
<ui:define name="title">Mon Profil - Lions User Manager</ui:define>
|
||||
|
||||
<ui:define name="content">
|
||||
<div class="grid">
|
||||
<!-- ================================================================
|
||||
EN-TÊTE DE LA PAGE
|
||||
================================================================ -->
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="flex align-items-center justify-content-between">
|
||||
<h2 class="text-900 font-semibold text-xl m-0">
|
||||
<i class="pi pi-user text-blue-500 mr-2"></i>
|
||||
Mon Profil
|
||||
</h2>
|
||||
<h:link outcome="/pages/user-manager/dashboard" styleClass="p-button p-button-text">
|
||||
<i class="pi pi-arrow-left mr-2"></i>
|
||||
Retour au tableau de bord
|
||||
</h:link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
CARTE PROFIL PRINCIPAL
|
||||
================================================================ -->
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="grid">
|
||||
<!-- Photo de profil et informations principales -->
|
||||
<div class="col-12 md:col-4">
|
||||
<div class="text-center mb-4">
|
||||
<!-- Avatar avec gradient -->
|
||||
<div style="width: 140px; height: 140px; border-radius: 50%; background: linear-gradient(135deg, var(--primary-color), var(--primary-600, #387FE9)); display: flex; align-items: center; justify-content: center; margin: 0 auto 1.5rem auto; font-size: 3.5rem; font-weight: bold; color: white; box-shadow: 0 8px 24px rgba(0,0,0,0.12);">
|
||||
#{userSessionBean.initials}
|
||||
</div>
|
||||
|
||||
<!-- Nom complet -->
|
||||
<h3 class="text-900 font-semibold text-2xl mb-2">#{userSessionBean.fullName}</h3>
|
||||
|
||||
<!-- Email -->
|
||||
<p class="text-600 mb-3 flex align-items-center justify-content-center gap-2">
|
||||
<i class="pi pi-envelope"></i>
|
||||
#{userSessionBean.email}
|
||||
</p>
|
||||
|
||||
<!-- Badge de statut -->
|
||||
<div class="inline-flex align-items-center justify-content-center gap-2">
|
||||
<span class="inline-flex align-items-center gap-2 bg-green-100 text-green-700 px-3 py-2 border-round font-semibold" style="font-size: 1rem;">
|
||||
<i class="pi pi-circle-fill" style="font-size: 0.5rem; animation: pulse 2s ease-in-out infinite;"></i>
|
||||
<span>Connecté</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Badge du rôle principal -->
|
||||
<div class="mt-3 flex justify-content-center">
|
||||
<span class="inline-flex align-items-center bg-blue-100 text-blue-700 px-3 py-1 border-round font-semibold text-sm" style="text-transform: uppercase; letter-spacing: 0.5px;">
|
||||
#{userSessionBean.primaryRole}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Informations détaillées -->
|
||||
<div class="col-12 md:col-8">
|
||||
<div class="grid">
|
||||
<!-- Colonne gauche: Informations personnelles -->
|
||||
<div class="col-12 md:col-6">
|
||||
<h4 class="text-900 font-semibold text-lg mb-3 flex align-items-center gap-2">
|
||||
<i class="pi pi-user text-blue-500"></i>
|
||||
Informations Personnelles
|
||||
</h4>
|
||||
|
||||
<div class="mb-3 pb-3 border-bottom-1 surface-border">
|
||||
<label class="block text-600 font-medium mb-1 text-sm">Nom d'utilisateur</label>
|
||||
<p class="text-900 font-semibold m-0">#{userSessionBean.username}</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 pb-3 border-bottom-1 surface-border">
|
||||
<label class="block text-600 font-medium mb-1 text-sm">Nom complet</label>
|
||||
<p class="text-900 font-semibold m-0">#{userSessionBean.fullName}</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 pb-3 border-bottom-1 surface-border">
|
||||
<label class="block text-600 font-medium mb-1 text-sm">Adresse email</label>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<p class="text-900 font-semibold m-0">#{userSessionBean.email}</p>
|
||||
<i class="pi pi-check-circle text-green-500" title="Email vérifié"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="block text-600 font-medium mb-1 text-sm">Prénom</label>
|
||||
<p class="text-900 font-semibold m-0">#{userSessionBean.firstName}</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="block text-600 font-medium mb-1 text-sm">Nom</label>
|
||||
<p class="text-900 font-semibold m-0">#{userSessionBean.lastName}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Colonne droite: Rôles et permissions -->
|
||||
<div class="col-12 md:col-6">
|
||||
<h4 class="text-900 font-semibold text-lg mb-3 flex align-items-center gap-2">
|
||||
<i class="pi pi-shield text-purple-500"></i>
|
||||
Rôles et Permissions
|
||||
</h4>
|
||||
|
||||
<div class="mb-3 pb-3 border-bottom-1 surface-border">
|
||||
<label class="block text-600 font-medium mb-2 text-sm">Rôles assignés</label>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<ui:repeat value="#{userSessionBean.roles}" var="role">
|
||||
<p:badge value="#{role}" severity="info" styleClass="text-sm"></p:badge>
|
||||
</ui:repeat>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 pb-3 border-bottom-1 surface-border">
|
||||
<label class="block text-600 font-medium mb-2 text-sm">Rôle principal</label>
|
||||
<div class="flex align-items-center">
|
||||
<p:badge value="#{userSessionBean.primaryRole}"
|
||||
severity="success"
|
||||
styleClass="text-sm">
|
||||
</p:badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 pb-3 border-bottom-1 surface-border">
|
||||
<label class="block text-600 font-medium mb-1 text-sm">Niveau d'accès</label>
|
||||
<p class="text-900 font-semibold m-0">
|
||||
<h:outputText value="Administrateur système" rendered="#{userSessionBean.hasRole('admin')}" />
|
||||
<h:outputText value="Gestionnaire utilisateurs" rendered="#{userSessionBean.hasRole('user_manager') and not userSessionBean.hasRole('admin')}" />
|
||||
<h:outputText value="Consultation utilisateurs" rendered="#{userSessionBean.hasRole('user_viewer') and not userSessionBean.hasRole('user_manager') and not userSessionBean.hasRole('admin')}" />
|
||||
<h:outputText value="Auditeur" rendered="#{userSessionBean.hasRole('auditor') and not userSessionBean.hasRole('user_viewer') and not userSessionBean.hasRole('user_manager') and not userSessionBean.hasRole('admin')}" />
|
||||
<h:outputText value="Utilisateur standard" rendered="#{not userSessionBean.hasRole('admin') and not userSessionBean.hasRole('user_manager') and not userSessionBean.hasRole('user_viewer') and not userSessionBean.hasRole('auditor')}" />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="block text-600 font-medium mb-2 text-sm">Statut du compte</label>
|
||||
<div class="flex align-items-center">
|
||||
<p:badge value="Actif" severity="success" styleClass="text-sm"></p:badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
INFORMATIONS DE SESSION OIDC
|
||||
================================================================ -->
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<h3 class="text-900 font-semibold text-lg mb-4 flex align-items-center gap-2">
|
||||
<i class="pi pi-shield text-orange-500"></i>
|
||||
Informations de Session OIDC
|
||||
</h3>
|
||||
|
||||
<div class="grid">
|
||||
<!-- Colonne gauche: Token Information -->
|
||||
<div class="col-12 md:col-6">
|
||||
<h4 class="text-900 font-semibold mb-3">Informations du Token</h4>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="block text-600 font-medium mb-1 text-sm">Issuer (Émetteur)</label>
|
||||
<p class="text-700 m-0 text-sm font-mono bg-bluegray-50 p-2 border-round">
|
||||
#{userSessionBean.issuer}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="block text-600 font-medium mb-1 text-sm">Subject (Identifiant)</label>
|
||||
<p class="text-700 m-0 text-sm font-mono bg-bluegray-50 p-2 border-round">
|
||||
#{userSessionBean.subject}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="block text-600 font-medium mb-1 text-sm">Audience</label>
|
||||
<p class="text-700 m-0 text-sm font-mono bg-bluegray-50 p-2 border-round">
|
||||
account
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="block text-600 font-medium mb-2 text-sm">Token Type</label>
|
||||
<div class="flex align-items-center">
|
||||
<p:badge value="Bearer" severity="info" styleClass="text-sm"></p:badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Colonne droite: Session Details -->
|
||||
<div class="col-12 md:col-6">
|
||||
<h4 class="text-900 font-semibold mb-3">Détails de la Session</h4>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="block text-600 font-medium mb-1 text-sm">Expiration du token</label>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-calendar text-orange-500"></i>
|
||||
<p class="text-700 m-0 text-sm">
|
||||
<h:outputText value="#{userSessionBean.expirationTime}">
|
||||
<f:convertDateTime pattern="dd/MM/yyyy à HH:mm:ss" timeZone="Europe/Paris" type="both"/>
|
||||
</h:outputText>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="block text-600 font-medium mb-1 text-sm">Émis le</label>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-clock text-blue-500"></i>
|
||||
<p class="text-700 m-0 text-sm">
|
||||
<h:outputText value="#{userSessionBean.issuedAt}">
|
||||
<f:convertDateTime pattern="dd/MM/yyyy à HH:mm:ss" timeZone="Europe/Paris" type="both"/>
|
||||
</h:outputText>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="block text-600 font-medium mb-1 text-sm">Realm Keycloak</label>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-globe text-purple-500"></i>
|
||||
<p class="text-700 m-0 text-sm font-semibold">
|
||||
lions-user-manager
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="block text-600 font-medium mb-1 text-sm">Durée de validité</label>
|
||||
<div class="flex align-items-center gap-2">
|
||||
<i class="pi pi-hourglass text-green-500"></i>
|
||||
<p class="text-700 m-0 text-sm">
|
||||
Session active
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
STATISTIQUES D'ACTIVITÉ
|
||||
================================================================ -->
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<h3 class="text-900 font-semibold text-lg mb-4 flex align-items-center gap-2">
|
||||
<i class="pi pi-chart-line text-green-500"></i>
|
||||
Statistiques d'Activité
|
||||
</h3>
|
||||
|
||||
<div class="grid">
|
||||
<div class="col-12 md:col-6 lg:col-3">
|
||||
<div class="surface-50 border-round p-3">
|
||||
<div class="flex align-items-center justify-content-between mb-2">
|
||||
<span class="text-600 font-medium text-sm">Connexions</span>
|
||||
<i class="pi pi-sign-in text-blue-500"></i>
|
||||
</div>
|
||||
<p class="text-900 font-bold text-2xl m-0">--</p>
|
||||
<small class="text-500">Total des connexions</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6 lg:col-3">
|
||||
<div class="surface-50 border-round p-3">
|
||||
<div class="flex align-items-center justify-content-between mb-2">
|
||||
<span class="text-600 font-medium text-sm">Dernière connexion</span>
|
||||
<i class="pi pi-clock text-green-500"></i>
|
||||
</div>
|
||||
<p class="text-900 font-bold text-xl m-0">Aujourd'hui</p>
|
||||
<small class="text-500">Session en cours</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6 lg:col-3">
|
||||
<div class="surface-50 border-round p-3">
|
||||
<div class="flex align-items-center justify-content-between mb-2">
|
||||
<span class="text-600 font-medium text-sm">Actions</span>
|
||||
<i class="pi pi-history text-orange-500"></i>
|
||||
</div>
|
||||
<p class="text-900 font-bold text-2xl m-0">--</p>
|
||||
<small class="text-500">Actions effectuées</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 md:col-6 lg:col-3">
|
||||
<div class="surface-50 border-round p-3">
|
||||
<div class="flex align-items-center justify-content-between mb-2">
|
||||
<span class="text-600 font-medium text-sm">Sessions</span>
|
||||
<i class="pi pi-desktop text-purple-500"></i>
|
||||
</div>
|
||||
<p class="text-900 font-bold text-2xl m-0">1</p>
|
||||
<small class="text-500">Session active</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
ACTIONS
|
||||
================================================================ -->
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<h3 class="text-900 font-semibold text-lg mb-4 flex align-items-center gap-2">
|
||||
<i class="pi pi-cog text-gray-500"></i>
|
||||
Actions Rapides
|
||||
</h3>
|
||||
|
||||
<h:form id="formProfileActions">
|
||||
<div class="grid">
|
||||
<!-- Gestion du Profil -->
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="surface-50 border-round p-3 h-full">
|
||||
<h4 class="text-900 font-semibold mb-3 flex align-items-center gap-2">
|
||||
<i class="pi pi-user text-blue-500"></i>
|
||||
<span>Gestion du Profil</span>
|
||||
</h4>
|
||||
<div class="flex flex-column gap-2">
|
||||
<p:commandButton value="Modifier mon profil"
|
||||
icon="pi pi-pencil"
|
||||
styleClass="p-button-outlined w-full justify-content-start"
|
||||
disabled="true">
|
||||
<f:attribute name="data-tooltip" value="Fonctionnalité gérée par Keycloak"/>
|
||||
</p:commandButton>
|
||||
|
||||
<p:commandButton value="Changer mon mot de passe"
|
||||
icon="pi pi-key"
|
||||
styleClass="p-button-outlined w-full justify-content-start"
|
||||
disabled="true">
|
||||
<f:attribute name="data-tooltip" value="Utilisez le portail Keycloak"/>
|
||||
</p:commandButton>
|
||||
|
||||
<p:commandButton value="Paramètres de sécurité"
|
||||
icon="pi pi-shield"
|
||||
styleClass="p-button-outlined w-full justify-content-start"
|
||||
disabled="true">
|
||||
<f:attribute name="data-tooltip" value="Fonctionnalité à venir"/>
|
||||
</p:commandButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Gestion des Sessions -->
|
||||
<div class="col-12 md:col-6">
|
||||
<div class="surface-50 border-round p-3 h-full">
|
||||
<h4 class="text-900 font-semibold mb-3 flex align-items-center gap-2">
|
||||
<i class="pi pi-desktop text-purple-500"></i>
|
||||
<span>Sessions et Sécurité</span>
|
||||
</h4>
|
||||
<div class="flex flex-column gap-2">
|
||||
<p:commandButton value="Voir mes sessions actives"
|
||||
icon="pi pi-desktop"
|
||||
styleClass="p-button-outlined p-button-info w-full justify-content-start"
|
||||
disabled="true">
|
||||
<f:attribute name="data-tooltip" value="Fonctionnalité à venir"/>
|
||||
</p:commandButton>
|
||||
|
||||
<p:commandButton value="Historique des connexions"
|
||||
icon="pi pi-history"
|
||||
styleClass="p-button-outlined p-button-secondary w-full justify-content-start"
|
||||
disabled="true">
|
||||
<f:attribute name="data-tooltip" value="Fonctionnalité à venir"/>
|
||||
</p:commandButton>
|
||||
|
||||
<p:commandButton value="Se déconnecter"
|
||||
icon="pi pi-sign-out"
|
||||
styleClass="p-button-danger w-full justify-content-start"
|
||||
action="#{userSessionBean.logout}">
|
||||
<p:confirm header="Confirmation de déconnexion"
|
||||
message="Êtes-vous sûr de vouloir vous déconnecter ?"
|
||||
icon="pi pi-exclamation-triangle" />
|
||||
</p:commandButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</h:form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================================================================
|
||||
DIALOG DE CONFIRMATION
|
||||
================================================================ -->
|
||||
<p:confirmDialog global="true" showEffect="fade" hideEffect="fade"
|
||||
responsive="true" width="400">
|
||||
<p:commandButton value="Non" type="button"
|
||||
styleClass="p-button-text"
|
||||
icon="pi pi-times" />
|
||||
<p:commandButton value="Oui" type="button"
|
||||
styleClass="p-button-danger"
|
||||
icon="pi pi-check" />
|
||||
</p:confirmDialog>
|
||||
|
||||
<!-- Animation CSS pour le badge "Connecté" -->
|
||||
<style>
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
}
|
||||
</style>
|
||||
</ui:define>
|
||||
|
||||
</ui:composition>
|
||||
Reference in New Issue
Block a user