fix(client): Corrections composants JSF - expressions EL et formulaires imbriqués

This commit is contained in:
lionsdev
2025-12-05 16:24:13 +00:00
parent bb75d0fe12
commit ab716f038a
8 changed files with 633 additions and 371 deletions

View File

@@ -0,0 +1,131 @@
<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">
<p:panel header="#{mode == 'create' ? 'Nouveau Rôle' : 'Modifier Rôle'}"
styleClass="w-full">
<p:panelGrid columns="2" styleClass="w-full" columnClasses="col-12 md:col-6">
<!-- Nom du rôle -->
<p:outputLabel for="roleName" value="Nom du rôle *" />
<p:inputText id="roleName"
value="#{role.name}"
required="true"
readonly="#{readonly}"
placeholder="ADMIN, USER, MODERATOR..."
styleClass="w-full">
<f:validateLength minimum="2" maximum="100" />
<f:validateRegex pattern="^[A-Z_]+$" />
</p:inputText>
<!-- Description -->
<p:outputLabel for="description" value="Description" />
<p:inputTextarea id="description"
value="#{role.description}"
readonly="#{readonly}"
placeholder="Description du rôle..."
rows="3"
styleClass="w-full" />
<!-- Type de rôle -->
<p:outputLabel for="typeRole" value="Type de rôle *" />
<p:selectOneMenu id="typeRole"
value="#{role.typeRole}"
required="true"
readonly="#{readonly or mode == 'edit'}"
styleClass="w-full">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItem itemLabel="Rôle Realm" itemValue="REALM_ROLE" />
<f:selectItem itemLabel="Rôle Client" itemValue="CLIENT_ROLE" />
<f:selectItem itemLabel="Rôle Composite" itemValue="COMPOSITE_ROLE" />
</p:selectOneMenu>
<!-- Realm (si affiché) -->
<c:if test="#{showRealmSelector}">
<p:outputLabel for="realmName" value="Realm *" />
<p:selectOneMenu id="realmName"
value="#{role.realmName}"
required="#{showRealmSelector}"
readonly="#{readonly}"
styleClass="w-full">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItems value="#{roleBean.availableRealms}" />
</p:selectOneMenu>
</c:if>
<!-- Client (si affiché) -->
<c:if test="#{showClientSelector}">
<p:outputLabel for="clientId" value="Client *" />
<p:selectOneMenu id="clientId"
value="#{role.clientId}"
required="#{showClientSelector}"
readonly="#{readonly}"
styleClass="w-full">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItems value="#{roleBean.availableClients}" />
</p:selectOneMenu>
</c:if>
<!-- Rôle composite -->
<c:if test="#{showCompositeOptions}">
<p:outputLabel for="composite" value="Rôle composite" />
<p:selectBooleanCheckbox id="composite"
value="#{role.composite}"
readonly="#{readonly}" />
</c:if>
</p:panelGrid>
<!-- Boutons d'action -->
<f:facet name="footer">
<div class="flex gap-2 justify-content-end">
<c:if test="#{not readonly}">
<c:choose>
<!-- Si hasSubmitAction est explicitement défini à true, utiliser action -->
<c:when test="#{hasSubmitAction == true}">
<p:commandButton
value="#{mode == 'create' ? 'Créer' : 'Modifier'}"
icon="pi pi-check"
styleClass="p-button-success"
action="#{submitAction}"
update="#{not empty update ? update : '@form'}"
process="@form" />
</c:when>
<!-- Si submitOutcome est fourni, utiliser outcome -->
<c:when test="#{not empty submitOutcome}">
<p:commandButton
value="#{mode == 'create' ? 'Créer' : 'Modifier'}"
icon="pi pi-check"
styleClass="p-button-success"
outcome="#{submitOutcome}"
update="#{not empty update ? update : '@form'}"
process="@form" />
</c:when>
<!-- Sinon, essayer d'utiliser submitAction si fourni -->
<c:otherwise>
<p:commandButton
value="#{mode == 'create' ? 'Créer' : 'Modifier'}"
icon="pi pi-check"
styleClass="p-button-success"
action="#{submitAction}"
update="#{not empty update ? update : '@form'}"
process="@form" />
</c:otherwise>
</c:choose>
</c:if>
<p:commandButton
value="Annuler"
icon="pi pi-times"
styleClass="p-button-secondary"
onclick="PF('createRealmRoleDialog').hide(); PF('createClientRoleDialog').hide();"
immediate="true" />
</div>
</f:facet>
</p:panel>
</ui:composition>

View File

