You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by fm...@apache.org on 2015/11/17 14:59:55 UTC

[3/3] syncope git commit: [SYNCOPE-156] providing status panel for any objects

[SYNCOPE-156] providing status panel for any objects


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/e034afcd
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/e034afcd
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/e034afcd

Branch: refs/heads/master
Commit: e034afcd5e7da01d56d9222d85f14d3b15cb4c6a
Parents: c2ce2e8
Author: fmartelli <fa...@gmail.com>
Authored: Tue Nov 17 14:59:33 2015 +0100
Committer: fmartelli <fa...@gmail.com>
Committed: Tue Nov 17 14:59:33 2015 +0100

----------------------------------------------------------------------
 .../client/console/commons/AnyDataProvider.java |   2 +-
 .../commons/NotificationAwareComponent.java     |  25 +
 .../console/commons/status/StatusBean.java      |   4 +-
 .../console/commons/status/StatusUtils.java     |  19 +-
 .../client/console/pages/AbstractBasePage.java  |   4 +-
 .../client/console/pages/StatusModal.java       | 648 +++++++++++++++++++
 .../client/console/pages/StatusModalPage.java   | 648 -------------------
 .../console/panels/AnySearchResultPanel.java    |   4 +-
 .../console/panels/GroupSearchResultPanel.java  |   6 +-
 .../client/console/panels/ListViewPanel.java    | 187 ++++--
 .../client/console/panels/ResourceModal.java    |   2 +-
 .../console/panels/UserSearchResultPanel.java   |  16 +-
 .../console/rest/AbstractAnyRestClient.java     |   2 +-
 .../console/rest/AnyObjectRestClient.java       |   6 +-
 .../client/console/rest/GroupRestClient.java    |   2 +-
 .../client/console/rest/UserRestClient.java     |   2 +-
 .../markup/html/ClearIndicatingAjaxLink.java    |   8 +-
 .../markup/html/bootstrap/dialog/BaseModal.java |   4 +-
 .../wicket/markup/html/form/ActionLink.java     |  15 +
 .../markup/html/form/ActionLinksPanel.java      | 131 ++--
 .../client/console/wizards/AjaxWizard.java      |  42 +-
 .../console/wizards/AjaxWizardBuilder.java      |   8 +-
 .../client/console/wizards/WizardMgtPanel.java  |  19 +-
 .../console/wizards/any/AnyWizardBuilder.java   |  12 +
 .../console/wizards/any/ConnObjectPanel.java    |  98 +++
 .../client/console/wizards/any/Details.java     |  46 ++
 .../console/wizards/any/GroupDetails.java       |  15 +-
 .../console/wizards/any/GroupWizardBuilder.java |  16 +-
 .../console/wizards/any/PasswordPanel.java      |   4 +-
 .../client/console/wizards/any/PlainAttrs.java  |   4 +-
 .../client/console/wizards/any/StatusPanel.java | 220 +++++++
 .../client/console/wizards/any/UserDetails.java |  48 +-
 .../console/wizards/any/UserWizardBuilder.java  |  42 +-
 .../panels/AbstractSearchResultPanel.properties |   4 +-
 .../AbstractSearchResultPanel_it.properties     |   4 +-
 .../AbstractSearchResultPanel_pt_BR.properties  |   4 +-
 .../client/console/panels/ListViewPanel.html    |  26 +-
 .../markup/html/form/ActionLinksPanel.html      |   2 +-
 .../client/console/wizards/WizardMgtPanel.html  |   8 +-
 .../console/wizards/any/ConnObjectPanel.html    |  26 +
 .../client/console/wizards/any/Details.html     |  27 +
 .../console/wizards/any/GroupDetails.html       |   4 +-
 .../client/console/wizards/any/StatusPanel.html |  46 ++
 .../console/wizards/any/StatusPanel.properties  |  19 +
 .../wizards/any/StatusPanel_it.properties       |  19 +
 .../wizards/any/StatusPanel_pt_BR.properties    |  19 +
 .../client/console/wizards/any/UserDetails.html |   5 +-
 .../console/wizards/any/UserDetails.properties  |   1 +
 .../wizards/any/UserDetails_it.properties       |   1 +
 .../wizards/any/UserDetails_pt_BR.properties    |   3 +-
 50 files changed, 1688 insertions(+), 839 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/e034afcd/client/console/src/main/java/org/apache/syncope/client/console/commons/AnyDataProvider.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/AnyDataProvider.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/AnyDataProvider.java
index dbf823b..6a2d226 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/AnyDataProvider.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/AnyDataProvider.java
@@ -99,7 +99,7 @@ public class AnyDataProvider<T extends AnyTO> extends SortableDataProvider<T, St
                     ? 0
                     : restClient.searchCount(realm, fiql, type);
         } else {
-            result = restClient.count(realm);
+            result = restClient.count(type, realm);
         }
 
         return result;

