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 2016/01/26 15:57:30 UTC

[2/2] syncope git commit: [SYNCOPE-743] providing propagation tasks management

[SYNCOPE-743] providing propagation tasks management


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

Branch: refs/heads/master
Commit: 17f53ed8bed18c5abb0d6f63a8b801106872504a
Parents: a2e5e74
Author: fmartelli <fa...@gmail.com>
Authored: Tue Jan 26 15:57:11 2016 +0100
Committer: fmartelli <fa...@gmail.com>
Committed: Tue Jan 26 15:57:11 2016 +0100

----------------------------------------------------------------------
 .../client/console/commons/Constants.java       |   2 +
 .../panels/AbstractSearchResultPanel.java       |  37 ++-
 .../console/panels/AbstractTypesPanel.java      |   5 +-
 .../panels/AnyObjectSearchResultPanel.java      |  10 +-
 .../console/panels/AnyTypeClassesPanel.java     |  27 +-
 .../client/console/panels/AnyTypePanel.java     |  31 +-
 .../console/panels/GroupSearchResultPanel.java  |  10 +-
 .../client/console/panels/MultilevelPanel.java  | 126 ++++++++
 .../syncope/client/console/panels/Realm.java    |  12 -
 .../console/panels/RelationshipTypePanel.java   |  28 +-
 .../client/console/panels/SchemaTypePanel.java  |  30 +-
 .../console/panels/SecurityQuestionsPanel.java  |  14 +-
 .../console/panels/UserSearchResultPanel.java   |  18 +-
 .../AnyObjectSelectionSearchResultPanel.java    |  14 +-
 .../search/GroupSelectionSearchResultPanel.java |  11 +-
 .../search/UserSelectionSearchResultPanel.java  |  13 +-
 .../client/console/rest/TaskRestClient.java     |  28 +-
 .../client/console/tasks/ExecMessage.java       |  34 +++
 .../console/tasks/PropagationTaskDetails.java   |  78 +++++
 .../tasks/PropagationTaskSearchResultPanel.java | 287 +++++++++++++++++++
 .../client/console/tasks/PropagationTasks.java  |  69 +++++
 .../client/console/tasks/TaskDetails.java       | 267 +++++++++++++++++
 .../console/topology/TopologyNodePanel.java     |   8 +-
 .../console/topology/TopologyTogglePanel.java   |   4 +-
 .../repeater/data/table/DatePropertyColumn.java |  54 ++++
 .../wizards/AbstractModalPanelBuilder.java      |   8 +-
 .../console/wizards/any/AnyWizardBuilder.java   |   7 +-
 .../client/console/wizards/any/Ownership.java   |  53 ++--
 .../console/wizards/any/Relationships.java      |  24 +-
 .../client/console/wizards/any/StatusPanel.java |  72 ++---
 .../provision/ProvisionWizardBuilder.java       |   7 +-
 .../console/wizards/role/RoleWizardBuilder.java |   5 -
 .../META-INF/resources/css/topology.css         |   8 +-
 .../client/console/panels/MultilevelPanel.html  |  42 +++
 .../client/console/tasks/ExecMessage.html       |  30 ++
 .../tasks/PropagationTaskDetails$Profile.html   |  28 ++
 .../PropagationTaskDetails$Profile.properties   |  18 ++
 .../PropagationTaskSearchResultPanel.properties |  32 +++
 .../client/console/tasks/PropagationTasks.html  |  24 ++
 .../client/console/tasks/TaskDetails.html       |  27 ++
 .../client/console/tasks/TaskDetails.properties |  26 ++
 .../markup/html/form/ActionLinksPanel.html      |   4 +-
 .../any/StatusPanel$RemoteObjectPanel.html      |  24 ++
 .../client/console/wizards/any/StatusPanel.html |  24 +-
 44 files changed, 1348 insertions(+), 332 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java