@@ -49,106 +49,44 @@
<c:set var="showClientSelector" value="#{empty showClientSelector ? false : showClientSelector}" />
<c:set var="showCompositeOptions" value="#{empty showCompositeOptions ? true : showCompositeOptions}" />
<c:set var="readonly" value="#{empty readonly ? false : readonly}" />
<c:set var="useParentForm" value="#{empty useParentForm ? false : useParentForm}" />
<h:form id="#{formId}">
<p:panel header="#{mode == 'create' ? 'Nouveau Rôle' : 'Modifier Rôle'}"
styleClass="w-full">
<p:panelGrid columns="2" styleClass="w-full" columnClasses="col-12 md:col-6">
<!-- Nom du rôle -->
<p:outputLabel for="roleName" value="Nom du rôle *" />
<p:inputText id="roleName"
value="#{role.name}"
required="true"
readonly="#{readonly}"
placeholder="ADMIN, USER, MODERATOR..."
styleClass="w-full">
<f:validateLength minimum="2" maximum="100" />
<f:validateRegex pattern="^[A-Z_]+$" />
</p:inputText>
<!-- Description -->
<p:outputLabel for="description" value="Description" />
<p:inputTextarea id="description"
value="#{role.description}"
readonly="#{readonly}"
placeholder="Description du rôle..."
rows="3"
styleClass="w-full" />
<!-- Type de rôle -->
<p:outputLabel for="typeRole" value="Type de rôle *" />
<p:selectOneMenu id="typeRole"
value="#{role.typeRole}"
required="true"
readonly="#{readonly or mode == 'edit'}"
styleClass="w-full">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItem itemLabel="Rôle Realm" itemValue="REALM_ROLE" />
<f:selectItem itemLabel="Rôle Client" itemValue="CLIENT_ROLE" />
<f:selectItem itemLabel="Rôle Composite" itemValue="COMPOSITE_ROLE" />
</p:selectOneMenu>
<!-- Realm (si affiché) -->
<c:if test="#{showRealmSelector}">
<p:outputLabel for="realmName" value="Realm *" />
<p:selectOneMenu id="realmName"
value="#{role.realmName}"
required="#{showRealmSelector}"
readonly="#{readonly}"
styleClass="w-full">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItems value="#{roleBean.availableRealms}" />
</p:selectOneMenu>
</c:if>
<!-- Client (si affiché) -->
<c:if test="#{showClientSelector}">
<p:outputLabel for="clientId" value="Client *" />
<p:selectOneMenu id="clientId"
value="#{role.clientId}"
required="#{showClientSelector}"
readonly="#{readonly}"
styleClass="w-full">
<f:selectItem itemLabel="Sélectionner..." itemValue="" />
<f:selectItems value="#{roleBean.availableClients}" />
</p:selectOneMenu>
</c:if>
<!-- Rôle composite -->
<c:if test="#{showCompositeOptions}">
<p:outputLabel for="composite" value="Rôle composite" />
<p:selectBooleanCheckbox id="composite"
value="#{role.composite}"
readonly="#{readonly}" />
</c:if>
</p:panelGrid>
<!-- Boutons d'action -->
<f:facet name="footer">
<div class="flex gap-2 justify-content-end">
<c:if test="#{not readonly}">
<p:commandButton
value="#{mode == 'create' ? 'Créer' : 'Modifier'}"
icon="pi pi-check"
styleClass="p-button-success"
action="#{not empty submitAction ? submitAction : null}"
outcome="#{not empty submitOutcome ? submitOutcome : null}"
update="#{not empty update ? update : '@form'}"
process="@form" />
</c:if>
<p:commandButton
value="Annuler"
icon="pi pi-times"
styleClass="p-button-secondary"
outcome="#{not empty cancelOutcome ? cancelOutcome : '/pages/user-manager/roles/list'}"
immediate="true" />
</div>
</f:facet>
</p:panel>
</h:form>
<c:choose>
<c:when test="#{useParentForm}">
<!-- Utiliser le formulaire parent (pas de h:form ici) -->
<ui:include src="/templates/components/role-management/role-form-content.xhtml">
<ui:param name="role" value="#{role}" />
<ui:param name="mode" value="#{mode}" />
<ui:param name="showRealmSelector" value="#{showRealmSelector}" />
<ui:param name="showClientSelector" value="#{showClientSelector}" />
<ui:param name="showCompositeOptions" value="#{showCompositeOptions}" />
<ui:param name="readonly" value="#{readonly}" />
<ui:param name="hasSubmitAction" value="#{hasSubmitAction}" />
<ui:param name="submitAction" value="#{submitAction}" />
<ui:param name="submitOutcome" value="#{submitOutcome}" />
<ui:param name="update" value="#{update}" />
<ui:param name="cancelOutcome" value="#{cancelOutcome}" />
</ui:include>
</c:when>
<c:otherwise>
<!-- Créer son propre formulaire -->
<h:form id="#{formId}">
<ui:include src="/templates/components/role-management/role-form-content.xhtml">
<ui:param name="role" value="#{role}" />
<ui:param name="mode" value="#{mode}" />
<ui:param name="showRealmSelector" value="#{showRealmSelector}" />
<ui:param name="showClientSelector" value="#{showClientSelector}" />
<ui:param name="showCompositeOptions" value="#{showCompositeOptions}" />
<ui:param name="readonly" value="#{readonly}" />
<ui:param name="hasSubmitAction" value="#{hasSubmitAction}" />
<ui:param name="submitAction" value="#{submitAction}" />
<ui:param name="submitOutcome" value="#{submitOutcome}" />
<ui:param name="update" value="#{update}" />
<ui:param name="cancelOutcome" value="#{cancelOutcome}" />
</ui:include>
</h:form>
</c:otherwise>
</c:choose>
</ui:composition>

View File