http://git-wip-us.apache.org/repos/asf/syncope/blob/e034afcd/client/console/src/main/java/org/apache/syncope/client/console/commons/NotificationAwareComponent.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/NotificationAwareComponent.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/NotificationAwareComponent.java
new file mode 100644
index 0000000..b767db0
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/NotificationAwareComponent.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.commons;
+
+import org.apache.syncope.client.console.panels.NotificationPanel;
+
+public interface NotificationAwareComponent {
+    NotificationPanel getFeedbackPanel();
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/e034afcd/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusBean.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusBean.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusBean.java
index 893b8aa..3a317b8 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusBean.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusBean.java
@@ -45,7 +45,9 @@ public class StatusBean implements Serializable {
 
     public StatusBean(final AnyTO any, final String resourceName) {
         this.anyKey = any.getKey();
-        this.anyName = any instanceof UserTO ? ((UserTO) any).getUsername() : ((GroupTO) any).getName();
+        this.anyName = any instanceof UserTO
+                ? ((UserTO) any).getUsername()
+                : any instanceof GroupTO ? ((GroupTO) any).getName() : String.valueOf(any.getKey());
         this.resourceName = resourceName;
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/e034afcd/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusUtils.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusUtils.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusUtils.java
index 73da6a7..0e5c02f 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusUtils.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/status/StatusUtils.java
@@ -28,6 +28,7 @@ import org.apache.syncope.client.console.commons.ConnIdSpecialAttributeName;
 import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.panels.ImagePanel;
 import org.apache.syncope.client.console.rest.AbstractAnyRestClient;
+import org.apache.syncope.common.lib.patch.PasswordPatch;
 import org.apache.syncope.common.lib.patch.StatusPatch;
 import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.AttrTO;
@@ -48,9 +49,9 @@ public class StatusUtils implements Serializable {
 
     private static final String IMG_PREFIX = "/img/statuses/";
 
-    private final AbstractAnyRestClient restClient;
+    private final AbstractAnyRestClient<?> restClient;
 
-    public StatusUtils(final AbstractAnyRestClient restClient) {
+    public StatusUtils(final AbstractAnyRestClient<?> restClient) {
         this.restClient = restClient;
     }
 
@@ -139,6 +140,20 @@ public class StatusUtils implements Serializable {
                 : null;
     }
 
+    public static PasswordPatch buildPasswordPatch(final String password, final Collection<StatusBean> statuses) {
+        final PasswordPatch.Builder builder = new PasswordPatch.Builder();
+        builder.value(password);
+
+        for (StatusBean status : statuses) {
+            if ("syncope".equalsIgnoreCase(status.getResourceName())) {
+                builder.onSyncope(true);
+            } else {
+                builder.resource(status.getResourceName());
+            }
+        }
+        return builder.build();
+    }
+
     public static StatusPatch buildStatusPatch(final Collection<StatusBean> statuses) {
         return buildStatusPatch(statuses, null);
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/e034afcd/client/console/src/main/java/org/apache/syncope/client/console/pages/AbstractBasePage.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/AbstractBasePage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/AbstractBasePage.java
index c4096af..247051e 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/pages/AbstractBasePage.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/AbstractBasePage.java
@@ -19,6 +19,7 @@
 package org.apache.syncope.client.console.pages;
 
 import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.NotificationAwareComponent;
 import org.apache.syncope.client.console.panels.NotificationPanel;
 import org.apache.syncope.client.console.wicket.markup.head.MetaHeaderItem;
 import org.apache.wicket.markup.head.HeaderItem;
@@ -29,7 +30,7 @@ import org.apache.wicket.request.mapper.parameter.PageParameters;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class AbstractBasePage extends WebPage {
+public class AbstractBasePage extends WebPage implements NotificationAwareComponent {
 
     private static final long serialVersionUID = 8611724965544132636L;
 
@@ -64,6 +65,7 @@ public class AbstractBasePage extends WebPage {
         add(feedbackPanel);
     }
 
+    @Override
     public NotificationPanel getFeedbackPanel() {
         return feedbackPanel;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/e034afcd/client/console/src/main/java/org/apache/syncope/client/console/pages/StatusModal.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/StatusModal.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/StatusModal.java
new file mode 100644
index 0000000..e6c7a27
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/StatusModal.java
@@ -0,0 +1,648 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.pages;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.status.AbstractStatusBeanProvider;
+import org.apache.syncope.client.console.commons.status.ConnObjectWrapper;
+import org.apache.syncope.client.console.commons.status.Status;
+import org.apache.syncope.client.console.commons.status.StatusBean;
+import org.apache.syncope.client.console.commons.status.StatusUtils;
+import org.apache.syncope.client.console.panels.ActionDataTablePanel;
+import org.apache.syncope.client.console.rest.GroupRestClient;
+import org.apache.syncope.client.console.rest.ResourceRestClient;
+import org.apache.syncope.client.console.rest.UserRestClient;
+import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxButton;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.BulkActionResult;
+import org.apache.syncope.common.lib.to.ResourceTO;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.types.ResourceAssociationAction;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.PasswordTextField;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.model.StringResourceModel;
+
+public class StatusModal<T extends AnyTO> extends AbstractStatusModalPage {
+
+    private static final long serialVersionUID = -9148734710505211261L;
+
+    private final UserRestClient userRestClient = new UserRestClient();
+
+    private final GroupRestClient groupRestClient = new GroupRestClient();
+
+    private final ResourceRestClient resourceRestClient = new ResourceRestClient();
+
+    private final AnyTO anyTO;
+
+    private int rowsPerPage = 10;
+
+    private final StatusUtils statusUtils;
+
+    private final boolean statusOnly;
+
+    // --------------------------------
+    // password management fields ..
+    // --------------------------------
+    private final ClearIndicatingAjaxButton cancel;
+
+    private final WebMarkupContainer pwdMgt;
+
+    private final Form<?> pwdMgtForm;
+
+    private final AjaxCheckBoxPanel changepwd;
+
+    private final PasswordTextField password;
+
+    private final PasswordTextField confirm;
+    // --------------------------------
+
+    private final ActionDataTablePanel<StatusBean, String> table;
+
+    private final List<IColumn<StatusBean, String>> columns;
+
+    public StatusModal(
+            final BaseModal<T> modal,
+            final PageReference pageRef,
+            final AnyTO attributableTO) {
+
+        this(modal, pageRef, attributableTO, false);
+    }
+
+    public StatusModal(
+            final BaseModal<T> modal,
+            final PageReference pageRef,
+            final AnyTO anyTO,
+            final boolean statusOnly) {
+
+        super(modal, pageRef);
+
+        this.statusOnly = statusOnly;
+        this.anyTO = anyTO;
+
+        statusUtils = new StatusUtils(anyTO instanceof UserTO ? userRestClient : groupRestClient);
+
+        add(new Label("displayName", anyTO.getKey() + " "
+                + (anyTO instanceof UserTO ? ((UserTO) anyTO).getUsername() : ((GroupTO) anyTO).getName())));
+
+        columns = new ArrayList<>();
+        columns.add(new AbstractColumn<StatusBean, String>(
+                new StringResourceModel("resourceName", this, null), "resourceName") {
+
+                    private static final long serialVersionUID = 2054811145491901166L;
+
+                    @Override
+                    public void populateItem(
+                            final Item<ICellPopulator<StatusBean>> cellItem,
+                            final String componentId,
+                            final IModel<StatusBean> model) {
+
+                                cellItem.add(new Label(componentId, model.getObject().getResourceName()) {
+
+                                    private static final long serialVersionUID = 8432079838783825801L;
+
+                                    @Override
+                                    protected void onComponentTag(final ComponentTag tag) {
+                                        if (model.getObject().isLinked()) {
+                                            super.onComponentTag(tag);
+                                        } else {
+                                            tag.put("style", "color: #DDDDDD");
+                                        }
+                                    }
+                                });
+                            }
+                });
+
+        columns.add(new PropertyColumn<StatusBean, String>(
+                new StringResourceModel("connObjectLink", this, null), "connObjectLink", "connObjectLink"));
+
+        columns.add(new AbstractColumn<StatusBean, String>(
+                new StringResourceModel("status", this, null)) {
+
+                    private static final long serialVersionUID = -3503023501954863131L;
+
+                    @Override
+                    public String getCssClass() {
+                        return "action";
+                    }
+
+                    @Override
+                    public void populateItem(
+                            final Item<ICellPopulator<StatusBean>> cellItem,
+                            final String componentId,
+                            final IModel<StatusBean> model) {
+
+                                if (model.getObject().isLinked()) {
+                                    cellItem.add(statusUtils.getStatusImagePanel(componentId, model.getObject().
+                                                    getStatus()));
+                                } else {
+                                    cellItem.add(new Label(componentId, ""));
+                                }
+                            }
+                });
+
+        table = new ActionDataTablePanel<StatusBean, String>(
+                "resourceDatatable",
+                columns,
+                (ISortableDataProvider<StatusBean, String>) new AttributableStatusProvider(),
+                rowsPerPage,
+                pageRef) {
+
+                    private static final long serialVersionUID = 6510391461033818316L;
+
+                    @Override
+                    public boolean isElementEnabled(final StatusBean element) {
+                        return !statusOnly || element.getStatus() != Status.OBJECT_NOT_FOUND;
+                    }
+                };
+        table.setOutputMarkupId(true);
+
+        final String pageId = anyTO instanceof GroupTO ? "Groups" : "Users";
+
+        final Fragment pwdMgtFragment = new Fragment("pwdMgtFields", "pwdMgtFragment", this);
+        addOrReplace(pwdMgtFragment);
+
+        pwdMgt = new WebMarkupContainer("pwdMgt");
+        pwdMgtFragment.add(pwdMgt.setOutputMarkupId(true));
+
+        pwdMgtForm = new Form<>("pwdMgtForm");
+        pwdMgtForm.setVisible(false).setEnabled(false);
+        pwdMgt.add(pwdMgtForm);
+
+        password = new PasswordTextField("password", new Model<String>());
+        pwdMgtForm.add(password.setRequired(false).setEnabled(false));
+
+        confirm = new PasswordTextField("confirm", new Model<String>());
+        pwdMgtForm.add(confirm.setRequired(false).setEnabled(false));
+
+        changepwd = new AjaxCheckBoxPanel("changepwd", "changepwd", new Model<>(false));
+        pwdMgtForm.add(changepwd.setModelObject(false));
+        pwdMgtForm.add(new Label("changePwdLabel", new ResourceModel("changePwdLabel", "Password propagation")));
+
+        changepwd.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                password.setEnabled(changepwd.getModelObject());
+                confirm.setEnabled(changepwd.getModelObject());
+                target.add(pwdMgt);
+            }
+        });
+
+        cancel = new ClearIndicatingAjaxButton("cancel", new ResourceModel("cancel"), pageRef) {
+
+            private static final long serialVersionUID = -2341391430136818026L;
+
+            @Override
+            protected void onSubmitInternal(final AjaxRequestTarget target, final Form<?> form) {
+                // ignore
+                modal.close(target);
+            }
+        }.feedbackPanelAutomaticReload(false);
+
+        pwdMgtForm.add(cancel);
+
+        final ClearIndicatingAjaxButton goon = new ClearIndicatingAjaxButton("continue", new ResourceModel("continue"),
+                pageRef) {
+
+                    private static final long serialVersionUID = -2341391430136818027L;
+
+                    @Override
+                    protected void onSubmitInternal(final AjaxRequestTarget target, final Form<?> form) {
+                        // none
+                    }
+                };
+
+        pwdMgtForm.add(goon);
+
+        if (statusOnly) {
+            table.addAction(new ActionLink<Serializable>() {
+
+                private static final long serialVersionUID = -3722207913631435501L;
+
+                @Override
+                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
+                    try {
+                        userRestClient.reactivate(
+                                anyTO.getETagValue(),
+                                anyTO.getKey(),
+                                new ArrayList<>(table.getModelObject()));
+
+                        ((BasePage) pageRef.getPage()).setModalResult(true);
+
+                        modal.close(target);
+                    } catch (Exception e) {
+                        LOG.error("Error enabling resources", e);
+                        error(getString(Constants.ERROR) + ": " + e.getMessage());
+                        modal.getFeedbackPanel().refresh(target);
+                    }
+                }
+            }, ActionLink.ActionType.REACTIVATE, pageId);
+
+            table.addAction(new ActionLink<Serializable>() {
+
+                private static final long serialVersionUID = -3722207913631435501L;
+
+                @Override
+                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
+                    try {
+                        userRestClient.suspend(
+                                anyTO.getETagValue(),
+                                anyTO.getKey(),
+                                new ArrayList<>(table.getModelObject()));
+
+                        if (pageRef.getPage() instanceof BasePage) {
+                            ((BasePage) pageRef.getPage()).setModalResult(true);
+                        }
+
+                        modal.close(target);
+                    } catch (Exception e) {
+                        LOG.error("Error disabling resources", e);
+                        error(getString(Constants.ERROR) + ": " + e.getMessage());
+                        modal.getFeedbackPanel().refresh(target);
+                    }
+                }
+            }, ActionLink.ActionType.SUSPEND, pageId);
+        } else {
+            table.addAction(new ActionLink<Serializable>() {
+
+                private static final long serialVersionUID = -3722207913631435501L;
+
+                @Override
+                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
+                    try {
+                        if (anyTO instanceof UserTO) {
+                            userRestClient.unlink(
+                                    anyTO.getETagValue(),
+                                    anyTO.getKey(),
+                                    new ArrayList<>(table.getModelObject()));
+                        } else {
+                            groupRestClient.unlink(
+                                    anyTO.getETagValue(),
+                                    anyTO.getKey(),
+                                    new ArrayList<>(table.getModelObject()));
+                        }
+
+                        ((BasePage) pageRef.getPage()).setModalResult(true);
+                        modal.close(target);
+                    } catch (Exception e) {
+                        LOG.error("Error unlinking resources", e);
+                        error(getString(Constants.ERROR) + ": " + e.getMessage());
+                        modal.getFeedbackPanel().refresh(target);
+                    }
+                }
+            }, ActionLink.ActionType.UNLINK, pageId);
+
+            table.addAction(new ActionLink<Serializable>() {
+
+                private static final long serialVersionUID = -3722207913631435501L;
+
+                @Override
+                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
+                    try {
+                        if (anyTO instanceof UserTO) {
+                            userRestClient.link(
+                                    anyTO.getETagValue(),
+                                    anyTO.getKey(),
+                                    new ArrayList<>(table.getModelObject()));
+                        } else {
+                            groupRestClient.link(
+                                    anyTO.getETagValue(),
+                                    anyTO.getKey(),
+                                    new ArrayList<>(table.getModelObject()));
+                        }
+
+                        ((BasePage) pageRef.getPage()).setModalResult(true);
+                        modal.close(target);
+                    } catch (Exception e) {
+                        LOG.error("Error linking resources", e);
+                        error(getString(Constants.ERROR) + ": " + e.getMessage());
+                        modal.getFeedbackPanel().refresh(target);
+                    }
+                }
+            }, ActionLink.ActionType.LINK, pageId);
+
+            table.addAction(new ActionLink<Serializable>() {
+
+                private static final long serialVersionUID = -3722207913631435501L;
+
+                @Override
+                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
+                    try {
+                        BulkActionResult bulkActionResult;
+                        if (anyTO instanceof UserTO) {
+                            bulkActionResult = userRestClient.deprovision(
+                                    anyTO.getETagValue(),
+                                    anyTO.getKey(),
+                                    new ArrayList<>(table.getModelObject()));
+                        } else {
+                            bulkActionResult = groupRestClient.deprovision(
+                                    anyTO.getETagValue(),
+                                    anyTO.getKey(),
+                                    new ArrayList<>(table.getModelObject()));
+                        }
+
+                        ((BasePage) pageRef.getPage()).setModalResult(true);
+                        loadBulkActionResultPage(target, table.getModelObject(), bulkActionResult);
+                    } catch (Exception e) {
+                        LOG.error("Error de-provisioning user", e);
+                        error(getString(Constants.ERROR) + ": " + e.getMessage());
+                        modal.getFeedbackPanel().refresh(target);
+                    }
+                }
+            }, ActionLink.ActionType.DEPROVISION, pageId);
+
+            table.addAction(new ActionLink<Serializable>() {
+
+                private static final long serialVersionUID = -3722207913631435501L;
+
+                @Override
+                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
+
+                    if (anyTO instanceof UserTO) {
+                        StatusModal.this.passwordManagement(
+                                target, ResourceAssociationAction.PROVISION, table.getModelObject());
+                    } else {
+                        try {
+                            final BulkActionResult bulkActionResult = groupRestClient.provision(
+                                    anyTO.getETagValue(),
+                                    anyTO.getKey(),
+                                    new ArrayList<>(table.getModelObject()));
+
+                            ((BasePage) pageRef.getPage()).setModalResult(true);
+                            loadBulkActionResultPage(target, table.getModelObject(), bulkActionResult);
+                        } catch (Exception e) {
+                            LOG.error("Error provisioning user", e);
+                            error(getString(Constants.ERROR) + ": " + e.getMessage());
+                            modal.getFeedbackPanel().refresh(target);
+                        }
+                    }
+                }
+            }.feedbackPanelAutomaticReload(!(anyTO instanceof UserTO)), ActionLink.ActionType.PROVISION, pageId);
+
+            table.addAction(new ActionLink<Serializable>() {
+
+                private static final long serialVersionUID = -3722207913631435501L;
+
+                @Override
+                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
+                    try {
+                        final BulkActionResult bulkActionResult;
+                        if (anyTO instanceof UserTO) {
+                            bulkActionResult = userRestClient.unassign(
+                                    anyTO.getETagValue(),
+                                    anyTO.getKey(),
+                                    new ArrayList<>(table.getModelObject()));
+                        } else {
+                            bulkActionResult = groupRestClient.unassign(
+                                    anyTO.getETagValue(),
+                                    anyTO.getKey(),
+                                    new ArrayList<>(table.getModelObject()));
+                        }
+
+                        ((BasePage) pageRef.getPage()).setModalResult(true);
+                        loadBulkActionResultPage(target, table.getModelObject(), bulkActionResult);
+                    } catch (Exception e) {
+                        LOG.error("Error unassigning resources", e);
+                        error(getString(Constants.ERROR) + ": " + e.getMessage());
+                        modal.getFeedbackPanel().refresh(target);
+                    }
+                }
+            }, ActionLink.ActionType.UNASSIGN, pageId);
+
+            table.addAction(new ActionLink<Serializable>() {
+
+                private static final long serialVersionUID = -3722207913631435501L;
+
+                @Override
+                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
+                    if (anyTO instanceof UserTO) {
+                        StatusModal.this.passwordManagement(
+                                target, ResourceAssociationAction.ASSIGN, table.getModelObject());
+                    } else {
+                        try {
+                            final BulkActionResult bulkActionResult = groupRestClient.assign(
+                                    anyTO.getETagValue(),
+                                    anyTO.getKey(),
+                                    new ArrayList<>(table.getModelObject()));
+
+                            ((BasePage) pageRef.getPage()).setModalResult(true);
+                            loadBulkActionResultPage(target, table.getModelObject(), bulkActionResult);
+                        } catch (Exception e) {
+                            LOG.error("Error assigning resources", e);
+                            error(getString(Constants.ERROR) + ": " + e.getMessage());
+                            modal.getFeedbackPanel().refresh(target);
+                        }
+                    }
+                }
+            }.feedbackPanelAutomaticReload(!(anyTO instanceof UserTO)), ActionLink.ActionType.ASSIGN, pageId);
+        }
+
+        table.addCancelButton(modal);
+        add(table);
+    }
+
+    private class AttributableStatusProvider extends AbstractStatusBeanProvider {
+
+        private static final long serialVersionUID = 4586969457669796621L;
+
+        AttributableStatusProvider() {
+            super(statusOnly ? "resourceName" : "connObjectLink");
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public List<StatusBean> getStatusBeans() {
+            final List<String> resources = new ArrayList<>();
+            for (ResourceTO resourceTO : resourceRestClient.getAll()) {
+                resources.add(resourceTO.getKey());
+            }
+
+            final List<ConnObjectWrapper> connObjects = statusUtils.getConnectorObjects(anyTO);
+
+            final List<StatusBean> statusBeans = new ArrayList<>(connObjects.size() + 1);
+
+            for (ConnObjectWrapper entry : connObjects) {
+                final StatusBean statusBean = statusUtils.getStatusBean(anyTO,
+                        entry.getResourceName(),
+                        entry.getConnObjectTO(),
+                        anyTO instanceof GroupTO);
+
+                statusBeans.add(statusBean);
+                resources.remove(entry.getResourceName());
+            }
+
+            if (statusOnly) {
+                final StatusBean syncope = new StatusBean(anyTO, "Syncope");
+
+                syncope.setConnObjectLink(((UserTO) anyTO).getUsername());
+
+                Status syncopeStatus = Status.UNDEFINED;
+                if (((UserTO) anyTO).getStatus() != null) {
+                    try {
+                        syncopeStatus = Status.valueOf(((UserTO) anyTO).getStatus().toUpperCase());
+                    } catch (IllegalArgumentException e) {
+                        LOG.warn("Unexpected status found: {}", ((UserTO) anyTO).getStatus(), e);
+                    }
+                }
+                syncope.setStatus(syncopeStatus);
+
+                statusBeans.add(syncope);
+            } else {
+                for (String resource : resources) {
+                    final StatusBean statusBean = statusUtils.getStatusBean(anyTO,
+                            resource,
+                            null,
+                            anyTO instanceof GroupTO);
+
+                    statusBean.setLinked(false);
+                    statusBeans.add(statusBean);
+                }
+            }
+
+            return statusBeans;
+        }
+    }
+
+    private void passwordManagement(
+            final AjaxRequestTarget target,
+            final ResourceAssociationAction type,
+            final Collection<StatusBean> selection) {
+
+        final ClearIndicatingAjaxButton goon = new ClearIndicatingAjaxButton("continue", new ResourceModel("continue",
+                "Continue"), pageRef) {
+
+                    private static final long serialVersionUID = -2341391430136818027L;
+
+                    @Override
+                    protected void onSubmitInternal(final AjaxRequestTarget target, final Form<?> form) {
+                        try {
+                            if (StringUtils.isNotBlank(password.getModelObject())
+                            && !password.getModelObject().equals(confirm.getModelObject())) {
+                                throw new Exception(getString("passwordMismatch"));
+                            }
+
+                            final BulkActionResult bulkActionResult;
+                            switch (type) {
+//                                case ASSIGN:
+//                                    bulkActionResult = userRestClient.assign(
+//                                            anyTO.getETagValue(),
+//                                            anyTO.getKey(),
+//                                            new ArrayList<>(selection),
+//                                            changepwd.getModelObject(),
+//                                            password.getModelObject());
+//                                    break;
+//                                case PROVISION:
+//                                    bulkActionResult = userRestClient.provision(
+//                                            anyTO.getETagValue(),
+//                                            anyTO.getKey(),
+//                                            new ArrayList<>(selection),
+//                                            changepwd.getModelObject(),
+//                                            password.getModelObject());
+//                                    break;
+                                default:
+                                    bulkActionResult = null;
+                                // ignore
+                            }
+
+                            ((BasePage) pageRef.getPage()).setModalResult(true);
+
+                            if (bulkActionResult != null) {
+                                loadBulkActionResultPage(target, selection, bulkActionResult);
+                            } else {
+
+                                target.add(((BasePage) pageRef.getPage()).getFeedbackPanel());
+                                modal.close(target);
+                            }
+                        } catch (Exception e) {
+                            LOG.error("Error provisioning resources", e);
+                            error(getString(Constants.ERROR) + ": " + e.getMessage());
+                            modal.getFeedbackPanel().refresh(target);
+                        }
+                    }
+                }.feedbackPanelAutomaticReload(false);
+
+        pwdMgtForm.addOrReplace(goon);
+
+        table.setVisible(false);
+        pwdMgtForm.setVisible(true).setEnabled(true);
+
+        target.add(table);
+        target.add(pwdMgt);
+    }
+
+    private void loadBulkActionResultPage(
+            final AjaxRequestTarget target,
+            final Collection<StatusBean> selection,
+            final BulkActionResult bulkActionResult) {
+        final List<String> resources = new ArrayList<>(selection.size());
+        for (StatusBean statusBean : selection) {
+            resources.add(statusBean.getResourceName());
+        }
+
+        final List<ConnObjectWrapper> connObjects = statusUtils.getConnectorObjects(Collections.singletonList(anyTO),
+                resources);
+
+        final List<StatusBean> statusBeans = new ArrayList<>(connObjects.size());
+
+        for (ConnObjectWrapper entry : connObjects) {
+            final StatusBean statusBean = statusUtils.getStatusBean(anyTO,
+                    entry.getResourceName(),
+                    entry.getConnObjectTO(),
+                    anyTO instanceof GroupTO);
+
+            statusBeans.add(statusBean);
+        }
+
+        target.add(modal.setContent(new BulkActionResultModalPage<>(
+                modal,
+                pageRef,
+                statusBeans,
+                columns,
+                bulkActionResult,
+                "resourceName")));
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/e034afcd/client/console/src/main/java/org/apache/syncope/client/console/pages/StatusModalPage.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/StatusModalPage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/StatusModalPage.java
deleted file mode 100644
index 4f5e27a..0000000
--- a/client/console/src/main/java/org/apache/syncope/client/console/pages/StatusModalPage.java
+++ /dev/null
@@ -1,648 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.client.console.pages;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.console.commons.Constants;
-import org.apache.syncope.client.console.commons.status.AbstractStatusBeanProvider;
-import org.apache.syncope.client.console.commons.status.ConnObjectWrapper;
-import org.apache.syncope.client.console.commons.status.Status;
-import org.apache.syncope.client.console.commons.status.StatusBean;
-import org.apache.syncope.client.console.commons.status.StatusUtils;
-import org.apache.syncope.client.console.panels.ActionDataTablePanel;
-import org.apache.syncope.client.console.rest.GroupRestClient;
-import org.apache.syncope.client.console.rest.ResourceRestClient;
-import org.apache.syncope.client.console.rest.UserRestClient;
-import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxButton;
-import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
-import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
-import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
-import org.apache.syncope.common.lib.to.AnyTO;
-import org.apache.syncope.common.lib.to.BulkActionResult;
-import org.apache.syncope.common.lib.to.ResourceTO;
-import org.apache.syncope.common.lib.to.GroupTO;
-import org.apache.syncope.common.lib.to.UserTO;
-import org.apache.syncope.common.lib.types.ResourceAssociationAction;
-import org.apache.wicket.PageReference;
-import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
-import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
-import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
-import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
-import org.apache.wicket.extensions.markup.html.repeater.data.table.ISortableDataProvider;
-import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
-import org.apache.wicket.markup.ComponentTag;
-import org.apache.wicket.markup.html.WebMarkupContainer;
-import org.apache.wicket.markup.html.basic.Label;
-import org.apache.wicket.markup.html.form.Form;
-import org.apache.wicket.markup.html.form.PasswordTextField;
-import org.apache.wicket.markup.html.panel.Fragment;
-import org.apache.wicket.markup.repeater.Item;
-import org.apache.wicket.model.IModel;
-import org.apache.wicket.model.Model;
-import org.apache.wicket.model.ResourceModel;
-import org.apache.wicket.model.StringResourceModel;
-
-public class StatusModalPage<T extends AnyTO> extends AbstractStatusModalPage {
-
-    private static final long serialVersionUID = -9148734710505211261L;
-
-    private final UserRestClient userRestClient = new UserRestClient();
-
-    private final GroupRestClient groupRestClient = new GroupRestClient();
-
-    private final ResourceRestClient resourceRestClient = new ResourceRestClient();
-
-    private final AnyTO anyTO;
-
-    private int rowsPerPage = 10;
-
-    private final StatusUtils statusUtils;
-
-    private final boolean statusOnly;
-
-    // --------------------------------
-    // password management fields ..
-    // --------------------------------
-    private final ClearIndicatingAjaxButton cancel;
-
-    private final WebMarkupContainer pwdMgt;
-
-    private final Form<?> pwdMgtForm;
-
-    private final AjaxCheckBoxPanel changepwd;
-
-    private final PasswordTextField password;
-
-    private final PasswordTextField confirm;
-    // --------------------------------
-
-    private final ActionDataTablePanel<StatusBean, String> table;
-
-    private final List<IColumn<StatusBean, String>> columns;
-
-    public StatusModalPage(
-            final BaseModal<T> modal,
-            final PageReference pageRef,
-            final AnyTO attributableTO) {
-
-        this(modal, pageRef, attributableTO, false);
-    }
-
-    public StatusModalPage(
-            final BaseModal<T> modal,
-            final PageReference pageRef,
-            final AnyTO anyTO,
-            final boolean statusOnly) {
-
-        super(modal, pageRef);
-
-        this.statusOnly = statusOnly;
-        this.anyTO = anyTO;
-
-        statusUtils = new StatusUtils(anyTO instanceof UserTO ? userRestClient : groupRestClient);
-
-        add(new Label("displayName", anyTO.getKey() + " "
-                + (anyTO instanceof UserTO ? ((UserTO) anyTO).getUsername() : ((GroupTO) anyTO).getName())));
-
-        columns = new ArrayList<>();
-        columns.add(new AbstractColumn<StatusBean, String>(
-                new StringResourceModel("resourceName", this, null), "resourceName") {
-
-                    private static final long serialVersionUID = 2054811145491901166L;
-
-                    @Override
-                    public void populateItem(
-                            final Item<ICellPopulator<StatusBean>> cellItem,
-                            final String componentId,
-                            final IModel<StatusBean> model) {
-
-                                cellItem.add(new Label(componentId, model.getObject().getResourceName()) {
-
-                                    private static final long serialVersionUID = 8432079838783825801L;
-
-                                    @Override
-                                    protected void onComponentTag(final ComponentTag tag) {
-                                        if (model.getObject().isLinked()) {
-                                            super.onComponentTag(tag);
-                                        } else {
-                                            tag.put("style", "color: #DDDDDD");
-                                        }
-                                    }
-                                });
-                            }
-                });
-
-        columns.add(new PropertyColumn<StatusBean, String>(
-                new StringResourceModel("connObjectLink", this, null), "connObjectLink", "connObjectLink"));
-
-        columns.add(new AbstractColumn<StatusBean, String>(
-                new StringResourceModel("status", this, null)) {
-
-                    private static final long serialVersionUID = -3503023501954863131L;
-
-                    @Override
-                    public String getCssClass() {
-                        return "action";
-                    }
-
-                    @Override
-                    public void populateItem(
-                            final Item<ICellPopulator<StatusBean>> cellItem,
-                            final String componentId,
-                            final IModel<StatusBean> model) {
-
-                                if (model.getObject().isLinked()) {
-                                    cellItem.add(statusUtils.getStatusImagePanel(componentId, model.getObject().
-                                                    getStatus()));
-                                } else {
-                                    cellItem.add(new Label(componentId, ""));
-                                }
-                            }
-                });
-
-        table = new ActionDataTablePanel<StatusBean, String>(
-                "resourceDatatable",
-                columns,
-                (ISortableDataProvider<StatusBean, String>) new AttributableStatusProvider(),
-                rowsPerPage,
-                pageRef) {
-
-                    private static final long serialVersionUID = 6510391461033818316L;
-
-                    @Override
-                    public boolean isElementEnabled(final StatusBean element) {
-                        return !statusOnly || element.getStatus() != Status.OBJECT_NOT_FOUND;
-                    }
-                };
-        table.setOutputMarkupId(true);
-
-        final String pageId = anyTO instanceof GroupTO ? "Groups" : "Users";
-
-        final Fragment pwdMgtFragment = new Fragment("pwdMgtFields", "pwdMgtFragment", this);
-        addOrReplace(pwdMgtFragment);
-
-        pwdMgt = new WebMarkupContainer("pwdMgt");
-        pwdMgtFragment.add(pwdMgt.setOutputMarkupId(true));
-
-        pwdMgtForm = new Form("pwdMgtForm");
-        pwdMgtForm.setVisible(false).setEnabled(false);
-        pwdMgt.add(pwdMgtForm);
-
-        password = new PasswordTextField("password", new Model<String>());
-        pwdMgtForm.add(password.setRequired(false).setEnabled(false));
-
-        confirm = new PasswordTextField("confirm", new Model<String>());
-        pwdMgtForm.add(confirm.setRequired(false).setEnabled(false));
-
-        changepwd = new AjaxCheckBoxPanel("changepwd", "changepwd", new Model<>(false));
-        pwdMgtForm.add(changepwd.setModelObject(false));
-        pwdMgtForm.add(new Label("changePwdLabel", new ResourceModel("changePwdLabel", "Password propagation")));
-
-        changepwd.getField().add(new AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
-
-            private static final long serialVersionUID = -1107858522700306810L;
-
-            @Override
-            protected void onUpdate(final AjaxRequestTarget target) {
-                password.setEnabled(changepwd.getModelObject());
-                confirm.setEnabled(changepwd.getModelObject());
-                target.add(pwdMgt);
-            }
-        });
-
-        cancel = new ClearIndicatingAjaxButton("cancel", new ResourceModel("cancel"), pageRef) {
-
-            private static final long serialVersionUID = -2341391430136818026L;
-
-            @Override
-            protected void onSubmitInternal(final AjaxRequestTarget target, final Form<?> form) {
-                // ignore
-                modal.close(target);
-            }
-        }.feedbackPanelAutomaticReload(false);
-
-        pwdMgtForm.add(cancel);
-
-        final ClearIndicatingAjaxButton goon = new ClearIndicatingAjaxButton("continue", new ResourceModel("continue"),
-                pageRef) {
-
-                    private static final long serialVersionUID = -2341391430136818027L;
-
-                    @Override
-                    protected void onSubmitInternal(final AjaxRequestTarget target, final Form<?> form) {
-                        // none
-                    }
-                };
-
-        pwdMgtForm.add(goon);
-
-        if (statusOnly) {
-            table.addAction(new ActionLink<Serializable>() {
-
-                private static final long serialVersionUID = -3722207913631435501L;
-
-                @Override
-                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
-                    try {
-                        userRestClient.reactivate(
-                                anyTO.getETagValue(),
-                                anyTO.getKey(),
-                                new ArrayList<>(table.getModelObject()));
-
-                        ((BasePage) pageRef.getPage()).setModalResult(true);
-
-                        modal.close(target);
-                    } catch (Exception e) {
-                        LOG.error("Error enabling resources", e);
-                        error(getString(Constants.ERROR) + ": " + e.getMessage());
-                        modal.getFeedbackPanel().refresh(target);
-                    }
-                }
-            }, ActionLink.ActionType.REACTIVATE, pageId);
-
-            table.addAction(new ActionLink<Serializable>() {
-
-                private static final long serialVersionUID = -3722207913631435501L;
-
-                @Override
-                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
-                    try {
-                        userRestClient.suspend(
-                                anyTO.getETagValue(),
-                                anyTO.getKey(),
-                                new ArrayList<>(table.getModelObject()));
-
-                        if (pageRef.getPage() instanceof BasePage) {
-                            ((BasePage) pageRef.getPage()).setModalResult(true);
-                        }
-
-                        modal.close(target);
-                    } catch (Exception e) {
-                        LOG.error("Error disabling resources", e);
-                        error(getString(Constants.ERROR) + ": " + e.getMessage());
-                        modal.getFeedbackPanel().refresh(target);
-                    }
-                }
-            }, ActionLink.ActionType.SUSPEND, pageId);
-        } else {
-            table.addAction(new ActionLink<Serializable>() {
-
-                private static final long serialVersionUID = -3722207913631435501L;
-
-                @Override
-                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
-                    try {
-                        if (anyTO instanceof UserTO) {
-                            userRestClient.unlink(
-                                    anyTO.getETagValue(),
-                                    anyTO.getKey(),
-                                    new ArrayList<>(table.getModelObject()));
-                        } else {
-                            groupRestClient.unlink(
-                                    anyTO.getETagValue(),
-                                    anyTO.getKey(),
-                                    new ArrayList<>(table.getModelObject()));
-                        }
-
-                        ((BasePage) pageRef.getPage()).setModalResult(true);
-                        modal.close(target);
-                    } catch (Exception e) {
-                        LOG.error("Error unlinking resources", e);
-                        error(getString(Constants.ERROR) + ": " + e.getMessage());
-                        modal.getFeedbackPanel().refresh(target);
-                    }
-                }
-            }, ActionLink.ActionType.UNLINK, pageId);
-
-            table.addAction(new ActionLink<Serializable>() {
-
-                private static final long serialVersionUID = -3722207913631435501L;
-
-                @Override
-                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
-                    try {
-                        if (anyTO instanceof UserTO) {
-                            userRestClient.link(
-                                    anyTO.getETagValue(),
-                                    anyTO.getKey(),
-                                    new ArrayList<>(table.getModelObject()));
-                        } else {
-                            groupRestClient.link(
-                                    anyTO.getETagValue(),
-                                    anyTO.getKey(),
-                                    new ArrayList<>(table.getModelObject()));
-                        }
-
-                        ((BasePage) pageRef.getPage()).setModalResult(true);
-                        modal.close(target);
-                    } catch (Exception e) {
-                        LOG.error("Error linking resources", e);
-                        error(getString(Constants.ERROR) + ": " + e.getMessage());
-                        modal.getFeedbackPanel().refresh(target);
-                    }
-                }
-            }, ActionLink.ActionType.LINK, pageId);
-
-            table.addAction(new ActionLink<Serializable>() {
-
-                private static final long serialVersionUID = -3722207913631435501L;
-
-                @Override
-                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
-                    try {
-                        BulkActionResult bulkActionResult;
-                        if (anyTO instanceof UserTO) {
-                            bulkActionResult = userRestClient.deprovision(
-                                    anyTO.getETagValue(),
-                                    anyTO.getKey(),
-                                    new ArrayList<>(table.getModelObject()));
-                        } else {
-                            bulkActionResult = groupRestClient.deprovision(
-                                    anyTO.getETagValue(),
-                                    anyTO.getKey(),
-                                    new ArrayList<>(table.getModelObject()));
-                        }
-
-                        ((BasePage) pageRef.getPage()).setModalResult(true);
-                        loadBulkActionResultPage(target, table.getModelObject(), bulkActionResult);
-                    } catch (Exception e) {
-                        LOG.error("Error de-provisioning user", e);
-                        error(getString(Constants.ERROR) + ": " + e.getMessage());
-                        modal.getFeedbackPanel().refresh(target);
-                    }
-                }
-            }, ActionLink.ActionType.DEPROVISION, pageId);
-
-            table.addAction(new ActionLink<Serializable>() {
-
-                private static final long serialVersionUID = -3722207913631435501L;
-
-                @Override
-                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
-
-                    if (anyTO instanceof UserTO) {
-                        StatusModalPage.this.passwordManagement(
-                                target, ResourceAssociationAction.PROVISION, table.getModelObject());
-                    } else {
-                        try {
-                            final BulkActionResult bulkActionResult = groupRestClient.provision(
-                                    anyTO.getETagValue(),
-                                    anyTO.getKey(),
-                                    new ArrayList<>(table.getModelObject()));
-
-                            ((BasePage) pageRef.getPage()).setModalResult(true);
-                            loadBulkActionResultPage(target, table.getModelObject(), bulkActionResult);
-                        } catch (Exception e) {
-                            LOG.error("Error provisioning user", e);
-                            error(getString(Constants.ERROR) + ": " + e.getMessage());
-                            modal.getFeedbackPanel().refresh(target);
-                        }
-                    }
-                }
-            }.feedbackPanelAutomaticReload(!(anyTO instanceof UserTO)), ActionLink.ActionType.PROVISION, pageId);
-
-            table.addAction(new ActionLink<Serializable>() {
-
-                private static final long serialVersionUID = -3722207913631435501L;
-
-                @Override
-                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
-                    try {
-                        final BulkActionResult bulkActionResult;
-                        if (anyTO instanceof UserTO) {
-                            bulkActionResult = userRestClient.unassign(
-                                    anyTO.getETagValue(),
-                                    anyTO.getKey(),
-                                    new ArrayList<>(table.getModelObject()));
-                        } else {
-                            bulkActionResult = groupRestClient.unassign(
-                                    anyTO.getETagValue(),
-                                    anyTO.getKey(),
-                                    new ArrayList<>(table.getModelObject()));
-                        }
-
-                        ((BasePage) pageRef.getPage()).setModalResult(true);
-                        loadBulkActionResultPage(target, table.getModelObject(), bulkActionResult);
-                    } catch (Exception e) {
-                        LOG.error("Error unassigning resources", e);
-                        error(getString(Constants.ERROR) + ": " + e.getMessage());
-                        modal.getFeedbackPanel().refresh(target);
-                    }
-                }
-            }, ActionLink.ActionType.UNASSIGN, pageId);
-
-            table.addAction(new ActionLink<Serializable>() {
-
-                private static final long serialVersionUID = -3722207913631435501L;
-
-                @Override
-                public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
-                    if (anyTO instanceof UserTO) {
-                        StatusModalPage.this.passwordManagement(
-                                target, ResourceAssociationAction.ASSIGN, table.getModelObject());
-                    } else {
-                        try {
-                            final BulkActionResult bulkActionResult = groupRestClient.assign(
-                                    anyTO.getETagValue(),
-                                    anyTO.getKey(),
-                                    new ArrayList<>(table.getModelObject()));
-
-                            ((BasePage) pageRef.getPage()).setModalResult(true);
-                            loadBulkActionResultPage(target, table.getModelObject(), bulkActionResult);
-                        } catch (Exception e) {
-                            LOG.error("Error assigning resources", e);
-                            error(getString(Constants.ERROR) + ": " + e.getMessage());
-                            modal.getFeedbackPanel().refresh(target);
-                        }
-                    }
-                }
-            }.feedbackPanelAutomaticReload(!(anyTO instanceof UserTO)), ActionLink.ActionType.ASSIGN, pageId);
-        }
-
-        table.addCancelButton(modal);
-        add(table);
-    }
-
-    private class AttributableStatusProvider extends AbstractStatusBeanProvider {
-
-        private static final long serialVersionUID = 4586969457669796621L;
-
-        AttributableStatusProvider() {
-            super(statusOnly ? "resourceName" : "connObjectLink");
-        }
-
-        @SuppressWarnings("unchecked")
-        @Override
-        public List<StatusBean> getStatusBeans() {
-            final List<String> resources = new ArrayList<>();
-            for (ResourceTO resourceTO : resourceRestClient.getAll()) {
-                resources.add(resourceTO.getKey());
-            }
-
-            final List<ConnObjectWrapper> connObjects = statusUtils.getConnectorObjects(anyTO);
-
-            final List<StatusBean> statusBeans = new ArrayList<>(connObjects.size() + 1);
-
-            for (ConnObjectWrapper entry : connObjects) {
-                final StatusBean statusBean = statusUtils.getStatusBean(anyTO,
-                        entry.getResourceName(),
-                        entry.getConnObjectTO(),
-                        anyTO instanceof GroupTO);
-
-                statusBeans.add(statusBean);
-                resources.remove(entry.getResourceName());
-            }
-
-            if (statusOnly) {
-                final StatusBean syncope = new StatusBean(anyTO, "Syncope");
-
-                syncope.setConnObjectLink(((UserTO) anyTO).getUsername());
-
-                Status syncopeStatus = Status.UNDEFINED;
-                if (((UserTO) anyTO).getStatus() != null) {
-                    try {
-                        syncopeStatus = Status.valueOf(((UserTO) anyTO).getStatus().toUpperCase());
-                    } catch (IllegalArgumentException e) {
-                        LOG.warn("Unexpected status found: {}", ((UserTO) anyTO).getStatus(), e);
-                    }
-                }
-                syncope.setStatus(syncopeStatus);
-
-                statusBeans.add(syncope);
-            } else {
-                for (String resource : resources) {
-                    final StatusBean statusBean = statusUtils.getStatusBean(anyTO,
-                            resource,
-                            null,
-                            anyTO instanceof GroupTO);
-
-                    statusBean.setLinked(false);
-                    statusBeans.add(statusBean);
-                }
-            }
-
-            return statusBeans;
-        }
-    }
-
-    private void passwordManagement(
-            final AjaxRequestTarget target,
-            final ResourceAssociationAction type,
-            final Collection<StatusBean> selection) {
-
-        final ClearIndicatingAjaxButton goon = new ClearIndicatingAjaxButton("continue", new ResourceModel("continue",
-                "Continue"), pageRef) {
-
-                    private static final long serialVersionUID = -2341391430136818027L;
-
-                    @Override
-                    protected void onSubmitInternal(final AjaxRequestTarget target, final Form<?> form) {
-                        try {
-                            if (StringUtils.isNotBlank(password.getModelObject())
-                            && !password.getModelObject().equals(confirm.getModelObject())) {
-                                throw new Exception(getString("passwordMismatch"));
-                            }
-
-                            final BulkActionResult bulkActionResult;
-                            switch (type) {
-//                                case ASSIGN:
-//                                    bulkActionResult = userRestClient.assign(
-//                                            anyTO.getETagValue(),
-//                                            anyTO.getKey(),
-//                                            new ArrayList<>(selection),
-//                                            changepwd.getModelObject(),
-//                                            password.getModelObject());
-//                                    break;
-//                                case PROVISION:
-//                                    bulkActionResult = userRestClient.provision(
-//                                            anyTO.getETagValue(),
-//                                            anyTO.getKey(),
-//                                            new ArrayList<>(selection),
-//                                            changepwd.getModelObject(),
-//                                            password.getModelObject());
-//                                    break;
-                                default:
-                                    bulkActionResult = null;
-                                // ignore
-                            }
-
-                            ((BasePage) pageRef.getPage()).setModalResult(true);
-
-                            if (bulkActionResult != null) {
-                                loadBulkActionResultPage(target, selection, bulkActionResult);
-                            } else {
-
-                                target.add(((BasePage) pageRef.getPage()).getFeedbackPanel());
-                                modal.close(target);
-                            }
-                        } catch (Exception e) {
-                            LOG.error("Error provisioning resources", e);
-                            error(getString(Constants.ERROR) + ": " + e.getMessage());
-                            modal.getFeedbackPanel().refresh(target);
-                        }
-                    }
-                }.feedbackPanelAutomaticReload(false);
-
-        pwdMgtForm.addOrReplace(goon);
-
-        table.setVisible(false);
-        pwdMgtForm.setVisible(true).setEnabled(true);
-
-        target.add(table);
-        target.add(pwdMgt);
-    }
-
-    private void loadBulkActionResultPage(
-            final AjaxRequestTarget target,
-            final Collection<StatusBean> selection,
-            final BulkActionResult bulkActionResult) {
-        final List<String> resources = new ArrayList<>(selection.size());
-        for (StatusBean statusBean : selection) {
-            resources.add(statusBean.getResourceName());
-        }
-
-        final List<ConnObjectWrapper> connObjects = statusUtils.getConnectorObjects(Collections.singletonList(anyTO),
-                resources);
-
-        final List<StatusBean> statusBeans = new ArrayList<>(connObjects.size());
-
-        for (ConnObjectWrapper entry : connObjects) {
-            final StatusBean statusBean = statusUtils.getStatusBean(anyTO,
-                    entry.getResourceName(),
-                    entry.getConnObjectTO(),
-                    anyTO instanceof GroupTO);
-
-            statusBeans.add(statusBean);
-        }
-
-        target.add(modal.setContent(new BulkActionResultModalPage<>(
-                modal,
-                pageRef,
-                statusBeans,
-                columns,
-                bulkActionResult,
-                "resourceName")));
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/e034afcd/client/console/src/main/java/org/apache/syncope/client/console/panels/AnySearchResultPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnySearchResultPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnySearchResultPanel.java
index d68a9c4..7a19e6c 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnySearchResultPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnySearchResultPanel.java
@@ -142,8 +142,8 @@ public class AnySearchResultPanel<T extends AnyTO> extends AbstractSearchResultP
 
                     @Override
                     public void onClick(final AjaxRequestTarget target, final AnyTO anyTO) {
-                        send(AnySearchResultPanel.this, Broadcast.BREADTH,
-                                new AjaxWizard.NewItemActionEvent<>(model.getObject(), target));
+                        send(AnySearchResultPanel.this, Broadcast.EXACT,
+                                new AjaxWizard.EditItemActionEvent<>(model.getObject(), target));
                     }
                 }, ActionLink.ActionType.EDIT, entitlement).add(new ActionLink<T>() {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/e034afcd/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java
index e803113..186e766 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java
@@ -55,8 +55,6 @@ public final class GroupSearchResultPanel extends AnySearchResultPanel<GroupTO>
 
     private static final long serialVersionUID = -1100228004207271270L;
 
-    private final String entitlement = "GROUP_READ";
-
     private GroupSearchResultPanel(
             final String type,
             final String parentId,
@@ -123,8 +121,8 @@ public final class GroupSearchResultPanel extends AnySearchResultPanel<GroupTO>
 
                     @Override
                     public void onClick(final AjaxRequestTarget target, final GroupTO anyTO) {
-                        send(GroupSearchResultPanel.this, Broadcast.BREADTH,
-                                new AjaxWizard.NewItemActionEvent<AnyTO>(model.getObject(), target));
+                        send(GroupSearchResultPanel.this, Broadcast.EXACT,
+                                new AjaxWizard.EditItemActionEvent<AnyTO>(model.getObject(), target));
                     }
                 }, ActionLink.ActionType.EDIT, entitlement).add(new ActionLink<GroupTO>() {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/e034afcd/client/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java
index 229bcca..be47039 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ListViewPanel.java
@@ -18,30 +18,38 @@
  */
 package org.apache.syncope.client.console.panels;
 
-import java.beans.IntrospectionException;
-import java.beans.PropertyDescriptor;
 import java.io.Serializable;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
 import org.apache.syncope.client.console.wizards.AjaxWizard;
 import org.apache.syncope.client.console.wizards.WizardMgtPanel;
+import org.apache.wicket.Component;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior;
+import org.apache.wicket.core.util.lang.PropertyResolver;
 import org.apache.wicket.event.IEvent;
 import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.Check;
+import org.apache.wicket.markup.html.form.CheckGroup;
+import org.apache.wicket.markup.html.form.CheckGroupSelector;
 import org.apache.wicket.markup.html.list.ListItem;
 import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
 import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.request.cycle.RequestCycle;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public final class ListViewPanel<T extends Serializable> extends WizardMgtPanel<T> {
+public abstract class ListViewPanel<T extends Serializable> extends WizardMgtPanel<T> {
 
     private static final long serialVersionUID = -7982691107029848579L;
 
@@ -50,6 +58,27 @@ public final class ListViewPanel<T extends Serializable> extends WizardMgtPanel<
      */
     private static final Logger LOG = LoggerFactory.getLogger(ListViewPanel.class);
 
+    public enum CheckAvailability {
+
+        /**
+         * No checks.
+         */
+        NONE,
+        /**
+         * Enabled checks including check group selector.
+         */
+        AVAILABLE,
+        /**
+         * Disabled checks.
+         */
+        DISABLED
+
+    }
+
+    private final CheckGroupSelector groupSelector;
+
+    private final Model<CheckAvailability> check;
+
     private final List<T> listOfItems;
 
     /**
@@ -67,12 +96,35 @@ public final class ListViewPanel<T extends Serializable> extends WizardMgtPanel<
             final Class<T> reference,
             final List<String> includes,
             final ActionLinksPanel.Builder<T> actions,
+            final CheckAvailability check,
+            final boolean reuseItem,
+            final IModel<? extends Collection<T>> model,
             final PageReference pageRef) {
         super(id, pageRef);
         setOutputMarkupId(true);
 
+        this.check = Model.of(check);
+
         add(new Label("caption", new ResourceModel("listview.caption", StringUtils.EMPTY)));
 
+        final CheckGroup<T> checkGroup = new CheckGroup<>("group", model);
+        checkGroup.setOutputMarkupId(true);
+        checkGroup.add(new AjaxFormChoiceComponentUpdatingBehavior() {
+
+            private static final long serialVersionUID = -151291731388673682L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                // ignore
+            }
+        });
+        add(checkGroup);
+
+        groupSelector = new CheckGroupSelector("groupselector", checkGroup);
+        add(groupSelector.setOutputMarkupId(true)
+                .setOutputMarkupPlaceholderTag(true)
+                .setVisible(this.check.getObject() == CheckAvailability.AVAILABLE));
+
         final List<String> toBeIncluded;
         if (includes == null || includes.isEmpty()) {
             toBeIncluded = new ArrayList<String>();
@@ -98,16 +150,7 @@ public final class ListViewPanel<T extends Serializable> extends WizardMgtPanel<
             }
         }
 
-        final ListView<String> names = new ListView<String>("names", toBeIncluded) {
-
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            protected void populateItem(final ListItem<String> item) {
-                item.add(new Label("name", new ResourceModel(item.getModelObject(), item.getModelObject())));
-            }
-        };
-        add(names);
+        add(header(toBeIncluded));
 
         final ListView<T> beans = new ListView<T>("beans", listOfItems) {
 
@@ -115,6 +158,12 @@ public final class ListViewPanel<T extends Serializable> extends WizardMgtPanel<
 
             @Override
             protected void populateItem(final ListItem<T> beanItem) {
+                beanItem.add(new Check<T>("check", beanItem.getModel(), checkGroup).setOutputMarkupId(true)
+                        .setOutputMarkupPlaceholderTag(true)
+                        .setVisible(ListViewPanel.this.check.getObject() == CheckAvailability.AVAILABLE
+                                || ListViewPanel.this.check.getObject() == CheckAvailability.DISABLED)
+                        .setEnabled(ListViewPanel.this.check.getObject() == CheckAvailability.AVAILABLE));
+
                 final T bean = beanItem.getModelObject();
 
                 final ListView<String> fields = new ListView<String>("fields", toBeIncluded) {
@@ -123,23 +172,7 @@ public final class ListViewPanel<T extends Serializable> extends WizardMgtPanel<
 
                     @Override
                     protected void populateItem(final ListItem<String> fieldItem) {
-                        try {
-                            LOG.debug("Processing field {}", fieldItem.getModelObject());
-
-                            final Object value = new PropertyDescriptor(fieldItem.getModelObject(), bean.getClass()).
-                                    getReadMethod().invoke(bean);
-
-                            LOG.debug("Field value {}", value);
-
-                            fieldItem.add(value == null
-                                    ? new Label("field", StringUtils.EMPTY)
-                                    : new Label("field", new ResourceModel(value.toString(), value.toString())));
-
-                        } catch (IntrospectionException | IllegalAccessException | IllegalArgumentException 
-                                | InvocationTargetException e) {
-                            LOG.error("Error retrieving value for field {}", fieldItem.getModelObject(), e);
-                            fieldItem.add(new Label("field", StringUtils.EMPTY));
-                        }
+                        fieldItem.add(getValueComponent(fieldItem.getModelObject(), bean));
                     }
                 };
                 beanItem.add(fields);
@@ -147,36 +180,69 @@ public final class ListViewPanel<T extends Serializable> extends WizardMgtPanel<
             }
         };
         beans.setOutputMarkupId(true);
-        beans.setReuseItems(true);
-        add(beans);
+        beans.setReuseItems(reuseItem);
+        beans.setRenderBodyOnly(true);
+        checkGroup.add(beans);
     }
 
-    public static <T extends Serializable> ListViewPanel.Builder<T> builder(
-            final Class<T> reference, final PageReference pageRef) {
-        return new ListViewPanel.Builder<T>(reference, pageRef);
+    private ListView<String> header(final List<String> labels) {
+        return new ListView<String>("names", labels) {
+
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void populateItem(final ListItem<String> item) {
+                item.add(new Label("name", new ResourceModel(item.getModelObject(), item.getModelObject())));
+            }
+        };
+    }
+
+    public void setCheckAvailability(final CheckAvailability check) {
+        // used to perform selectable enabling check condition
+        this.check.setObject(check);
+
+        final AjaxRequestTarget target = RequestCycle.get().find(AjaxRequestTarget.class);
+
+        // reload group selector
+        target.add(groupSelector.setVisible(check == CheckAvailability.AVAILABLE));
+        // reload the list view panel
+        target.add(ListViewPanel.this);
     }
 
+    protected abstract Component getValueComponent(final String key, final T bean);
+
     /**
      * ListViewPanel builder.
      *
      * @param <T> list item reference type.
      */
-    public static final class Builder<T extends Serializable> extends WizardMgtPanel.Builder<T> {
+    public static class Builder<T extends Serializable> extends WizardMgtPanel.Builder<T> {
 
         private static final long serialVersionUID = 1L;
 
+        private IModel<? extends Collection<T>> model = new Model<>();
+
         private final List<String> includes = new ArrayList<>();
 
         private final ActionLinksPanel.Builder<T> actions;
 
         private List<T> items;
 
-        private Builder(final Class<T> reference, final PageReference pageRef) {
+        private CheckAvailability check = CheckAvailability.NONE;
+
+        private boolean reuseItem = true;
+
+        public Builder(final Class<T> reference, final PageReference pageRef) {
             super(reference, pageRef);
             this.items = null;
             this.actions = ActionLinksPanel.<T>builder(pageRef);
         }
 
+        public Builder<T> setModel(final IModel<? extends Collection<T>> model) {
+            this.model = model;
+            return this;
+        }
+
         /**
          * Sets list of items.
          *
@@ -207,6 +273,15 @@ public final class ListViewPanel<T extends Serializable> extends WizardMgtPanel<
             return this;
         }
 
+        public Builder<T> withChecks(final CheckAvailability check) {
+            this.check = check;
+            return this;
+        }
+
+        public void setReuseItem(final boolean reuseItem) {
+            this.reuseItem = reuseItem;
+        }
+
         /**
          * Gives fields to be shown. It could be used to give an order as well.
          *
@@ -236,9 +311,43 @@ public final class ListViewPanel<T extends Serializable> extends WizardMgtPanel<
             return this;
         }
 
+        /**
+         * Overridable method to generate field value rendering component.
+         *
+         * @param key field key.
+         * @param bean source bean.
+         * @return field rendering component.
+         */
+        protected Component getValueComponent(final String key, final T bean) {
+            LOG.debug("Processing field {}", key);
+
+            Object value;
+            try {
+                value = PropertyResolver.getPropertyGetter(key, bean).invoke(bean);
+            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+                LOG.error("Error retrieving value for field {}", key, e);
+                value = StringUtils.EMPTY;
+            }
+
+            LOG.debug("Field value {}", value);
+
+            return value == null
+                    ? new Label("field", StringUtils.EMPTY)
+                    : new Label("field", new ResourceModel(value.toString(), value.toString()));
+        }
+
         @Override
         protected WizardMgtPanel<T> newInstance(final String id) {
-            return new ListViewPanel<T>(id, items, reference, includes, actions, pageRef);
+            return new ListViewPanel<T>(id, items, reference, includes, actions, check, reuseItem, model, pageRef) {
+
+                private static final long serialVersionUID = 1L;
+
+                @Override
+                protected Component getValueComponent(final String key, final T bean) {
+                    return Builder.this.getValueComponent(key, bean);
+                }
+
+            };
         }
     }
 
@@ -249,7 +358,7 @@ public final class ListViewPanel<T extends Serializable> extends WizardMgtPanel<
 
             final T item = ((AjaxWizard.NewItemEvent<T>) event.getPayload()).getItem();
             final AjaxRequestTarget target = ((AjaxWizard.NewItemEvent<T>) event.getPayload()).getTarget();
-
+            
             if (event.getPayload() instanceof AjaxWizard.NewItemFinishEvent) {
                 if (item != null && !this.listOfItems.contains(item)) {
                     this.listOfItems.add(item);

http://git-wip-us.apache.org/repos/asf/syncope/blob/e034afcd/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourceModal.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourceModal.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourceModal.java
index 0c6d38c..401f90f 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourceModal.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ResourceModal.java
@@ -88,7 +88,7 @@ public class ResourceModal extends AbstractResourceModal {
         //--------------------------------
         // Resource provision panels
         //--------------------------------
-        final ListViewPanel.Builder<ProvisionTO> builder = ListViewPanel.builder(ProvisionTO.class, pageRef);
+        final ListViewPanel.Builder<ProvisionTO> builder = new ListViewPanel.Builder<>(ProvisionTO.class, pageRef);
         builder.setItems(model.getObject().getProvisions());
         builder.includes("anyType", "objectClass");