index 69b0930..3a1e72f 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java
@@ -98,6 +98,8 @@ public final class Constants {
 
     public static final String PREF_PROPAGATION_TASKS_PAGINATOR_ROWS = "proagationtasks.paginator.rows";
 
+    public static final String PREF_TASK_EXECS_PAGINATOR_ROWS = "task.execs.paginator.rows";
+
     public static final String PREF_NOTIFICATION_TASKS_PAGINATOR_ROWS = "notificationtasks.paginator.rows";
 
     public static final String PREF_SCHED_TASKS_PAGINATOR_ROWS = "schedtasks.paginator.rows";

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractSearchResultPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractSearchResultPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractSearchResultPanel.java
index a3291b0..4d80334 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractSearchResultPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractSearchResultPanel.java
@@ -74,7 +74,7 @@ public abstract class AbstractSearchResultPanel<
      */
     protected final boolean filtered;
 
-    private final boolean checkBoxEnabled;
+    private boolean checkBoxEnabled;
 
     /**
      * Result table.
@@ -91,8 +91,35 @@ public abstract class AbstractSearchResultPanel<
      */
     protected final BasePage page;
 
+    /**
+     * Create simple unfiltered search result panel.
+     * Use the available builder for powerfull configuration options.
+     *
+     * @param id panel id.
+     * @param pageRef page reference.
+     */
+    public AbstractSearchResultPanel(final String id, final PageReference pageRef) {
+        this(id, pageRef, true);
+    }
+
+    public AbstractSearchResultPanel(final String id, final PageReference pageRef, final boolean wizardInModal) {
+        this(id, new Builder<T, W, E>(null, pageRef) {
+
+            private static final long serialVersionUID = -8424727765826509309L;
+
+            @Override
+            protected WizardMgtPanel<W> newInstance(final String id) {
+                throw new UnsupportedOperationException("Not supported yet.");
+            }
+        }.setFiltered(false), wizardInModal);
+    }
+
     protected AbstractSearchResultPanel(final String id, final Builder<T, W, E> builder) {
-        super(id, true);
+        this(id, builder, true);
+    }
+
+    protected AbstractSearchResultPanel(final String id, final Builder<T, W, E> builder, final boolean wizardInModal) {
+        super(id, wizardInModal);
 
         setOutputMarkupId(true);
 
@@ -168,6 +195,7 @@ public abstract class AbstractSearchResultPanel<
         final int currentPage = resultTable != null
                 ? (create ? (int) resultTable.getPageCount() - 1 : (int) resultTable.getCurrentPage()) : 0;
 
+        // reworking on bulkactions please, take care of restClient handle: maybe not useful to keep into
         AjaxDataTablePanel.Builder<T, String> resultTableBuilder = new AjaxDataTablePanel.Builder<>(
                 dataProvider, page.getPageReference()).
                 setColumns(getColumns()).
@@ -186,6 +214,11 @@ public abstract class AbstractSearchResultPanel<
         container.addOrReplace(resultTable);
     }
 
+    public AbstractSearchResultPanel<T, W, DP, E> disableCheckBoxes() {
+        this.checkBoxEnabled = false;
+        return this;
+    }
+
     @Override
     public void onEvent(final IEvent<?> event) {
         if (event.getPayload() instanceof EventDataWrapper) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractTypesPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractTypesPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractTypesPanel.java
index fd9f547..9d6ff26 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractTypesPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractTypesPanel.java
@@ -22,14 +22,15 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
 import org.apache.syncope.client.console.commons.SearchableDataProvider;
 import org.apache.syncope.client.console.rest.BaseRestClient;
 import org.apache.syncope.common.lib.AbstractBaseBean;
+import org.apache.wicket.PageReference;
 
 public abstract class AbstractTypesPanel<T extends AbstractBaseBean, DP extends SearchableDataProvider<T>>
         extends AbstractSearchResultPanel<T, T, DP, BaseRestClient> {
 
     private static final long serialVersionUID = 7890071604330629259L;
 
-    public AbstractTypesPanel(final String id, final Builder<T, T, BaseRestClient> builder) {
-        super(id, builder);
+    public AbstractTypesPanel(final String id, final PageReference pageRef) {
+        super(id, pageRef);
         setFooterVisibility(true);
         modal.addSumbitButton();
         modal.size(Modal.Size.Large);

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectSearchResultPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectSearchResultPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectSearchResultPanel.java
index a7e5d31..c47b9c6 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectSearchResultPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyObjectSearchResultPanel.java
@@ -27,7 +27,6 @@ import org.apache.commons.lang3.SerializationUtils;
 import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.pages.AnyDisplayAttributesModalPage;
 import org.apache.syncope.client.console.pages.BasePage;
-import org.apache.syncope.client.console.rest.AbstractAnyRestClient;
 import org.apache.syncope.client.console.rest.AnyObjectRestClient;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.AttrColumn;
@@ -196,13 +195,8 @@ public class AnyObjectSearchResultPanel extends AnySearchResultPanel<AnyObjectTO
 
         private static final long serialVersionUID = -6828423611982275641L;
 
-        public Builder(
-                final List<AnyTypeClassTO> anyTypeClassTOs,
-                final AbstractAnyRestClient<AnyObjectTO> restClient,
-                final String type,
-                final PageReference pageRef) {
-
-            super(anyTypeClassTOs, restClient, type, pageRef);
+        public Builder(final List<AnyTypeClassTO> anyTypeClassTOs, final String type, final PageReference pageRef) {
+            super(anyTypeClassTOs, new AnyObjectRestClient(), type, pageRef);
             setShowResultPage(true);
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypeClassesPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypeClassesPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypeClassesPanel.java
index e4fca73..aec4cce 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypeClassesPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypeClassesPanel.java
@@ -32,13 +32,11 @@ import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.commons.SearchableDataProvider;
 import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
 import org.apache.syncope.client.console.pages.BasePage;
-import org.apache.syncope.client.console.rest.BaseRestClient;
 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.ActionLinksPanel;
 import org.apache.syncope.client.console.wizards.AbstractModalPanelBuilder;
 import org.apache.syncope.client.console.wizards.AjaxWizard;
-import org.apache.syncope.client.console.wizards.WizardMgtPanel;
 import org.apache.syncope.common.lib.to.AnyTypeClassTO;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.syncope.common.rest.api.service.AnyTypeClassService;
@@ -60,21 +58,9 @@ public class AnyTypeClassesPanel extends AbstractTypesPanel<AnyTypeClassTO, AnyT
 
     private static final long serialVersionUID = -2356760296223908382L;
 
-    public AnyTypeClassesPanel(final String id,
-            final AbstractSearchResultPanel.Builder<AnyTypeClassTO, AnyTypeClassTO, BaseRestClient> builder) {
-        super(id, builder);
-    }
-
     public AnyTypeClassesPanel(final String id, final PageReference pageRef) {
-        super(id, new AbstractSearchResultPanel.Builder<AnyTypeClassTO, AnyTypeClassTO, BaseRestClient>(null, pageRef) {
-
-            private static final long serialVersionUID = 8769126634538601689L;
-
-            @Override
-            protected WizardMgtPanel<AnyTypeClassTO> newInstance(final String id) {
-                return new AnyTypeClassesPanel(id, this);
-            }
-        }.disableCheckBoxes());
+        super(id, pageRef);
+        disableCheckBoxes();
 
         this.addNewItemPanelBuilder(new AbstractModalPanelBuilder<AnyTypeClassTO>(
                 BaseModal.CONTENT_ID, new AnyTypeClassTO(), pageRef) {
@@ -106,15 +92,6 @@ public class AnyTypeClassesPanel extends AbstractTypesPanel<AnyTypeClassTO, AnyT
                     }
                 };
             }
-
-            @Override
-            protected void onCancelInternal(final AnyTypeClassTO modelObject) {
-            }
-
-            @Override
-            protected Serializable onApplyInternal(final AnyTypeClassTO modelObject) {
-                return null;
-            }
         }, true);
 
         initResultTable();

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypePanel.java
index b7caf9c..5d1b29f 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypePanel.java
@@ -33,13 +33,11 @@ import org.apache.syncope.client.console.commons.SearchableDataProvider;
 import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
 import org.apache.syncope.client.console.pages.BasePage;
 import org.apache.syncope.client.console.panels.AnyTypePanel.AnyTypeProvider;
-import org.apache.syncope.client.console.rest.BaseRestClient;
 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.ActionLinksPanel;
 import org.apache.syncope.client.console.wizards.AbstractModalPanelBuilder;
 import org.apache.syncope.client.console.wizards.AjaxWizard;
-import org.apache.syncope.client.console.wizards.WizardMgtPanel;
 import org.apache.syncope.common.lib.to.AnyTypeTO;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.syncope.common.rest.api.service.AnyTypeService;
@@ -61,20 +59,9 @@ public class AnyTypePanel extends AbstractTypesPanel<AnyTypeTO, AnyTypeProvider>
 
     private static final long serialVersionUID = 3905038169553185171L;
 
-    public AnyTypePanel(final String id, final Builder<AnyTypeTO, AnyTypeTO, BaseRestClient> builder) {
-        super(id, builder);
-    }
-
     public AnyTypePanel(final String id, final PageReference pageRef) {
-        super(id, new Builder<AnyTypeTO, AnyTypeTO, BaseRestClient>(null, pageRef) {
-
-            private static final long serialVersionUID = 8769126634538601689L;
-
-            @Override
-            protected WizardMgtPanel<AnyTypeTO> newInstance(final String id) {
-                return new AnyTypePanel(id, this);
-            }
-        }.disableCheckBoxes());
+        super(id, pageRef);
+        disableCheckBoxes();
 
         this.addNewItemPanelBuilder(new AbstractModalPanelBuilder<AnyTypeTO>(
                 BaseModal.CONTENT_ID, new AnyTypeTO(), pageRef) {
@@ -106,16 +93,6 @@ public class AnyTypePanel extends AbstractTypesPanel<AnyTypeTO, AnyTypeProvider>
                     }
                 };
             }
-
-            @Override
-            protected void onCancelInternal(final AnyTypeTO modelObject) {
-            }
-
-            @Override
-            protected Serializable onApplyInternal(final AnyTypeTO modelObject) {
-                // do nothing
-                return null;
-            }
         }, true);
 
         initResultTable();
@@ -200,8 +177,8 @@ public class AnyTypePanel extends AbstractTypesPanel<AnyTypeTO, AnyTypeProvider>
             public void populateItem(final Item<ICellPopulator<AnyTypeTO>> item, final String componentId,
                     final IModel<AnyTypeTO> model) {
 
-                final ActionLinksPanel.Builder<Serializable> actionLinks =
-                        ActionLinksPanel.builder(page.getPageReference());
+                final ActionLinksPanel.Builder<Serializable> actionLinks = ActionLinksPanel.builder(page.
+                        getPageReference());
                 actionLinks.setDisableIndicator(true);
                 actionLinks.addWithRoles(new ActionLink<Serializable>() {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/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 b8917b3..2349c12 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
@@ -28,7 +28,6 @@ import org.apache.commons.lang3.SerializationUtils;
 import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.pages.BasePage;
 import org.apache.syncope.client.console.pages.GroupDisplayAttributesModalPage;
-import org.apache.syncope.client.console.rest.AbstractAnyRestClient;
 import org.apache.syncope.client.console.rest.GroupRestClient;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.AttrColumn;
@@ -193,13 +192,8 @@ public class GroupSearchResultPanel extends AnySearchResultPanel<GroupTO> {
 
         private static final long serialVersionUID = 1L;
 
-        public Builder(
-                final List<AnyTypeClassTO> anyTypeClassTOs,
-                final AbstractAnyRestClient<GroupTO> restClient,
-                final String type,
-                final PageReference pageRef) {
-
-            super(anyTypeClassTOs, restClient, type, pageRef);
+        public Builder(final List<AnyTypeClassTO> anyTypeClassTOs, final String type, final PageReference pageRef) {
+            super(anyTypeClassTOs, new GroupRestClient(), type, pageRef);
             setShowResultPage(true);
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/panels/MultilevelPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/MultilevelPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/MultilevelPanel.java
new file mode 100644
index 0000000..da90ab6
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/MultilevelPanel.java
@@ -0,0 +1,126 @@
+/*
+ * 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.panels;
+
+import org.apache.syncope.client.console.commons.status.StatusBean;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.markup.html.IHeaderContributor;
+import org.apache.wicket.markup.html.TransparentWebMarkupContainer;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.ResourceModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MultilevelPanel extends Panel implements IHeaderContributor {
+
+    private static final long serialVersionUID = -4064294905566247729L;
+
+    /**
+     * Logger.
+     */
+    protected static final Logger LOG = LoggerFactory.getLogger(MultilevelPanel.class);
+
+    private boolean isFirstLevel = true;
+
+    public static final String FIRST_LEVEL_ID = "first";
+
+    public static final String SECOND_LEVEL_ID = "second";
+
+    private final WebMarkupContainer firstLevelContainer;
+
+    private final WebMarkupContainer secondLevelContainer;
+
+    public MultilevelPanel(final String id) {
+        super(id);
+
+        firstLevelContainer = new TransparentWebMarkupContainer("firstLevelContainer");
+        firstLevelContainer.setOutputMarkupPlaceholderTag(true);
+        firstLevelContainer.setVisible(true);
+        add(firstLevelContainer);
+
+        secondLevelContainer = new WebMarkupContainer("secondLevelContainer");
+        secondLevelContainer.setOutputMarkupPlaceholderTag(true);
+        secondLevelContainer.setVisible(false);
+        add(secondLevelContainer);
+
+        secondLevelContainer.add(new AjaxLink<StatusBean>("back") {
+
+            private static final long serialVersionUID = -7978723352517770644L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                prev(target);
+            }
+        });
+    }
+
+    public final void next(final String title, final SecondLevel secondLevel, final AjaxRequestTarget target) {
+        if (isFirstLevel) {
+            secondLevelContainer.addOrReplace(new Label("title", new ResourceModel(title, title)));
+            secondLevelContainer.addOrReplace(secondLevel);
+            secondLevelContainer.setVisible(true);
+            target.add(secondLevelContainer);
+
+            firstLevelContainer.setVisible(false);
+            target.add(firstLevelContainer);
+
+            isFirstLevel = false;
+        } else {
+            LOG.warn("No further level available");
+        }
+    }
+
+    private void prev(final AjaxRequestTarget target) {
+        if (isFirstLevel) {
+            LOG.warn("No further level available");
+        } else {
+            firstLevelContainer.setVisible(true);
+            target.add(firstLevelContainer);
+
+            secondLevelContainer.setVisible(false);
+            target.add(secondLevelContainer);
+
+            isFirstLevel = true;
+        }
+    }
+
+    /**
+     * Ad panel with id <tt>first</tt>
+     *
+     * @param panel panel to be used into the first level.
+     * @return the current MultilevelPanel instance.
+     */
+    public MultilevelPanel setFirstLevel(final Panel panel) {
+        firstLevelContainer.add(panel);
+        return this;
+    }
+
+    public static class SecondLevel extends Panel {
+
+        private static final long serialVersionUID = 5685291231060035528L;
+
+        public SecondLevel() {
+            super(SECOND_LEVEL_ID);
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
index 9534d6b..12c6118 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
@@ -23,11 +23,8 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.tabs.AjaxBootstrapTabbed
 import java.util.ArrayList;
 import java.util.List;
 import org.apache.syncope.client.console.pages.BasePage;
-import org.apache.syncope.client.console.rest.AnyObjectRestClient;
 import org.apache.syncope.client.console.rest.AnyTypeClassRestClient;
 import org.apache.syncope.client.console.rest.AnyTypeRestClient;
-import org.apache.syncope.client.console.rest.GroupRestClient;
-import org.apache.syncope.client.console.rest.UserRestClient;
 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.ActionLinksPanel;
@@ -66,12 +63,6 @@ public abstract class Realm extends Panel {
 
     private final AnyTypeClassRestClient anyTypeClassRestClient = new AnyTypeClassRestClient();
 
-    private final UserRestClient userRestClient = new UserRestClient();
-
-    private final GroupRestClient groupRestClient = new GroupRestClient();
-
-    private final AnyObjectRestClient anyObjectRestClient = new AnyObjectRestClient();
-
     private final PageReference pageRef;
 
     @SuppressWarnings({ "unchecked", "unchecked" })
@@ -159,7 +150,6 @@ public abstract class Realm extends Panel {
                 userTO.setRealm(realmTO.getFullPath());
                 panel = new UserSearchResultPanel.Builder(
                         anyTypeClassRestClient.list(anyTypeTO.getClasses()),
-                        userRestClient,
                         anyTypeTO.getKey(),
                         pageReference).setRealm(realmTO.getFullPath()).
                         addNewItemPanelBuilder(new UserWizardBuilder(
@@ -173,7 +163,6 @@ public abstract class Realm extends Panel {
                 groupTO.setRealm(realmTO.getFullPath());
                 panel = new GroupSearchResultPanel.Builder(
                         anyTypeClassRestClient.list(anyTypeTO.getClasses()),
-                        groupRestClient,
                         anyTypeTO.getKey(),
                         pageReference).setRealm(realmTO.getFullPath()).
                         addNewItemPanelBuilder(new GroupWizardBuilder(
@@ -188,7 +177,6 @@ public abstract class Realm extends Panel {
                 anyObjectTO.setType(anyTypeTO.getKey());
                 panel = new AnyObjectSearchResultPanel.Builder(
                         anyTypeClassRestClient.list(anyTypeTO.getClasses()),
-                        anyObjectRestClient,
                         anyTypeTO.getKey(),
                         pageReference).setRealm(realmTO.getFullPath()).
                         addNewItemPanelBuilder(new AnyObjectWizardBuilder(

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipTypePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipTypePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipTypePanel.java
index 64570d6..e90b0cc 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipTypePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipTypePanel.java
@@ -32,13 +32,11 @@ import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.commons.SearchableDataProvider;
 import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
 import org.apache.syncope.client.console.panels.RelationshipTypePanel.RelationshipTypeProvider;
-import org.apache.syncope.client.console.rest.BaseRestClient;
 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.ActionLinksPanel;
 import org.apache.syncope.client.console.wizards.AbstractModalPanelBuilder;
 import org.apache.syncope.client.console.wizards.AjaxWizard;
-import org.apache.syncope.client.console.wizards.WizardMgtPanel;
 import org.apache.syncope.common.lib.to.RelationshipTypeTO;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.syncope.common.rest.api.service.RelationshipTypeService;
@@ -60,21 +58,9 @@ public class RelationshipTypePanel extends AbstractTypesPanel<RelationshipTypeTO
 
     private static final long serialVersionUID = -3731778000138547357L;
 
-    public RelationshipTypePanel(
-            final String id, final Builder<RelationshipTypeTO, RelationshipTypeTO, BaseRestClient> builder) {
-        super(id, builder);
-    }
-
     public RelationshipTypePanel(final String id, final PageReference pageRef) {
-        super(id, new Builder<RelationshipTypeTO, RelationshipTypeTO, BaseRestClient>(null, pageRef) {
-
-            private static final long serialVersionUID = 8769126634538601689L;
-
-            @Override
-            protected WizardMgtPanel<RelationshipTypeTO> newInstance(final String id) {
-                return new RelationshipTypePanel(id, this);
-            }
-        }.disableCheckBoxes());
+        super(id, pageRef);
+        disableCheckBoxes();
 
         this.addNewItemPanelBuilder(new AbstractModalPanelBuilder<RelationshipTypeTO>(
                 BaseModal.CONTENT_ID, new RelationshipTypeTO(), pageRef) {
@@ -109,16 +95,6 @@ public class RelationshipTypePanel extends AbstractTypesPanel<RelationshipTypeTO
                     }
                 };
             }
-
-            @Override
-            protected void onCancelInternal(final RelationshipTypeTO modelObject) {
-            }
-
-            @Override
-            protected Serializable onApplyInternal(final RelationshipTypeTO modelObject) {
-                // do nothing
-                return null;
-            }
         }, true);
 
         initResultTable();

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/panels/SchemaTypePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/SchemaTypePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/SchemaTypePanel.java
index 3585783..12c9d15 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/SchemaTypePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/SchemaTypePanel.java
@@ -35,14 +35,12 @@ import org.apache.syncope.client.console.commons.SearchableDataProvider;
 import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
 import org.apache.syncope.client.console.pages.BasePage;
 import org.apache.syncope.client.console.panels.SchemaTypePanel.SchemaProvider;
-import org.apache.syncope.client.console.rest.BaseRestClient;
 import org.apache.syncope.client.console.rest.SchemaRestClient;
 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.ActionLinksPanel;
 import org.apache.syncope.client.console.wizards.AbstractModalPanelBuilder;
 import org.apache.syncope.client.console.wizards.AjaxWizard;
-import org.apache.syncope.client.console.wizards.WizardMgtPanel;
 import org.apache.syncope.common.lib.to.AbstractSchemaTO;
 import org.apache.syncope.common.lib.types.SchemaType;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
@@ -87,24 +85,9 @@ public class SchemaTypePanel extends AbstractTypesPanel<AbstractSchemaTO, Schema
 
     private final SchemaType schemaType;
 
-    public SchemaTypePanel(final String id, final SchemaType schemaType,
-            final AbstractSearchResultPanel.Builder<AbstractSchemaTO, AbstractSchemaTO, BaseRestClient> builder) {
-        super(id, builder);
-
-        this.schemaType = schemaType;
-    }
-
     public SchemaTypePanel(final String id, final SchemaType schemaType, final PageReference pageRef) {
-        super(id, new AbstractSearchResultPanel.Builder<AbstractSchemaTO, AbstractSchemaTO, BaseRestClient>(null,
-                pageRef) {
-
-            private static final long serialVersionUID = 8769126634538601689L;
-
-            @Override
-            protected WizardMgtPanel<AbstractSchemaTO> newInstance(final String id) {
-                return new SchemaTypePanel(id, schemaType, this).setPageRef(pageRef);
-            }
-        }.disableCheckBoxes());
+        super(id, pageRef);
+        disableCheckBoxes();
 
         this.schemaType = schemaType;
 
@@ -141,15 +124,6 @@ public class SchemaTypePanel extends AbstractTypesPanel<AbstractSchemaTO, Schema
                         }
                     };
                 }
-
-                @Override
-                protected void onCancelInternal(final AbstractSchemaTO modelObject) {
-                }
-
-                @Override
-                protected Serializable onApplyInternal(final AbstractSchemaTO modelObject) {
-                    return null;
-                }
             }, true);
 
             initResultTable();

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/panels/SecurityQuestionsPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/SecurityQuestionsPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/SecurityQuestionsPanel.java
index 4d0bd42..e82ace0 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/SecurityQuestionsPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/SecurityQuestionsPanel.java
@@ -83,16 +83,6 @@ public class SecurityQuestionsPanel extends AbstractSearchResultPanel<
                 final SecurityQuestionTO modelObject = newModelObject();
                 return new SecurityQuestionsModalPanel(modal, modelObject, pageRef);
             }
-
-            @Override
-            protected void onCancelInternal(final SecurityQuestionTO modelObject) {
-            }
-
-            @Override
-            protected Serializable onApplyInternal(final SecurityQuestionTO modelObject) {
-                // do nothing
-                return null;
-            }
         }, true);
 
         setFooterVisibility(true);
@@ -243,8 +233,8 @@ public class SecurityQuestionsPanel extends AbstractSearchResultPanel<
 
         @Override
         public Iterator<SecurityQuestionTO> iterator(final long first, final long count) {
-            final List<SecurityQuestionTO> list = SyncopeConsoleSession.get().getService(SecurityQuestionService.class).
-                    list();
+            final List<SecurityQuestionTO> list
+                    = SyncopeConsoleSession.get().getService(SecurityQuestionService.class).list();
             Collections.sort(list, comparator);
             return list.subList((int) first, (int) first + (int) count).iterator();
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/panels/UserSearchResultPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/UserSearchResultPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/UserSearchResultPanel.java
index 25db807..a99c957 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/UserSearchResultPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/UserSearchResultPanel.java
@@ -29,7 +29,6 @@ import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.pages.BasePage;
 import org.apache.syncope.client.console.pages.StatusModal;
 import org.apache.syncope.client.console.pages.UserDisplayAttributesModalPage;
-import org.apache.syncope.client.console.rest.AbstractAnyRestClient;
 import org.apache.syncope.client.console.rest.UserRestClient;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.AttrColumn;
@@ -121,8 +120,8 @@ public class UserSearchResultPanel extends AnySearchResultPanel<UserTO> {
 
                     @Override
                     public void onClick(final AjaxRequestTarget target, final UserTO ignore) {
-                        final IModel<AnyHandler<UserTO>> formModel =
-                                new CompoundPropertyModel<>(new AnyHandler<>(model.getObject()));
+                        final IModel<AnyHandler<UserTO>> formModel = new CompoundPropertyModel<>(new AnyHandler<>(model.
+                                getObject()));
                         modal.setFormModel(formModel);
 
                         target.add(modal.setContent(new StatusModal<>(
@@ -139,8 +138,8 @@ public class UserSearchResultPanel extends AnySearchResultPanel<UserTO> {
 
                     @Override
                     public void onClick(final AjaxRequestTarget target, final UserTO ignore) {
-                        final IModel<AnyHandler<UserTO>> formModel =
-                                new CompoundPropertyModel<>(new AnyHandler<>(model.getObject()));
+                        final IModel<AnyHandler<UserTO>> formModel = new CompoundPropertyModel<>(new AnyHandler<>(model.
+                                getObject()));
                         modal.setFormModel(formModel);
 
                         target.add(modal.setContent(new StatusModal<>(
@@ -233,13 +232,8 @@ public class UserSearchResultPanel extends AnySearchResultPanel<UserTO> {
 
         private static final long serialVersionUID = 1L;
 
-        public Builder(
-                final List<AnyTypeClassTO> anyTypeClassTOs,
-                final AbstractAnyRestClient<UserTO> restClient,
-                final String type,
-                final PageReference pageRef) {
-
-            super(anyTypeClassTOs, restClient, type, pageRef);
+        public Builder(final List<AnyTypeClassTO> anyTypeClassTOs, final String type, final PageReference pageRef) {
+            super(anyTypeClassTOs, new UserRestClient(), type, pageRef);
             setShowResultPage(true);
         }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/panels/search/AnyObjectSelectionSearchResultPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/AnyObjectSelectionSearchResultPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/AnyObjectSelectionSearchResultPanel.java
index 2039937..e9312e2 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/AnyObjectSelectionSearchResultPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/AnyObjectSelectionSearchResultPanel.java
@@ -20,7 +20,7 @@ package org.apache.syncope.client.console.panels.search;
 
 import java.util.List;
 import org.apache.syncope.client.console.commons.Constants;
-import org.apache.syncope.client.console.rest.AbstractAnyRestClient;
+import org.apache.syncope.client.console.rest.AnyObjectRestClient;
 import org.apache.syncope.client.console.wizards.WizardMgtPanel;
 import org.apache.syncope.client.console.wizards.any.AnyHandler;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
@@ -33,8 +33,7 @@ public final class AnyObjectSelectionSearchResultPanel extends AnySelectionSearc
 
     public static final String[] USER_DEFAULT_SELECTION = { "key" };
 
-    private AnyObjectSelectionSearchResultPanel(final String id,
-            final AnyObjectSelectionSearchResultPanel.Builder builder) {
+    private AnyObjectSelectionSearchResultPanel(final String id, final Builder builder) {
         super(id, builder);
     }
 
@@ -67,13 +66,8 @@ public final class AnyObjectSelectionSearchResultPanel extends AnySelectionSearc
 
         private static final long serialVersionUID = 1L;
 
-        public Builder(
-                final List<AnyTypeClassTO> anyTypeClassTOs,
-                final AbstractAnyRestClient<AnyObjectTO> restClient,
-                final String type,
-                final PageReference pageRef) {
-
-            super(anyTypeClassTOs, restClient, type, pageRef);
+        public Builder(final List<AnyTypeClassTO> anyTypeClassTOs, final String type, final PageReference pageRef) {
+            super(anyTypeClassTOs, new AnyObjectRestClient(), type, pageRef);
             this.filtered = true;
             this.checkBoxEnabled = false;
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSelectionSearchResultPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSelectionSearchResultPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSelectionSearchResultPanel.java
index e3a734c..77ecf4b 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSelectionSearchResultPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/GroupSelectionSearchResultPanel.java
@@ -20,7 +20,7 @@ package org.apache.syncope.client.console.panels.search;
 
 import java.util.List;
 import org.apache.syncope.client.console.commons.Constants;
-import org.apache.syncope.client.console.rest.AbstractAnyRestClient;
+import org.apache.syncope.client.console.rest.GroupRestClient;
 import org.apache.syncope.client.console.wizards.WizardMgtPanel;
 import org.apache.syncope.client.console.wizards.any.AnyHandler;
 import org.apache.syncope.common.lib.to.AnyTypeClassTO;
@@ -66,13 +66,8 @@ public final class GroupSelectionSearchResultPanel extends AnySelectionSearchRes
 
         private static final long serialVersionUID = 1L;
 
-        public Builder(
-                final List<AnyTypeClassTO> anyTypeClassTOs,
-                final AbstractAnyRestClient<GroupTO> restClient,
-                final String type,
-                final PageReference pageRef) {
-
-            super(anyTypeClassTOs, restClient, type, pageRef);
+        public Builder(final List<AnyTypeClassTO> anyTypeClassTOs, final String type, final PageReference pageRef) {
+            super(anyTypeClassTOs, new GroupRestClient(), type, pageRef);
             this.filtered = true;
             this.checkBoxEnabled = false;
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/panels/search/UserSelectionSearchResultPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/UserSelectionSearchResultPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/UserSelectionSearchResultPanel.java
index 8ae41f4..52fbeb2 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/search/UserSelectionSearchResultPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/search/UserSelectionSearchResultPanel.java
@@ -20,7 +20,7 @@ package org.apache.syncope.client.console.panels.search;
 
 import java.util.List;
 import org.apache.syncope.client.console.commons.Constants;
-import org.apache.syncope.client.console.rest.AbstractAnyRestClient;
+import org.apache.syncope.client.console.rest.UserRestClient;
 import org.apache.syncope.client.console.wizards.WizardMgtPanel;
 import org.apache.syncope.client.console.wizards.any.AnyHandler;
 import org.apache.syncope.common.lib.to.AnyTypeClassTO;
@@ -33,7 +33,7 @@ public final class UserSelectionSearchResultPanel extends AnySelectionSearchResu
 
     public static final String[] USER_DEFAULT_SELECTION = { "key", "username", "status" };
 
-    private UserSelectionSearchResultPanel(final String id, final UserSelectionSearchResultPanel.Builder builder) {
+    private UserSelectionSearchResultPanel(final String id, final Builder builder) {
         super(id, builder);
     }
 
@@ -66,13 +66,8 @@ public final class UserSelectionSearchResultPanel extends AnySelectionSearchResu
 
         private static final long serialVersionUID = 1L;
 
-        public Builder(
-                final List<AnyTypeClassTO> anyTypeClassTOs,
-                final AbstractAnyRestClient<UserTO> restClient,
-                final String type,
-                final PageReference pageRef) {
-
-            super(anyTypeClassTOs, restClient, type, pageRef);
+        public Builder(final List<AnyTypeClassTO> anyTypeClassTOs, final String type, final PageReference pageRef) {
+            super(anyTypeClassTOs, new UserRestClient(), type, pageRef);
             this.filtered = true;
             this.checkBoxEnabled = false;
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java
index a97c066..bf7a894 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/TaskRestClient.java
@@ -30,8 +30,10 @@ import org.apache.syncope.common.lib.to.PropagationTaskTO;
 import org.apache.syncope.common.lib.to.PushTaskTO;
 import org.apache.syncope.common.lib.to.SchedTaskTO;
 import org.apache.syncope.common.lib.to.SyncTaskTO;
+import org.apache.syncope.common.lib.to.TaskExecTO;
 import org.apache.syncope.common.lib.types.TaskType;
 import org.apache.syncope.common.rest.api.beans.ExecuteQuery;
+import org.apache.syncope.common.rest.api.beans.TaskExecQuery;
 import org.apache.syncope.common.rest.api.beans.TaskQuery;
 import org.apache.syncope.common.rest.api.service.TaskService;
 import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
@@ -61,10 +63,25 @@ public class TaskRestClient extends BaseRestClient implements ExecutionRestClien
      * @param kind of task (propagation, sched, sync).
      * @return number of stored tasks.
      */
-    public int count(final String kind) {
+    public int count(final TaskType kind) {
         return getService(TaskService.class).
-                list(new TaskQuery.Builder().type(TaskType.valueOf(kind)).page(1).size(1).build()).
-                getTotalCount();
+                list(new TaskQuery.Builder().type(kind).page(1).size(1).build()).getTotalCount();
+    }
+
+    public int countExecutions(final Long taskId) {
+        return getService(TaskService.class).
+                listExecutions(new TaskExecQuery.Builder().key(taskId).page(1).size(1).build()).getTotalCount();
+    }
+
+    public List<PropagationTaskTO> listPropagationTasks(
+            final String resource, final int page, final int size, final SortParam<String> sort) {
+
+        return getService(TaskService.class).
+                <PropagationTaskTO>list(new TaskQuery.Builder().type(TaskType.PROPAGATION).
+                        resource(resource).
+                        page(page).size(size).
+                        orderBy(toOrderBy(sort)).build()).
+                getResult();
     }
 
     @SuppressWarnings("unchecked")
@@ -77,6 +94,11 @@ public class TaskRestClient extends BaseRestClient implements ExecutionRestClien
                 getResult();
     }
 
+    public List<TaskExecTO> listExecutions(final Long taskId, final int page, final int size) {
+        return getService(TaskService.class).
+                listExecutions(new TaskExecQuery.Builder().key(taskId).page(page).size(size).build()).getResult();
+    }
+
     private TaskType getTaskType(final Class<?> reference) {
         TaskType result = null;
         if (PropagationTaskTO.class.equals(reference)) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/tasks/ExecMessage.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/tasks/ExecMessage.java b/client/console/src/main/java/org/apache/syncope/client/console/tasks/ExecMessage.java
new file mode 100644
index 0000000..50a8fa8
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/tasks/ExecMessage.java
@@ -0,0 +1,34 @@
+/*
+ * 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.tasks;
+
+import org.apache.syncope.client.console.panels.MultilevelPanel;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.model.Model;
+
+public class ExecMessage extends MultilevelPanel.SecondLevel {
+
+    private static final long serialVersionUID = 3163146190501510888L;
+
+    public ExecMessage(final String message) {
+        super();
+        final Label dialogContent = new Label("message", new Model<String>(message));
+        add(dialogContent.setOutputMarkupId(true));
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/tasks/PropagationTaskDetails.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/tasks/PropagationTaskDetails.java b/client/console/src/main/java/org/apache/syncope/client/console/tasks/PropagationTaskDetails.java
new file mode 100644
index 0000000..dac1e7d
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/tasks/PropagationTaskDetails.java
@@ -0,0 +1,78 @@
+/*
+ * 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.tasks;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.to.PropagationTaskTO;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
+import org.apache.wicket.extensions.markup.html.tabs.ITab;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+
+/**
+ * Modal window with Task form (to stop and start execution).
+ */
+public class PropagationTaskDetails extends TaskDetails<PropagationTaskTO> {
+
+    private static final long serialVersionUID = -4110576026663173545L;
+
+    public PropagationTaskDetails(final PropagationTaskTO taskTO, final PageReference pageRef) {
+        super(taskTO, pageRef);
+    }
+
+    @Override
+    protected List<ITab> buildTabList(final PropagationTaskTO taskTO, final PageReference pageRef) {
+        final List<ITab> res = new ArrayList<>();
+        res.add(new AbstractTab(new Model<>("profile")) {
+
+            private static final long serialVersionUID = -5861786415855103559L;
+
+            @Override
+            public WebMarkupContainer getPanel(final String panelId) {
+                return new Profile(panelId, taskTO);
+            }
+        });
+        return res;
+    }
+
+    public class Profile extends Panel {
+
+        private static final long serialVersionUID = -1518744792346267268L;
+
+        public Profile(final String id, final PropagationTaskTO taskTO) {
+            super(id);
+            add(new AjaxTextFieldPanel(
+                    "key", getString("key"), new PropertyModel<String>(taskTO, "key")).
+                    setEnabled(false));
+
+            add(new AjaxTextFieldPanel(
+                    "anyKey", getString("anyKey"), new PropertyModel<String>(taskTO, "anyKey")).
+                    setEnabled(false));
+
+            add(new AjaxTextFieldPanel(
+                    "resource", getString("resource"), new PropertyModel<String>(taskTO, "resource")).
+                    setEnabled(false));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/tasks/PropagationTaskSearchResultPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/tasks/PropagationTaskSearchResultPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/tasks/PropagationTaskSearchResultPanel.java
new file mode 100644
index 0000000..794d942
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/tasks/PropagationTaskSearchResultPanel.java
@@ -0,0 +1,287 @@
+/*
+ * 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.tasks;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.SearchableDataProvider;
+import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.syncope.client.console.panels.AbstractSearchResultPanel;
+import org.apache.syncope.client.console.panels.ModalPanel;
+import org.apache.syncope.client.console.rest.TaskRestClient;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink.ActionType;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.to.PropagationTaskTO;
+import org.apache.syncope.common.lib.types.StandardEntitlement;
+import org.apache.syncope.common.lib.types.TaskType;
+import org.apache.syncope.client.console.tasks.PropagationTaskSearchResultPanel.TasksProvider;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.model.StringResourceModel;
+
+/**
+ * Tasks page.
+ */
+public abstract class PropagationTaskSearchResultPanel extends AbstractSearchResultPanel<
+        PropagationTaskTO, PropagationTaskTO, TasksProvider<PropagationTaskTO>, TaskRestClient>
+        implements ModalPanel<PropagationTaskTO> {
+
+    private static final long serialVersionUID = 4984337552918213290L;
+
+    private final TaskRestClient taskRestClient = new TaskRestClient();
+
+    private final String resource;
+
+    protected PropagationTaskSearchResultPanel(
+            final String id,
+            final PageReference pageRef,
+            final String resource) {
+
+        super(id, pageRef, false);
+        this.resource = resource;
+        setShowResultPage(true);
+        modal.size(Modal.Size.Large);
+        initResultTable();
+    }
+
+    @Override
+    protected List<IColumn<PropagationTaskTO, String>> getColumns() {
+        final List<IColumn<PropagationTaskTO, String>> columns = new ArrayList<IColumn<PropagationTaskTO, String>>();
+
+        columns.add(new PropertyColumn<PropagationTaskTO, String>(
+                new StringResourceModel("key", this, null), "key", "key"));
+
+        columns.add(new PropertyColumn<PropagationTaskTO, String>(new StringResourceModel(
+                "operation", this, null), "operation", "operation"));
+
+        columns.add(new PropertyColumn<PropagationTaskTO, String>(
+                new StringResourceModel("anyTypeKind", this, null), "anyTypeKind", "anyTypeKind"));
+
+        columns.add(new PropertyColumn<PropagationTaskTO, String>(
+                new StringResourceModel("anyKey", this, null), "anyKey", "anyKey"));
+
+        columns.add(new PropertyColumn<PropagationTaskTO, String>(
+                new StringResourceModel("resource", this, null), "resource", "resource"));
+
+        columns.add(new PropertyColumn<PropagationTaskTO, String>(
+                new StringResourceModel("connObjectKey", this, null), "connObjectKey", "connObjectKey"));
+
+        columns.add(new DatePropertyColumn<PropagationTaskTO>(
+                new StringResourceModel("start", this, null), "start", "start"));
+
+        columns.add(new DatePropertyColumn<PropagationTaskTO>(
+                new StringResourceModel("end", this, null), "end", "end"));
+
+        columns.add(new PropertyColumn<PropagationTaskTO, String>(
+                new StringResourceModel("latestExecStatus", this, null), "latestExecStatus", "latestExecStatus"));
+
+        columns.add(new ActionColumn<PropagationTaskTO, String>(new ResourceModel("actions", "")) {
+
+            private static final long serialVersionUID = 2054811145491901166L;
+
+            @Override
+            public String getCssClass() {
+                return "action";
+            }
+
+            @Override
+            public ActionLinksPanel<PropagationTaskTO> getActions(
+                    final String componentId, final IModel<PropagationTaskTO> model) {
+
+                final PropagationTaskTO taskTO = model.getObject();
+
+                final ActionLinksPanel<PropagationTaskTO> panel = ActionLinksPanel.<PropagationTaskTO>builder(pageRef).
+                        add(new ActionLink<PropagationTaskTO>() {
+
+                            private static final long serialVersionUID = -3722207913631435501L;
+
+                            @Override
+                            public void onClick(final AjaxRequestTarget target, final PropagationTaskTO modelObject) {
+                                viewTask(taskTO, target);
+                            }
+                        }, ActionLink.ActionType.EDIT, StandardEntitlement.TASK_READ).
+                        add(new ActionLink<PropagationTaskTO>() {
+
+                            private static final long serialVersionUID = -3722207913631435501L;
+
+                            @Override
+                            public void onClick(final AjaxRequestTarget target, final PropagationTaskTO modelObject) {
+                                try {
+                                    taskRestClient.startExecution(taskTO.getKey(), new Date());
+                                    info(getString(Constants.OPERATION_SUCCEEDED));
+                                    target.add(container);
+                                } catch (SyncopeClientException e) {
+                                    error(getString(Constants.ERROR) + ": " + e.getMessage());
+                                    LOG.error("While running propagation task {}", taskTO.getKey(), e);
+                                }
+                                ((BasePage) getPage()).getNotificationPanel().refresh(target);
+                            }
+                        }, ActionLink.ActionType.EXECUTE, StandardEntitlement.TASK_EXECUTE).
+                        add(new ActionLink<PropagationTaskTO>() {
+
+                            private static final long serialVersionUID = -3722207913631435501L;
+
+                            @Override
+                            public void onClick(final AjaxRequestTarget target, final PropagationTaskTO modelObject) {
+                                try {
+                                    taskRestClient.delete(taskTO.getKey(), PropagationTaskTO.class);
+                                    info(getString(Constants.OPERATION_SUCCEEDED));
+                                    target.add(container);
+                                } catch (SyncopeClientException e) {
+                                    error(getString(Constants.ERROR) + ": " + e.getMessage());
+                                    LOG.error("While deleting propagation task {}", taskTO.getKey(), e);
+                                }
+                                ((BasePage) getPage()).getNotificationPanel().refresh(target);
+                            }
+                        }, ActionLink.ActionType.DELETE, StandardEntitlement.TASK_DELETE).build(componentId);
+
+                return panel;
+            }
+
+            @Override
+            public ActionLinksPanel<PropagationTaskTO> getHeader(final String componentId) {
+                final ActionLinksPanel.Builder<PropagationTaskTO> panel
+                        = ActionLinksPanel.builder(page.getPageReference());
+
+                return panel.add(new ActionLink<PropagationTaskTO>() {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target, final PropagationTaskTO ignore) {
+                        if (target != null) {
+                            target.add(container);
+                        }
+                    }
+                }, ActionLink.ActionType.RELOAD, StandardEntitlement.TASK_LIST).build(componentId);
+            }
+        });
+
+        return columns;
+    }
+
+    @Override
+    protected Collection<ActionType> getBulkActions() {
+        final List<ActionType> bulkActions = new ArrayList<>();
+        bulkActions.add(ActionType.DELETE);
+        return bulkActions;
+    }
+
+    @Override
+    protected TasksProvider<PropagationTaskTO> dataProvider() {
+        return new PropagationTasksProvider(rows, this.resource);
+    }
+
+    @Override
+    protected String paginatorRowsKey() {
+        return Constants.PREF_PROPAGATION_TASKS_PAGINATOR_ROWS;
+    }
+
+    @Override
+    public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public void onError(final AjaxRequestTarget target, final Form<?> form) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public PropagationTaskTO getItem() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public class PropagationTasksProvider extends TasksProvider<PropagationTaskTO> {
+
+        private static final long serialVersionUID = 4725679400450513556L;
+
+        private final String resource;
+
+        public PropagationTasksProvider(final int paginatorRows, final String resource) {
+            super(paginatorRows, TaskType.PROPAGATION);
+            this.resource = resource;
+        }
+
+        @Override
+        public Iterator<PropagationTaskTO> iterator(final long first, final long count) {
+            final int page = ((int) first / paginatorRows);
+
+            final List<PropagationTaskTO> tasks = taskRestClient.listPropagationTasks(
+                    resource, (page < 0 ? 0 : page) + 1, paginatorRows, getSort());
+
+            Collections.sort(tasks, getComparator());
+            return tasks.iterator();
+        }
+    }
+
+    public abstract class TasksProvider<T extends AbstractTaskTO> extends SearchableDataProvider<T> {
+
+        private static final long serialVersionUID = -20112718133295756L;
+
+        private final SortableDataProviderComparator<T> comparator;
+
+        private final TaskType id;
+
+        public TasksProvider(final int paginatorRows, final TaskType id) {
+
+            super(paginatorRows);
+
+            //Default sorting
+            setSort("key", SortOrder.DESCENDING);
+            comparator = new SortableDataProviderComparator<T>(this);
+            this.id = id;
+        }
+
+        public SortableDataProviderComparator<T> getComparator() {
+            return comparator;
+        }
+
+        @Override
+        public long size() {
+            return taskRestClient.count(id);
+        }
+
+        @Override
+        public IModel<T> model(final T object) {
+            return new CompoundPropertyModel<>(object);
+        }
+    }
+
+    protected abstract void viewTask(final PropagationTaskTO taskTO, final AjaxRequestTarget target);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/tasks/PropagationTasks.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/tasks/PropagationTasks.java b/client/console/src/main/java/org/apache/syncope/client/console/tasks/PropagationTasks.java
new file mode 100644
index 0000000..542ae3d
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/tasks/PropagationTasks.java
@@ -0,0 +1,69 @@
+/*
+ * 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.tasks;
+
+import static org.apache.syncope.client.console.panels.MultilevelPanel.FIRST_LEVEL_ID;
+
+import java.io.Serializable;
+import org.apache.syncope.client.console.panels.ModalPanel;
+import org.apache.syncope.client.console.panels.MultilevelPanel;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.PropagationTaskTO;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.panel.Panel;
+
+public class PropagationTasks extends Panel implements ModalPanel<Serializable> {
+
+    private static final long serialVersionUID = -4013796607157549641L;
+
+    public <T extends AnyTO> PropagationTasks(final PageReference pageReference, final String resource) {
+        super(BaseModal.CONTENT_ID);
+
+        final MultilevelPanel mlp = new MultilevelPanel("tasks");
+        add(mlp);
+
+        mlp.setFirstLevel(new PropagationTaskSearchResultPanel(FIRST_LEVEL_ID, pageReference, resource) {
+
+            private static final long serialVersionUID = -2195387360323687302L;
+
+            @Override
+            protected void viewTask(final PropagationTaskTO taskTO, final AjaxRequestTarget target) {
+                mlp.next("task.view", new PropagationTaskDetails(taskTO, pageReference), target);
+            }
+        });
+    }
+
+    @Override
+    public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public void onError(final AjaxRequestTarget target, final Form<?> form) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    public Serializable getItem() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/tasks/TaskDetails.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/tasks/TaskDetails.java b/client/console/src/main/java/org/apache/syncope/client/console/tasks/TaskDetails.java
new file mode 100644
index 0000000..c34c152
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/tasks/TaskDetails.java
@@ -0,0 +1,267 @@
+/*
+ * 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.tasks;
+
+import de.agilecoders.wicket.core.markup.html.bootstrap.tabs.AjaxBootstrapTabbedPanel;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.SearchableDataProvider;
+import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.syncope.client.console.panels.AbstractSearchResultPanel;
+import org.apache.syncope.client.console.panels.MultilevelPanel;
+import org.apache.syncope.client.console.panels.MultilevelPanel.SecondLevel;
+import org.apache.syncope.client.console.rest.TaskRestClient;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
+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.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractTaskTO;
+import org.apache.syncope.common.lib.to.TaskExecTO;
+import org.apache.syncope.common.lib.types.StandardEntitlement;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.repeater.data.table.AjaxFallbackDefaultDataTable;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
+import org.apache.wicket.extensions.markup.html.tabs.ITab;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.model.AbstractReadOnlyModel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.ResourceModel;
+
+/**
+ * Modal window with Task form (to stop and start execution).
+ *
+ * @param <T> task type.
+ */
+public abstract class TaskDetails<T extends AbstractTaskTO> extends MultilevelPanel.SecondLevel {
+
+    private static final long serialVersionUID = -4110576026663173545L;
+
+    public TaskDetails(final T taskTO, final PageReference pageReference) {
+        super();
+
+        final List<ITab> tabs = buildTabList(taskTO, pageReference);
+        tabs.add(new AbstractTab(new Model<>("executions")) {
+
+            private static final long serialVersionUID = -5861786415855103549L;
+
+            @Override
+            public WebMarkupContainer getPanel(final String panelId) {
+                final MultilevelPanel mlp = new MultilevelPanel(panelId);
+                mlp.setFirstLevel(new Executions(MultilevelPanel.FIRST_LEVEL_ID, taskTO, pageReference) {
+
+                    private static final long serialVersionUID = 5691719817252887541L;
+
+                    @Override
+                    protected void next(
+                            final String title, final SecondLevel secondLevel, final AjaxRequestTarget target) {
+                        mlp.next(title, secondLevel, target);
+                    }
+
+                });
+                return mlp;
+            }
+        });
+
+        add(new AjaxBootstrapTabbedPanel<>("tabbedPanel", tabs));
+    }
+
+    protected abstract List<ITab> buildTabList(final T taskTO, final PageReference pageReference);
+
+    public abstract class Executions
+            extends AbstractSearchResultPanel<TaskExecTO, TaskExecTO, TaskExecProvider, TaskRestClient> {
+
+        private static final long serialVersionUID = 2039393934721149162L;
+
+        private final AbstractTaskTO taskTO;
+
+        public Executions(final String id, final AbstractTaskTO taskTO, final PageReference pageRef) {
+            super(id, pageRef, false);
+            setOutputMarkupId(true);
+            this.taskTO = taskTO;
+            initResultTable();
+        }
+
+        protected abstract void next(final String title, final SecondLevel secondLevel, final AjaxRequestTarget target);
+
+        @Override
+        protected List<IColumn<TaskExecTO, String>> getColumns() {
+            final List<IColumn<TaskExecTO, String>> columns = new ArrayList<IColumn<TaskExecTO, String>>();
+
+            final int paginatorRows = 10;
+
+            columns.add(new PropertyColumn<TaskExecTO, String>(new ResourceModel("key"), "key", "key"));
+
+            columns.add(new DatePropertyColumn<TaskExecTO>(new ResourceModel("start"), "start", "start"));
+
+            columns.add(new DatePropertyColumn<TaskExecTO>(new ResourceModel("end"), "end", "end"));
+
+            columns.add(new PropertyColumn<TaskExecTO, String>(new ResourceModel("status"), "status", "status"));
+
+            columns.add(new ActionColumn<TaskExecTO, String>(new ResourceModel("actions", "")) {
+
+                private static final long serialVersionUID = -3503023501954863131L;
+
+                @Override
+                public ActionLinksPanel<TaskExecTO> getActions(
+                        final String componentId, final IModel<TaskExecTO> model) {
+
+                    final TaskExecTO taskExecutionTO = model.getObject();
+
+                    final ActionLinksPanel.Builder<TaskExecTO> panel = ActionLinksPanel.builder(pageRef);
+
+                    panel.
+                            add(new ActionLink<TaskExecTO>() {
+
+                                private static final long serialVersionUID = -3722207913631435501L;
+
+                                @Override
+                                public void onClick(final AjaxRequestTarget target, final TaskExecTO ignore) {
+                                    next("execution.view",
+                                            new ExecMessage(model.getObject().getMessage()), target);
+                                }
+                            }, ActionLink.ActionType.EDIT, StandardEntitlement.TASK_READ).
+                            add(new ActionLink<TaskExecTO>() {
+
+                                private static final long serialVersionUID = -3722207913631435501L;
+
+                                @Override
+                                public void onClick(final AjaxRequestTarget target, final TaskExecTO ignore) {
+                                    try {
+                                        restClient.deleteExecution(taskExecutionTO.getKey());
+                                        taskTO.getExecutions().remove(taskExecutionTO);
+                                        info(getString(Constants.OPERATION_SUCCEEDED));
+                                    } catch (SyncopeClientException scce) {
+                                        error(scce.getMessage());
+                                    }
+
+                                    BasePage.class.cast(pageRef.getPage()).getNotificationPanel().refresh(target);
+                                    target.add(Executions.this);
+                                }
+                            }, ActionLink.ActionType.DELETE, StandardEntitlement.TASK_DELETE);
+
+                    return panel.build(componentId, model.getObject());
+                }
+
+                @Override
+                public ActionLinksPanel<Serializable> getHeader(final String componentId) {
+                    final ActionLinksPanel.Builder<Serializable> panel = ActionLinksPanel.builder(pageRef);
+
+                    return panel.add(new ActionLink<Serializable>() {
+
+                        private static final long serialVersionUID = -7978723352517770644L;
+
+                        @Override
+                        public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
+                            if (target != null) {
+                                final AjaxFallbackDefaultDataTable<TaskExecTO, String> currentTable
+                                        = new AjaxFallbackDefaultDataTable<TaskExecTO, String>(
+                                                "executionsTable",
+                                                columns,
+                                                new TaskExecProvider(taskTO.getKey(), paginatorRows),
+                                                paginatorRows);
+                                currentTable.setOutputMarkupId(true);
+                                target.add(currentTable);
+                                addOrReplace(currentTable);
+                            }
+                        }
+                    }, ActionLink.ActionType.RELOAD, StandardEntitlement.TASK_LIST).build(componentId);
+                }
+            });
+
+            return columns;
+        }
+
+        @Override
+        protected TaskExecProvider dataProvider() {
+            return new TaskExecProvider(taskTO.getKey(), rows);
+        }
+
+        @Override
+        protected String paginatorRowsKey() {
+            return Constants.PREF_TASK_EXECS_PAGINATOR_ROWS;
+        }
+
+        @Override
+        protected Collection<ActionLink.ActionType> getBulkActions() {
+            final List<ActionLink.ActionType> bulkActions = new ArrayList<>();
+            bulkActions.add(ActionLink.ActionType.DELETE);
+            return bulkActions;
+        }
+
+    }
+
+    protected class TaskExecProvider extends SearchableDataProvider<TaskExecTO> {
+
+        private static final long serialVersionUID = 8943636537120648961L;
+
+        protected TaskRestClient taskRestClient = new TaskRestClient();
+
+        private final SortableDataProviderComparator<TaskExecTO> comparator;
+
+        private final Long taskId;
+
+        public TaskExecProvider(final Long taskId, final int paginatorRows) {
+            super(paginatorRows);
+            this.taskId = taskId;
+            comparator = new SortableDataProviderComparator<TaskExecTO>(this);
+        }
+
+        public SortableDataProviderComparator<TaskExecTO> getComparator() {
+            return comparator;
+        }
+
+        @Override
+        public Iterator<TaskExecTO> iterator(final long first, final long count) {
+            final int page = ((int) first / paginatorRows);
+            List<TaskExecTO> list = taskRestClient.listExecutions(taskId, (page < 0 ? 0 : page) + 1, paginatorRows);
+            Collections.sort(list, comparator);
+            return list.iterator();
+        }
+
+        @Override
+        public long size() {
+            return taskRestClient.countExecutions(taskId);
+        }
+
+        @Override
+        public IModel<TaskExecTO> model(final TaskExecTO taskExecution) {
+
+            return new AbstractReadOnlyModel<TaskExecTO>() {
+
+                private static final long serialVersionUID = 7485475149862342421L;
+
+                @Override
+                public TaskExecTO getObject() {
+                    return taskExecution;
+                }
+            };
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.java
index 1982b09..b83fae2 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyNodePanel.java
@@ -38,8 +38,6 @@ public class TopologyNodePanel extends Panel implements IAjaxIndicatorAware {
 
     }
 
-    private Status status = Status.INACTIVE;
-
     public TopologyNodePanel(
             final String id,
             final TopologyNode node) {
@@ -47,7 +45,7 @@ public class TopologyNodePanel extends Panel implements IAjaxIndicatorAware {
         super(id);
 
         final String resourceName = node.getDisplayName().length() > 14
-                ? node.getDisplayName().subSequence(0, 12) + "..."
+                ? node.getDisplayName().subSequence(0, 10) + "..."
                 : node.getDisplayName();
 
         add(new Label("label", resourceName));
@@ -103,8 +101,4 @@ public class TopologyNodePanel extends Panel implements IAjaxIndicatorAware {
     public String getAjaxIndicatorMarkupId() {
         return "veil";
     }
-
-    public void setStatus(final Status status) {
-        this.status = status;
-    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/17f53ed8/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java
index ad62deb..7c7215e 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java
@@ -28,6 +28,7 @@ import org.apache.syncope.client.console.panels.ResourceModal;
 import org.apache.syncope.client.console.panels.TogglePanel;
 import org.apache.syncope.client.console.rest.ConnectorRestClient;
 import org.apache.syncope.client.console.rest.ResourceRestClient;
+import org.apache.syncope.client.console.tasks.PropagationTasks;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.confirmation.ConfirmationModalBehavior;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.ConnInstanceTO;
@@ -295,8 +296,9 @@ public class TopologyTogglePanel extends TogglePanel<Serializable> {
             private static final long serialVersionUID = 3776750333491622263L;
 
             @Override
+            @SuppressWarnings("unchecked")
             public void onClick(final AjaxRequestTarget target) {
-                target.add(modal);
+                target.add(modal.setContent(new PropagationTasks(pageRef, node.getKey().toString())));
                 modal.header(new ResourceModel("task.propagation.list", "Propagation tasks"));
                 modal.show(true);
             }