@@ -45,6 +45,8 @@
<c:set var="size" value="#{empty size ? 'normal' : size}" />
<c:set var="disabled" value="#{empty disabled ? false : disabled}" />
<c:set var="process" value="#{empty process ? '@this' : process}" />
<c:set var="hasAction" value="#{not empty action}" />
<c:set var="hasOutcome" value="#{not empty outcome}" />
<!-- Déterminer la classe selon la severity -->
<c:choose>
@@ -81,15 +83,36 @@
<c:set var="buttonClass" value="#{buttonClass} #{styleClass}" />
</c:if>
<p:commandButton
value="#{value}"
icon="#{not empty icon ? icon : ''}"
styleClass="#{buttonClass}"
disabled="#{disabled}"
action="#{not empty action ? action : null}"
outcome="#{not empty outcome ? outcome : null}"
update="#{not empty update ? update : '@form'}"
process="#{process}" />
<c:choose>
<c:when test="#{hasAction}">
<p:commandButton
value="#{value}"
icon="#{not empty icon ? icon : ''}"
styleClass="#{buttonClass}"
disabled="#{disabled}"
action="#{action}"
update="#{not empty update ? update : '@form'}"
process="#{process}" />
</c:when>
<c:when test="#{hasOutcome}">
<p:commandButton
value="#{value}"
icon="#{not empty icon ? icon : ''}"
styleClass="#{buttonClass}"
disabled="#{disabled}"
outcome="#{outcome}"
update="#{not empty update ? update : '@form'}"
process="#{process}" />
</c:when>
<c:otherwise>
<p:commandButton
value="#{value}"
icon="#{not empty icon ? icon : ''}"
styleClass="#{buttonClass}"
disabled="true"
title="Aucune action définie" />
</c:otherwise>
</c:choose>
</ui:composition>

View File

@@ -43,7 +43,7 @@
</ui:include>
-->
<c:set var="var" value="#{empty var ? 'user' : var}" />
<c:set var="varName" value="#{empty var ? 'user' : var}" />
<c:set var="tableId" value="#{empty tableId ? 'userTable' : tableId}" />
<c:set var="paginator" value="#{empty paginator ? true : paginator}" />
<c:set var="rows" value="#{empty rows ? 20 : rows}" />
@@ -57,7 +57,7 @@
<p:dataTable
id="#{tableId}"
value="#{users}"
var="#{var}"
var="user"
paginator="#{paginator}"
rows="#{rows}"
selection="#{selection}"
@@ -73,32 +73,32 @@
</c:if>
<!-- Colonne Username -->
<p:column headerText="Nom d'utilisateur" sortBy="#{var.username}" style="width: 15%">
<p:column headerText="Nom d'utilisateur" sortBy="#{user.username}" style="width: 15%">
<div class="flex align-items-center gap-2">
<p:avatar
label="#{var.firstName != null ? var.firstName.substring(0,1) : 'U'}#{var.lastName != null ? var.lastName.substring(0,1) : ''}"
label="#{user.prenom != null ? user.prenom.substring(0,1) : 'U'}#{user.nom != null ? user.nom.substring(0,1) : ''}"
styleClass="user-avatar-small" />
<span class="font-semibold">#{var.username}</span>
<span class="font-semibold">#{user.username}</span>
</div>
</p:column>
<!-- Colonne Nom complet -->
<p:column headerText="Nom complet" sortBy="#{var.lastName}">
<p:column headerText="Nom complet" sortBy="#{user.nom}">
<div class="flex flex-column">
<span class="font-semibold">#{var.firstName} #{var.lastName}</span>
<c:if test="#{not empty var.fonction}">
<span class="text-color-secondary text-xs">#{var.fonction}</span>
<span class="font-semibold">#{user.prenom} #{user.nom}</span>
<c:if test="#{not empty user.fonction}">
<span class="text-color-secondary text-xs">#{user.fonction}</span>
</c:if>
</div>
</p:column>
<!-- Colonne Email -->
<c:if test="#{showEmail}">
<p:column headerText="Email" sortBy="#{var.email}">
<p:column headerText="Email" sortBy="#{user.email}">
<div class="flex align-items-center gap-2">
<i class="pi pi-envelope text-color-secondary"></i>
<span>#{var.email}</span>
<c:if test="#{var.emailVerified}">
<span>#{user.email}</span>
<c:if test="#{user.emailVerified}">
<i class="pi pi-check-circle text-green-500" title="Email vérifié"></i>
</c:if>
</div>
@@ -107,15 +107,15 @@
<!-- Colonne Statut -->
<c:if test="#{showStatus}">
<p:column headerText="Statut" sortBy="#{var.statut}">
<p:column headerText="Statut" sortBy="#{user.statut}">
<div class="flex align-items-center gap-2">
<p:tag
value="#{var.statut != null ? var.statut : 'INCONNU'}"
severity="#{var.enabled ? 'success' : 'danger'}" />
<c:if test="#{var.enabled}">
value="#{user.statut != null ? user.statut : 'INCONNU'}"
severity="#{user.enabled ? 'success' : 'danger'}" />
<c:if test="#{user.enabled}">
<i class="pi pi-check-circle text-green-500" title="Compte activé"></i>
</c:if>
<c:if test="#{not var.enabled}">
<c:if test="#{not user.enabled}">
<i class="pi pi-times-circle text-red-500" title="Compte désactivé"></i>
</c:if>
</div>
@@ -126,13 +126,13 @@
<c:if test="#{showRoles}">
<p:column headerText="Rôles">
<div class="flex flex-wrap gap-1">
<c:forEach var="role" items="#{var.realmRoles}" varStatus="status">
<c:if test="#{status.index < 3}">
<c:forEach var="role" items="#{user.realmRoles}" varStatus="status">
<c:if test="#{status.index &lt; 3}">
<p:tag value="#{role}" severity="info" styleClass="text-xs" />
</c:if>
</c:forEach>
<c:if test="#{var.realmRoles != null and var.realmRoles.size() > 3}">
<p:tag value="+#{var.realmRoles.size() - 3}" severity="secondary" styleClass="text-xs" />
<c:if test="#{user.realmRoles != null and user.realmRoles.size() &gt; 3}">
<p:tag value="+#{user.realmRoles.size() - 3}" severity="secondary" styleClass="text-xs" />
</c:if>
</div>
</p:column>
@@ -142,7 +142,7 @@
<c:if test="#{showActions}">
<p:column headerText="Actions" style="width: 150px">
<ui:include src="/templates/components/user-management/user-actions.xhtml">
<ui:param name="user" value="#{var}" />
<ui:param name="user" value="#{user}" />
<ui:param name="layout" value="dropdown" />
<ui:param name="update" value="#{not empty update ? update : tableId}" />
</ui:include>

View File

@@ -66,6 +66,13 @@
<c:set var="showResetPassword" value="#{empty showResetPassword ? true : showResetPassword}" />
<c:set var="showLogoutSessions" value="#{empty showLogoutSessions ? false : showLogoutSessions}" />
<!-- Définir les actions par défaut si non fournies -->
<c:set var="defaultActivateAction" value="#{userBean.activateUser(user.id)}" />
<c:set var="defaultDeactivateAction" value="#{userBean.deactivateUser(user.id)}" />
<c:set var="defaultDeleteAction" value="#{userBean.deleteUser(user.id)}" />
<c:set var="defaultResetPasswordAction" value="#{userBean.resetPassword(user.id)}" />
<c:set var="defaultLogoutSessionsAction" value="#{userBean.logoutAllSessions(user.id)}" />
<c:choose>
<!-- Layout Dropdown -->
<c:when test="#{layout == 'dropdown'}">
@@ -102,30 +109,66 @@
<p:separator />
<c:if test="#{showActivate and not user.enabled}">
<p:menuitem
value="Activer"
icon="pi pi-check"
styleClass="text-green-600"
action="#{not empty activateAction ? activateAction : userBean.activateUser(user.id)}"
update="#{update}" />
<c:choose>
<c:when test="#{not empty activateAction}">
<p:menuitem
value="Activer"
icon="pi pi-check"
styleClass="text-green-600"
action="#{activateAction}"
update="#{update}" />
</c:when>
<c:otherwise>
<p:menuitem
value="Activer"
icon="pi pi-check"
styleClass="text-green-600"
action="#{userBean.activateUser(user.id)}"
update="#{update}" />
</c:otherwise>
</c:choose>
</c:if>
<c:if test="#{showDeactivate and user.enabled}">
<p:menuitem
value="Désactiver"
icon="pi pi-times"
styleClass="text-orange-600"
action="#{not empty deactivateAction ? deactivateAction : userBean.deactivateUser(user.id)}"
update="#{update}" />
<c:choose>
<c:when test="#{not empty deactivateAction}">
<p:menuitem
value="Désactiver"
icon="pi pi-times"
styleClass="text-orange-600"
action="#{deactivateAction}"
update="#{update}" />
</c:when>
<c:otherwise>
<p:menuitem
value="Désactiver"
icon="pi pi-times"
styleClass="text-orange-600"
action="#{userBean.deactivateUser(user.id)}"
update="#{update}" />
</c:otherwise>
</c:choose>
</c:if>
<c:if test="#{showLogoutSessions}">
<p:menuitem
value="Déconnecter toutes les sessions"
icon="pi pi-sign-out"
styleClass="text-blue-600"
action="#{not empty logoutSessionsAction ? logoutSessionsAction : userBean.logoutAllSessions(user.id)}"
update="#{update}" />
<c:choose>
<c:when test="#{not empty logoutSessionsAction}">
<p:menuitem
value="Déconnecter toutes les sessions"
icon="pi pi-sign-out"
styleClass="text-blue-600"
action="#{logoutSessionsAction}"
update="#{update}" />
</c:when>
<c:otherwise>
<p:menuitem
value="Déconnecter toutes les sessions"
icon="pi pi-sign-out"
styleClass="text-blue-600"
action="#{userBean.logoutAllSessions(user.id)}"
update="#{update}" />
</c:otherwise>
</c:choose>
</c:if>
<c:if test="#{showDelete}">
@@ -172,30 +215,66 @@
</c:if>
<c:if test="#{showActivate and not user.enabled}">
<p:commandButton
icon="pi pi-check"
title="Activer"
styleClass="p-button-text p-button-sm p-button-success"
action="#{not empty activateAction ? activateAction : userBean.activateUser(user.id)}"
update="#{update}" />
<c:choose>
<c:when test="#{not empty activateAction}">
<p:commandButton
icon="pi pi-check"
title="Activer"
styleClass="p-button-text p-button-sm p-button-success"
action="#{activateAction}"
update="#{update}" />
</c:when>
<c:otherwise>
<p:commandButton
icon="pi pi-check"
title="Activer"
styleClass="p-button-text p-button-sm p-button-success"
action="#{userBean.activateUser(user.id)}"
update="#{update}" />
</c:otherwise>
</c:choose>
</c:if>
<c:if test="#{showDeactivate and user.enabled}">
<p:commandButton
icon="pi pi-times"
title="Désactiver"
styleClass="p-button-text p-button-sm p-button-warning"
action="#{not empty deactivateAction ? deactivateAction : userBean.deactivateUser(user.id)}"
update="#{update}" />
<c:choose>
<c:when test="#{not empty deactivateAction}">
<p:commandButton
icon="pi pi-times"
title="Désactiver"
styleClass="p-button-text p-button-sm p-button-warning"
action="#{deactivateAction}"
update="#{update}" />
</c:when>
<c:otherwise>
<p:commandButton
icon="pi pi-times"
title="Désactiver"
styleClass="p-button-text p-button-sm p-button-warning"
action="#{userBean.deactivateUser(user.id)}"
update="#{update}" />
</c:otherwise>
</c:choose>
</c:if>
<c:if test="#{showLogoutSessions}">
<p:commandButton
icon="pi pi-sign-out"
title="Déconnecter toutes les sessions"
styleClass="p-button-text p-button-sm p-button-info"
action="#{not empty logoutSessionsAction ? logoutSessionsAction : userBean.logoutAllSessions(user.id)}"
update="#{update}" />
<c:choose>
<c:when test="#{not empty logoutSessionsAction}">
<p:commandButton
icon="pi pi-sign-out"
title="Déconnecter toutes les sessions"
styleClass="p-button-text p-button-sm p-button-info"
action="#{logoutSessionsAction}"
update="#{update}" />
</c:when>
<c:otherwise>
<p:commandButton
icon="pi pi-sign-out"
title="Déconnecter toutes les sessions"
styleClass="p-button-text p-button-sm p-button-info"
action="#{userBean.logoutAllSessions(user.id)}"
update="#{update}" />
</c:otherwise>
</c:choose>
</c:if>
<c:if test="#{showDelete}">
@@ -216,13 +295,26 @@
message="Êtes-vous sûr de vouloir supprimer l'utilisateur #{user.username} ?"
header="Confirmation de suppression"
severity="warn">
<p:commandButton
value="Oui"
icon="pi pi-check"
styleClass="p-button-danger"
action="#{not empty deleteAction ? deleteAction : userBean.deleteUser(user.id)}"
update="#{update}"
oncomplete="PF('confirmDeleteDialog').hide()" />
<c:choose>
<c:when test="#{not empty deleteAction}">
<p:commandButton
value="Oui"
icon="pi pi-check"
styleClass="p-button-danger"
action="#{deleteAction}"
update="#{update}"
oncomplete="PF('confirmDeleteDialog').hide()" />
</c:when>
<c:otherwise>
<p:commandButton
value="Oui"
icon="pi pi-check"
styleClass="p-button-danger"
action="#{userBean.deleteUser(user.id)}"
update="#{update}"
oncomplete="PF('confirmDeleteDialog').hide()" />
</c:otherwise>
</c:choose>
<p:commandButton
value="Non"
icon="pi pi-times"
@@ -257,14 +349,28 @@
<f:facet name="footer">
<div class="flex gap-2 justify-content-end">
<p:commandButton
value="Réinitialiser"
icon="pi pi-check"
styleClass="p-button-primary"
action="#{not empty resetPasswordAction ? resetPasswordAction : userBean.resetPassword(user.id)}"
update="#{update}"
oncomplete="PF('resetPasswordDialog').hide()"
process="@form" />
<c:choose>
<c:when test="#{not empty resetPasswordAction}">
<p:commandButton
value="Réinitialiser"
icon="pi pi-check"
styleClass="p-button-primary"
action="#{resetPasswordAction}"
update="#{update}"
oncomplete="PF('resetPasswordDialog').hide()"
process="@form" />
</c:when>
<c:otherwise>
<p:commandButton
value="Réinitialiser"
icon="pi pi-check"
styleClass="p-button-primary"
action="#{userBean.resetPassword(user.id)}"
update="#{update}"
oncomplete="PF('resetPasswordDialog').hide()"
process="@form" />
</c:otherwise>
</c:choose>
<p:commandButton
value="Annuler"
icon="pi pi-times"

View File

@@ -19,9 +19,10 @@
- showRealmSelector: Boolean (défaut: false) - Afficher le sélecteur de realm
- showPasswordFields: Boolean (défaut: true) - Afficher les champs mot de passe
- readonly: Boolean (défaut: false) - Mode lecture seule
- submitAction: String (optionnel) - Action à exécuter à la soumission
- submitAction: String (optionnel) - Expression de méthode JSF à exécuter (ex: "#{bean.method}")
- submitOutcome: String (optionnel) - Page de redirection après soumission
- update: String (optionnel) - Composants à mettre à jour après soumission
- hasSubmitAction: Boolean (optionnel) - Indicateur si submitAction est fourni (pour éviter l'évaluation)
Exemples d'utilisation:
@@ -218,14 +219,38 @@
<f:facet name="footer">
<div class="flex gap-2 justify-content-end">
<c:if test="#{not readonly}">
<p:commandButton
value="#{mode == 'create' ? 'Créer' : 'Modifier'}"
icon="pi pi-check"
styleClass="p-button-success"
action="#{not empty submitAction ? submitAction : null}"
outcome="#{not empty submitOutcome ? submitOutcome : null}"
update="#{not empty update ? update : '@form'}"
process="@form" />
<c:choose>
<!-- Si hasSubmitAction est explicitement défini à true, utiliser action -->
<c:when test="#{hasSubmitAction == true}">
<p:commandButton
value="#{mode == 'create' ? 'Créer' : 'Modifier'}"
icon="pi pi-check"
styleClass="p-button-success"
action="#{submitAction}"
update="#{not empty update ? update : '@form'}"
process="@form" />
</c:when>
<!-- Si submitOutcome est fourni, utiliser outcome -->
<c:when test="#{not empty submitOutcome}">
<p:commandButton
value="#{mode == 'create' ? 'Créer' : 'Modifier'}"
icon="pi pi-check"
styleClass="p-button-success"
outcome="#{submitOutcome}"
update="#{not empty update ? update : '@form'}"
process="@form" />
</c:when>
<!-- Sinon, essayer d'utiliser submitAction si fourni -->
<c:otherwise>
<p:commandButton
value="#{mode == 'create' ? 'Créer' : 'Modifier'}"
icon="pi pi-check"
styleClass="p-button-success"
action="#{submitAction}"
update="#{not empty update ? update : '@form'}"
process="@form" />
</c:otherwise>
</c:choose>
</c:if>
<p:commandButton
value="Annuler"

View File

@@ -0,0 +1,181 @@
<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">
<p:panel styleClass="w-full mb-3">
<f:facet name="header">
<div class="flex align-items-center justify-content-between">
<span>Recherche d'utilisateurs</span>
<p:commandButton
icon="pi pi-filter"
styleClass="p-button-text p-button-sm"
onclick="PF('advancedSearchDialog').toggle()"
rendered="#{showAdvanced}"
title="Options avancées" />
</div>
</f:facet>
<!-- Recherche rapide -->
<div class="flex gap-2 align-items-end">
<div class="flex-1">
<p:outputLabel for="searchText" value="Rechercher" />
<p:inputText id="searchText"
value="#{searchCriteria.searchTerm}"
placeholder="Nom, prénom, email, username..."
styleClass="w-full">
<p:ajax event="keyup"
delay="500"
listener="#{searchAction}"
update="#{update}" />
</p:inputText>
</div>
<!-- Filtre Realm -->
<c:if test="#{showRealmFilter}">
<div style="width: 200px;">
<p:outputLabel for="realmFilter" value="Realm" />
<p:selectOneMenu id="realmFilter"
value="#{searchCriteria.realmName}"
styleClass="w-full">
<f:selectItem itemLabel="Tous les realms" itemValue="" />
<f:selectItems value="#{userBean.availableRealms}" />
</p:selectOneMenu>
</div>
</c:if>
<!-- Filtre Statut -->
<c:if test="#{showStatusFilter}">
<div style="width: 180px;">
<p:outputLabel for="statusFilter" value="Statut" />
<p:selectOneMenu id="statusFilter"
value="#{searchCriteria.statut}"
styleClass="w-full">
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
<f:selectItems value="#{userBean.statutOptions}" />
</p:selectOneMenu>
</div>
</c:if>
<!-- Bouton Rechercher -->
<div>
<p:commandButton
value="Rechercher"
icon="pi pi-search"
styleClass="p-button-primary"
action="#{searchAction}"
update="#{update}"
process="@form" />
</div>
<!-- Bouton Réinitialiser -->
<div>
<p:commandButton
value="Réinitialiser"
icon="pi pi-refresh"
styleClass="p-button-secondary"
action="#{userBean.resetSearch}"
update="#{update}"
process="@form" />
</div>
</div>
</p:panel>
<!-- Options avancées (Dialog) -->
<c:if test="#{showAdvanced}">
<p:dialog id="advancedSearchDialog"
header="Options de recherche avancées"
widgetVar="advancedSearchDialog"
modal="true"
resizable="false"
styleClass="w-full md:w-6">
<p:panelGrid columns="2" styleClass="w-full" columnClasses="col-12 md:col-6">
<!-- Email -->
<p:outputLabel for="emailFilter" value="Email" />
<p:inputText id="emailFilter"
value="#{searchCriteria.email}"
placeholder="email@example.com"
styleClass="w-full" />
<!-- Téléphone -->
<p:outputLabel for="phoneFilter" value="Téléphone" />
<p:inputText id="phoneFilter"
value="#{searchCriteria.telephone}"
placeholder="+225 07 12 34 56 78"
styleClass="w-full" />
<!-- Organisation -->
<p:outputLabel for="orgFilter" value="Organisation" />
<p:inputText id="orgFilter"
value="#{searchCriteria.organisation}"
placeholder="Nom de l'organisation"
styleClass="w-full" />
<!-- Ville -->
<p:outputLabel for="cityFilter" value="Ville" />
<p:inputText id="cityFilter"
value="#{searchCriteria.ville}"
placeholder="Nom de la ville"
styleClass="w-full" />
<!-- Rôle (si affiché) -->
<c:if test="#{showRoleFilter}">
<p:outputLabel for="roleFilter" value="Rôle Realm" />
<p:selectManyMenu id="roleFilter"
value="#{searchCriteria.realmRoles}"
styleClass="w-full">
<f:selectItem itemLabel="Tous les rôles" itemValue="" />
<f:selectItems value="#{userBean.availableRoles}" />
</p:selectManyMenu>
</c:if>
<!-- Date de création (début) -->
<p:outputLabel for="dateDebut" value="Date de création (début)" />
<p:calendar id="dateDebut"
value="#{searchCriteria.dateCreationMin}"
pattern="dd/MM/yyyy"
styleClass="w-full" />
<!-- Date de création (fin) -->
<p:outputLabel for="dateFin" value="Date de création (fin)" />
<p:calendar id="dateFin"
value="#{searchCriteria.dateCreationMax}"
pattern="dd/MM/yyyy"
styleClass="w-full" />
<!-- Enabled -->
<p:outputLabel for="enabledFilter" value="Compte activé" />
<p:selectOneMenu id="enabledFilter"
value="#{searchCriteria.enabled}"
styleClass="w-full">
<f:selectItem itemLabel="Tous" itemValue="" />
<f:selectItem itemLabel="Activé" itemValue="true" />
<f:selectItem itemLabel="Désactivé" itemValue="false" />
</p:selectOneMenu>
</p:panelGrid>
<f:facet name="footer">
<div class="flex gap-2 justify-content-end">
<p:commandButton
value="Appliquer"
icon="pi pi-check"
styleClass="p-button-primary"
action="#{searchAction}"
update="#{update}"
onclick="PF('advancedSearchDialog').hide()"
process="@form" />
<p:commandButton
value="Annuler"
icon="pi pi-times"
styleClass="p-button-secondary"
onclick="PF('advancedSearchDialog').hide()" />
</div>
</f:facet>
</p:dialog>
</c:if>
</ui:composition>

View File

@@ -21,6 +21,7 @@
- showStatusFilter: Boolean (défaut: true) - Afficher le filtre statut
- showRoleFilter: Boolean (défaut: true) - Afficher le filtre rôle
- formId: String (défaut: "searchForm") - ID du formulaire
- useParentForm: Boolean (défaut: false) - Si true, n'crée pas de formulaire (utilise le formulaire parent)
Exemples d'utilisation:
@@ -31,13 +32,15 @@
<ui:param name="update" value="userTable" />
</ui:include>
2. Recherche avec options avancées:
<ui:include src="/templates/components/user-management/user-search-bar.xhtml">
<ui:param name="searchCriteria" value="#{userBean.searchCriteria}" />
<ui:param name="searchAction" value="#{userBean.search}" />
<ui:param name="showAdvanced" value="true" />
<ui:param name="update" value="userTable" />
</ui:include>
2. Recherche avec formulaire parent:
<h:form id="formUsers">
<ui:include src="/templates/components/user-management/user-search-bar.xhtml">
<ui:param name="searchCriteria" value="#{userBean.searchCriteria}" />
<ui:param name="searchAction" value="#{userBean.search}" />
<ui:param name="update" value="userTable" />
<ui:param name="useParentForm" value="true" />
</ui:include>
</h:form>
-->
<c:set var="formId" value="#{empty formId ? 'searchForm' : formId}" />
@@ -46,180 +49,35 @@
<c:set var="showRealmFilter" value="#{empty showRealmFilter ? true : showRealmFilter}" />
<c:set var="showStatusFilter" value="#{empty showStatusFilter ? true : showStatusFilter}" />
<c:set var="showRoleFilter" value="#{empty showRoleFilter ? true : showRoleFilter}" />
<c:set var="useParentForm" value="#{empty useParentForm ? false : useParentForm}" />
<h:form id="#{formId}">
<p:panel styleClass="w-full mb-3">
<f:facet name="header">
<div class="flex align-items-center justify-content-between">
<span>Recherche d'utilisateurs</span>
<p:commandButton
icon="pi pi-filter"
styleClass="p-button-text p-button-sm"
onclick="PF('advancedSearchDialog').toggle()"
rendered="#{showAdvanced}"
title="Options avancées" />
</div>
</f:facet>
<!-- Recherche rapide -->
<div class="flex gap-2 align-items-end">
<div class="flex-1">
<p:outputLabel for="searchText" value="Rechercher" />
<p:inputText id="searchText"
value="#{searchCriteria.searchText}"
placeholder="Nom, prénom, email, username..."
styleClass="w-full">
<p:ajax event="keyup"
delay="500"
listener="#{searchAction}"
update="#{update}" />
</p:inputText>
</div>
<!-- Filtre Realm -->
<c:if test="#{showRealmFilter}">
<div style="width: 200px;">
<p:outputLabel for="realmFilter" value="Realm" />
<p:selectOneMenu id="realmFilter"
value="#{searchCriteria.realmName}"
styleClass="w-full">
<f:selectItem itemLabel="Tous les realms" itemValue="" />
<f:selectItems value="#{userBean.availableRealms}" />
</p:selectOneMenu>
</div>
</c:if>
<!-- Filtre Statut -->
<c:if test="#{showStatusFilter}">
<div style="width: 180px;">
<p:outputLabel for="statusFilter" value="Statut" />
<p:selectOneMenu id="statusFilter"
value="#{searchCriteria.statut}"
styleClass="w-full">
<f:selectItem itemLabel="Tous les statuts" itemValue="" />
<f:selectItems value="#{userBean.statutOptions}" />
</p:selectOneMenu>
</div>
</c:if>
<!-- Bouton Rechercher -->
<div>
<p:commandButton
value="Rechercher"
icon="pi pi-search"
styleClass="p-button-primary"
action="#{searchAction}"
update="#{update}"
process="@form" />
</div>
<!-- Bouton Réinitialiser -->
<div>
<p:commandButton
value="Réinitialiser"
icon="pi pi-refresh"
styleClass="p-button-secondary"
action="#{userBean.resetSearch}"
update="#{update}"
process="@form" />
</div>
</div>
</p:panel>
<!-- Options avancées (Dialog) -->
<c:if test="#{showAdvanced}">
<p:dialog id="advancedSearchDialog"
header="Options de recherche avancées"
widgetVar="advancedSearchDialog"
modal="true"
resizable="false"
styleClass="w-full md:w-6">
<p:panelGrid columns="2" styleClass="w-full" columnClasses="col-12 md:col-6">
<!-- Email -->
<p:outputLabel for="emailFilter" value="Email" />
<p:inputText id="emailFilter"
value="#{searchCriteria.email}"
placeholder="email@example.com"
styleClass="w-full" />
<!-- Téléphone -->
<p:outputLabel for="phoneFilter" value="Téléphone" />
<p:inputText id="phoneFilter"
value="#{searchCriteria.telephone}"
placeholder="+225 07 12 34 56 78"
styleClass="w-full" />
<!-- Organisation -->
<p:outputLabel for="orgFilter" value="Organisation" />
<p:inputText id="orgFilter"
value="#{searchCriteria.organisation}"
placeholder="Nom de l'organisation"
styleClass="w-full" />
<!-- Ville -->
<p:outputLabel for="cityFilter" value="Ville" />
<p:inputText id="cityFilter"
value="#{searchCriteria.ville}"
placeholder="Nom de la ville"
styleClass="w-full" />
<!-- Rôle (si affiché) -->
<c:if test="#{showRoleFilter}">
<p:outputLabel for="roleFilter" value="Rôle" />
<p:selectOneMenu id="roleFilter"
value="#{searchCriteria.roleName}"
styleClass="w-full">
<f:selectItem itemLabel="Tous les rôles" itemValue="" />
<f:selectItems value="#{userBean.availableRoles}" />
</p:selectOneMenu>
</c:if>
<!-- Date de création (début) -->
<p:outputLabel for="dateDebut" value="Date de création (début)" />
<p:calendar id="dateDebut"
value="#{searchCriteria.dateCreationDebut}"
pattern="dd/MM/yyyy"
styleClass="w-full" />
<!-- Date de création (fin) -->
<p:outputLabel for="dateFin" value="Date de création (fin)" />
<p:calendar id="dateFin"
value="#{searchCriteria.dateCreationFin}"
pattern="dd/MM/yyyy"
styleClass="w-full" />
<!-- Enabled -->
<p:outputLabel for="enabledFilter" value="Compte activé" />
<p:selectOneMenu id="enabledFilter"
value="#{searchCriteria.enabled}"
styleClass="w-full">
<f:selectItem itemLabel="Tous" itemValue="" />
<f:selectItem itemLabel="Activé" itemValue="true" />
<f:selectItem itemLabel="Désactivé" itemValue="false" />
</p:selectOneMenu>
</p:panelGrid>
<f:facet name="footer">
<div class="flex gap-2 justify-content-end">
<p:commandButton
value="Appliquer"
icon="pi pi-check"
styleClass="p-button-primary"
action="#{searchAction}"
update="#{update}"
onclick="PF('advancedSearchDialog').hide()"
process="@form" />
<p:commandButton
value="Annuler"
icon="pi pi-times"
styleClass="p-button-secondary"
onclick="PF('advancedSearchDialog').hide()" />
</div>
</f:facet>
</p:dialog>
</c:if>
</h:form>
<c:choose>
<c:when test="#{useParentForm}">
<!-- Utiliser le formulaire parent - pas de formulaire ici -->
<ui:include src="/templates/components/user-management/user-search-bar-content.xhtml">
<ui:param name="searchCriteria" value="#{searchCriteria}" />
<ui:param name="searchAction" value="#{searchAction}" />
<ui:param name="update" value="#{update}" />
<ui:param name="showAdvanced" value="#{showAdvanced}" />
<ui:param name="showRealmFilter" value="#{showRealmFilter}" />
<ui:param name="showStatusFilter" value="#{showStatusFilter}" />
<ui:param name="showRoleFilter" value="#{showRoleFilter}" />
</ui:include>
</c:when>
<c:otherwise>
<!-- Créer son propre formulaire -->
<h:form id="#{formId}">
<ui:include src="/templates/components/user-management/user-search-bar-content.xhtml">
<ui:param name="searchCriteria" value="#{searchCriteria}" />
<ui:param name="searchAction" value="#{searchAction}" />
<ui:param name="update" value="#{update}" />
<ui:param name="showAdvanced" value="#{showAdvanced}" />
<ui:param name="showRealmFilter" value="#{showRealmFilter}" />
<ui:param name="showStatusFilter" value="#{showStatusFilter}" />
<ui:param name="showRoleFilter" value="#{showRoleFilter}" />
</ui:include>
</h:form>
</c:otherwise>
</c:choose>
</ui:composition>