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/04/28 18:40:41 UTC

[4/4] syncope git commit: [SYNCOPE-745] report management + refactoring ModalPanel interface; still missing reportlets

[SYNCOPE-745] report management + refactoring ModalPanel interface; still missing reportlets


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

Branch: refs/heads/master
Commit: ae52b12e1432253900e5712af419855e595fac20
Parents: e87e410
Author: fmartelli <fa...@gmail.com>
Authored: Thu Apr 28 18:39:11 2016 +0200
Committer: fmartelli <fa...@gmail.com>
Committed: Thu Apr 28 18:39:11 2016 +0200

----------------------------------------------------------------------
 .../client/console/approvals/ApprovalModal.java |   5 +-
 .../client/console/bulk/BulkActionModal.java    |   4 +-
 .../client/console/bulk/BulkContent.java        |  10 +-
 .../notifications/MailTemplateContentModal.java | 120 ---------
 .../MailTemplateDirectoryPanel.java             |  24 +-
 .../notifications/MailTemplateModal.java        |  72 -----
 .../notifications/NotificationTasks.java        |  21 +-
 .../notifications/TemplateContentModal.java     | 124 +++++++++
 .../console/notifications/TemplateModal.java    |  76 ++++++
 .../syncope/client/console/pages/Reports.java   |  60 +++++
 .../console/panels/AbstractModalPanel.java      |   3 +-
 .../console/panels/AjaxDataTablePanel.java      |   5 +-
 .../console/panels/AnyTypeClassesPanel.java     |   4 +-
 .../client/console/panels/AnyTypesPanel.java    |   2 +-
 .../panels/ConnObjectDirectoryPanel.java        |  18 +-
 .../client/console/panels/ConnObjects.java      |  19 +-
 .../client/console/panels/DirectoryPanel.java   |   6 +-
 .../console/panels/FailureMessageModal.java     |  19 +-
 .../client/console/panels/ModalPanel.java       |  10 +-
 .../client/console/panels/ParametersPanel.java  |   2 +-
 .../console/panels/RelationshipTypesPanel.java  |   3 +-
 .../client/console/panels/SchemaTypePanel.java  |   2 +-
 .../console/panels/SecurityQuestionsPanel.java  |   3 +-
 .../console/panels/StartAtTogglePanel.java      | 105 ++++++++
 .../console/panels/SubmitableModalPanel.java    |  29 +++
 .../panels/TypeExtensionDirectoryPanel.java     |   7 +-
 .../client/console/panels/WizardModalPanel.java |  26 ++
 .../console/reports/ReportDirectoryPanel.java   | 261 +++++++++++++++++++
 .../console/reports/ReportExecutionDetails.java |  54 ++++
 .../reports/ReportStartAtTogglePanel.java       |  39 +++
 .../reports/ReportTemplateDirectoryPanel.java   | 251 ++++++++++++++++++
 .../console/reports/ReportWizardBuilder.java    | 108 ++++++++
 .../client/console/rest/BaseRestClient.java     |   3 +-
 .../console/rest/ExecutionRestClient.java       |   6 +-
 .../console/rest/NotificationRestClient.java    |   9 +-
 .../client/console/rest/ReportRestClient.java   |  63 ++++-
 .../syncope/client/console/rest/RestClient.java |  24 ++
 .../client/console/rest/TaskRestClient.java     |   2 +
 .../client/console/rest/TemplateRestClient.java |  36 +++
 .../console/status/StatusDirectoryPanel.java    |  19 +-
 .../client/console/status/StatusModal.java      |  20 +-
 .../client/console/tasks/AbstractTasks.java     |  20 +-
 .../console/tasks/ExecutionsDirectoryPanel.java | 232 +++++++++++++++++
 .../tasks/NotificationTaskDirectoryPanel.java   |   2 +-
 .../tasks/PropagationTaskDirectoryPanel.java    |   2 +-
 .../console/tasks/SchedTaskDirectoryPanel.java  |   9 +-
 .../console/tasks/SchedTaskWizardBuilder.java   |  12 +-
 .../console/tasks/StartAtTogglePanel.java       | 106 --------
 .../console/tasks/TaskDirectoryPanel.java       |  20 +-
 .../console/tasks/TaskExecutionDetails.java     |   3 +-
 .../client/console/tasks/TaskExecutions.java    | 227 ----------------
 .../console/tasks/TaskStartAtTogglePanel.java   |  39 +++
 .../markup/html/bootstrap/dialog/BaseModal.java |  17 +-
 .../wicket/markup/html/form/ActionLink.java     |   1 +
 .../markup/html/form/ActionLinksPanel.java      |  24 ++
 .../client/console/wizards/AjaxWizard.java      |   6 +-
 .../console/wizards/ModalPanelBuilder.java      |   4 +-
 .../client/console/wizards/WizardMgtPanel.java  |   4 +-
 .../client/console/wizards/any/ResultPage.java  |  15 +-
 .../META-INF/resources/css/syncopeConsole.css   |  16 ++
 .../META-INF/resources/css/topology.css         |  16 --
 .../notifications/MailTemplateContentModal.html |  53 ----
 .../notifications/MailTemplateModal.html        |  28 --
 .../notifications/TemplateContentModal.html     |  53 ++++
 .../console/notifications/TemplateModal.html    |  28 ++
 .../syncope/client/console/pages/Reports.html   |  19 +-
 .../client/console/pages/Reports.properties     |  18 ++
 .../client/console/pages/Reports_it.properties  |  18 ++
 .../console/pages/Reports_pt_BR.properties      |  18 ++
 .../client/console/pages/Reports_ru.properties  |  21 ++
 .../console/panels/StartAtTogglePanel.html      |  57 ++++
 .../panels/StartAtTogglePanel.properties        |  17 ++
 .../panels/StartAtTogglePanel_it.properties     |  17 ++
 .../panels/StartAtTogglePanel_pt_BR.properties  |  17 ++
 .../panels/StartAtTogglePanel_ru.properties     |  19 ++
 .../console/reports/ReportDirectoryPanel.html   |  23 ++
 .../reports/ReportDirectoryPanel.properties     |  35 +++
 .../reports/ReportDirectoryPanel_it.properties  |  35 +++
 .../ReportDirectoryPanel_pt_BR.properties       |  35 +++
 .../reports/ReportDirectoryPanel_ru.properties  |  43 +++
 .../console/reports/ReportExecutionDetails.html |  24 ++
 .../ReportTemplateDirectoryPanel.properties     |  20 ++
 .../ReportTemplateDirectoryPanel_it.properties  |  20 ++
 ...eportTemplateDirectoryPanel_pt_BR.properties |  20 ++
 .../ReportTemplateDirectoryPanel_ru.properties  |  25 ++
 .../reports/ReportWizardBuilder$Profile.html    |  25 ++
 .../ReportWizardBuilder$Profile.properties      |  19 ++
 .../ReportWizardBuilder$Profile_it.properties   |  19 ++
 ...ReportWizardBuilder$Profile_pt_BR.properties |  19 ++
 .../ReportWizardBuilder$Profile_ru.properties   |  21 ++
 .../reports/ReportWizardBuilder$Schedule.html   |  26 ++
 .../tasks/ExecutionsDirectoryPanel.properties   |  20 ++
 .../ExecutionsDirectoryPanel_it.properties      |  20 ++
 .../ExecutionsDirectoryPanel_pt_BR.properties   |  20 ++
 .../ExecutionsDirectoryPanel_ru.properties      |  25 ++
 .../console/tasks/StartAtTogglePanel.html       |  57 ----
 .../console/tasks/StartAtTogglePanel.properties |  17 --
 .../tasks/StartAtTogglePanel_it.properties      |  17 --
 .../tasks/StartAtTogglePanel_pt_BR.properties   |  17 --
 .../tasks/StartAtTogglePanel_ru.properties      |  19 --
 .../console/tasks/TaskExecutionDetails.html     |  24 --
 .../tasks/TaskExecutionDetails.properties       |  20 --
 .../tasks/TaskExecutionDetails_it.properties    |  20 --
 .../tasks/TaskExecutionDetails_pt_BR.properties |  20 --
 .../tasks/TaskExecutionDetails_ru.properties    |  25 --
 .../console/topology/TopologyTogglePanel.html   |   2 +-
 .../markup/html/form/ActionLinksPanel.html      |   7 +-
 .../panels/CamelRoutesDirectoryPanel.java       |   2 +-
 108 files changed, 2463 insertions(+), 1110 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalModal.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalModal.java b/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalModal.java
index dc0d90b..9398a5b 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalModal.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalModal.java
@@ -20,7 +20,6 @@ package org.apache.syncope.client.console.approvals;
 
 import org.apache.syncope.client.console.SyncopeConsoleSession;
 import org.apache.syncope.client.console.commons.Constants;
-import org.apache.syncope.client.console.panels.ModalPanel;
 import org.apache.syncope.client.console.panels.MultilevelPanel;
 import org.apache.syncope.client.console.rest.UserWorkflowRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
@@ -30,8 +29,10 @@ 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;
+import org.apache.syncope.client.console.panels.SubmitableModalPanel;
+import org.apache.syncope.client.console.panels.WizardModalPanel;
 
-public class ApprovalModal extends Panel implements ModalPanel<WorkflowFormTO> {
+public class ApprovalModal extends Panel implements SubmitableModalPanel, WizardModalPanel<WorkflowFormTO> {
 
     private static final long serialVersionUID = -8847854414429745216L;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/bulk/BulkActionModal.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/bulk/BulkActionModal.java b/client/console/src/main/java/org/apache/syncope/client/console/bulk/BulkActionModal.java
index 033ee0a..17cf48d 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/bulk/BulkActionModal.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/bulk/BulkActionModal.java
@@ -22,7 +22,7 @@ import java.io.Serializable;
 import java.util.Collection;
 import java.util.List;
 import org.apache.syncope.client.console.panels.AbstractModalPanel;
-import org.apache.syncope.client.console.rest.BaseRestClient;
+import org.apache.syncope.client.console.rest.RestClient;
 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.wicket.PageReference;
@@ -38,7 +38,7 @@ public class BulkActionModal<T extends Serializable, S> extends AbstractModalPan
             final Collection<T> items,
             final List<IColumn<T, S>> columns,
             final Collection<ActionLink.ActionType> actions,
-            final BaseRestClient bulkActionExecutor,
+            final RestClient bulkActionExecutor,
             final String keyFieldName) {
 
         super(modal, pageRef);

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/bulk/BulkContent.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/bulk/BulkContent.java b/client/console/src/main/java/org/apache/syncope/client/console/bulk/BulkContent.java
index 5110119..8bbd088 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/bulk/BulkContent.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/bulk/BulkContent.java
@@ -31,7 +31,7 @@ import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.commons.status.StatusBean;
 import org.apache.syncope.client.console.panels.MultilevelPanel;
 import org.apache.syncope.client.console.rest.AbstractAnyRestClient;
-import org.apache.syncope.client.console.rest.BaseRestClient;
+import org.apache.syncope.client.console.rest.RestClient;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.BulkActionResultColumn;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
@@ -64,7 +64,7 @@ public class BulkContent<T extends Serializable, S> extends MultilevelPanel.Seco
             final Collection<T> items,
             final List<IColumn<T, S>> columns,
             final Collection<ActionLink.ActionType> actions,
-            final BaseRestClient bulkActionExecutor,
+            final RestClient bulkActionExecutor,
             final String keyFieldName) {
 
         this(MultilevelPanel.SECOND_LEVEL_ID, modal, items, columns, actions, bulkActionExecutor, keyFieldName);
@@ -76,7 +76,7 @@ public class BulkContent<T extends Serializable, S> extends MultilevelPanel.Seco
             final Collection<T> items,
             final List<IColumn<T, S>> columns,
             final Collection<ActionLink.ActionType> actions,
-            final BaseRestClient bulkActionExecutor,
+            final RestClient bulkActionExecutor,
             final String keyFieldName) {
 
         super(id);
@@ -143,8 +143,8 @@ public class BulkContent<T extends Serializable, S> extends MultilevelPanel.Seco
                                 throw new IllegalArgumentException("Invalid bulk action executor");
                             }
 
-                            final AbstractAnyRestClient<?> anyRestClient =
-                                    AbstractAnyRestClient.class.cast(bulkActionExecutor);
+                            final AbstractAnyRestClient<?> anyRestClient = AbstractAnyRestClient.class.cast(
+                                    bulkActionExecutor);
 
                             if (items.isEmpty() || !(items.iterator().next() instanceof StatusBean)) {
                                 throw new IllegalArgumentException("Invalid items");

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateContentModal.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateContentModal.java b/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateContentModal.java
deleted file mode 100644
index 55804cb..0000000
--- a/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateContentModal.java
+++ /dev/null
@@ -1,120 +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.notifications;
-
-import java.io.Serializable;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.console.SyncopeConsoleSession;
-import org.apache.syncope.client.console.commons.Constants;
-import org.apache.syncope.client.console.panels.AbstractModalPanel;
-import org.apache.syncope.client.console.rest.NotificationRestClient;
-import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
-import org.apache.syncope.common.lib.types.MailTemplateFormat;
-import org.apache.wicket.PageReference;
-import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.markup.head.IHeaderResponse;
-import org.apache.wicket.markup.head.OnLoadHeaderItem;
-import org.apache.wicket.markup.html.form.Form;
-import org.apache.wicket.markup.html.form.TextArea;
-import org.apache.wicket.model.PropertyModel;
-
-public class MailTemplateContentModal extends AbstractModalPanel<Serializable> {
-
-    private static final long serialVersionUID = 2053048734388383021L;
-
-    private final MailTemplateContent content;
-
-    public MailTemplateContentModal(
-            final BaseModal<Serializable> modal,
-            final MailTemplateContent content,
-            final PageReference pageRef) {
-
-        super(modal, pageRef);
-        this.content = content;
-
-        TextArea<String> templateDefArea = new TextArea<>("template", new PropertyModel<String>(content, "content"));
-        templateDefArea.setMarkupId("template").setOutputMarkupPlaceholderTag(true);
-        add(templateDefArea);
-    }
-
-    @Override
-    public void renderHead(final IHeaderResponse response) {
-        super.renderHead(response);
-        response.render(OnLoadHeaderItem.forScript(
-                "CodeMirror.fromTextArea(document.getElementById('template'), {"
-                + "  lineNumbers: true, "
-                + "  lineWrapping: true, "
-                + "  autoCloseTags: true, "
-                + "  mode: 'text/html', "
-                + "  autoRefresh: true"
-                + "}).on('change', updateTextArea);"));
-    }
-
-    @Override
-    public MailTemplateContent getItem() {
-        return this.content;
-    }
-
-    @Override
-    public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
-        try {
-            new NotificationRestClient().updateTemplateFormat(
-                    content.getKey(), content.getContent(), content.getFormat());
-            info(getString(Constants.OPERATION_SUCCEEDED));
-            modal.show(false);
-            modal.close(target);
-        } catch (Exception e) {
-            LOG.error("While updating template for {}", content.getKey(), e);
-            error(StringUtils.isBlank(e.getMessage()) ? e.getClass().getName() : e.getMessage());
-        }
-        SyncopeConsoleSession.get().getNotificationPanel().refresh(target);
-    }
-
-    public static class MailTemplateContent implements Serializable {
-
-        private static final long serialVersionUID = -1756961687134322845L;
-
-        private final String key;
-
-        private String content;
-
-        private final MailTemplateFormat format;
-
-        public MailTemplateContent(final String key, final MailTemplateFormat format) {
-            this.key = key;
-            this.format = format;
-        }
-
-        public String getKey() {
-            return key;
-        }
-
-        public String getContent() {
-            return content;
-        }
-
-        public void setContent(final String content) {
-            this.content = content;
-        }
-
-        public MailTemplateFormat getFormat() {
-            return format;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java
index a781f4c..2b9d072 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java
@@ -32,7 +32,6 @@ import org.apache.syncope.client.console.commons.DirectoryDataProvider;
 import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
 import org.apache.syncope.client.console.notifications.MailTemplateDirectoryPanel.MailTemplateProvider;
 import org.apache.syncope.client.console.panels.DirectoryPanel;
-import org.apache.syncope.client.console.panels.ModalPanel;
 import org.apache.syncope.client.console.rest.NotificationRestClient;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
@@ -54,6 +53,7 @@ import org.apache.wicket.model.AbstractReadOnlyModel;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.ResourceModel;
 import org.apache.wicket.model.StringResourceModel;
+import org.apache.syncope.client.console.panels.WizardModalPanel;
 
 public class MailTemplateDirectoryPanel
         extends DirectoryPanel<MailTemplateTO, MailTemplateTO, MailTemplateProvider, NotificationRestClient> {
@@ -75,16 +75,18 @@ public class MailTemplateDirectoryPanel
         utilityModal.size(Modal.Size.Large);
         utilityModal.addSubmitButton();
 
+        restClient = new NotificationRestClient();
         addNewItemPanelBuilder(new AbstractModalPanelBuilder<MailTemplateTO>(new MailTemplateTO(), pageRef) {
 
             private static final long serialVersionUID = 1995192603527154740L;
 
             @Override
-            public ModalPanel<MailTemplateTO> build(final String id, final int index, final AjaxWizard.Mode mode) {
-                return new MailTemplateModal(modal, new MailTemplateTO(), pageReference);
+            public WizardModalPanel<MailTemplateTO> build(
+                    final String id, final int index, final AjaxWizard.Mode mode) {
+                return new TemplateModal<MailTemplateTO, MailTemplateFormat>(
+                        modal, restClient, new MailTemplateTO(), pageReference);
             }
         }, true);
-        restClient = new NotificationRestClient();
 
         initResultTable();
 
@@ -113,14 +115,15 @@ public class MailTemplateDirectoryPanel
 
                     @Override
                     public void onClick(final AjaxRequestTarget target, final MailTemplateTO ignore) {
-                        MailTemplateContentModal.MailTemplateContent content =
-                                new MailTemplateContentModal.MailTemplateContent(
+                        TemplateContentModal.TemplateContent<MailTemplateFormat> content
+                                = new TemplateContentModal.TemplateContent<MailTemplateFormat>(
                                         model.getObject().getKey(), MailTemplateFormat.HTML);
                         content.setContent(
                                 restClient.readTemplateFormat(model.getObject().getKey(), MailTemplateFormat.HTML));
 
                         utilityModal.header(new ResourceModel("mail.template.html", "HTML Content"));
-                        utilityModal.setContent(new MailTemplateContentModal(utilityModal, content, pageRef));
+                        utilityModal.setContent(new TemplateContentModal<MailTemplateTO, MailTemplateFormat>(
+                                utilityModal, restClient, content, pageRef));
                         utilityModal.show(true);
                         target.add(utilityModal);
                     }
@@ -132,15 +135,16 @@ public class MailTemplateDirectoryPanel
 
                     @Override
                     public void onClick(final AjaxRequestTarget target, final MailTemplateTO ignore) {
-                        MailTemplateContentModal.MailTemplateContent content =
-                                new MailTemplateContentModal.MailTemplateContent(
+                        TemplateContentModal.TemplateContent<MailTemplateFormat> content
+                                = new TemplateContentModal.TemplateContent<MailTemplateFormat>(
                                         model.getObject().getKey(), MailTemplateFormat.TEXT);
                         content.setContent(
                                 restClient.readTemplateFormat(model.getObject().getKey(), MailTemplateFormat.TEXT));
 
                         utilityModal.setFormModel(content);
                         utilityModal.header(new ResourceModel("mail.template.text", "TEXT Content"));
-                        utilityModal.setContent(new MailTemplateContentModal(utilityModal, content, pageRef));
+                        utilityModal.setContent(new TemplateContentModal<MailTemplateTO, MailTemplateFormat>(
+                                utilityModal, restClient, content, pageRef));
                         utilityModal.show(true);
                         target.add(utilityModal);
                     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateModal.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateModal.java b/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateModal.java
deleted file mode 100644
index 69ec7aa..0000000
--- a/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateModal.java
+++ /dev/null
@@ -1,72 +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.notifications;
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.syncope.client.console.SyncopeConsoleSession;
-import org.apache.syncope.client.console.commons.Constants;
-import org.apache.syncope.client.console.panels.AbstractModalPanel;
-import org.apache.syncope.client.console.rest.NotificationRestClient;
-import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
-import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
-import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.to.MailTemplateTO;
-import org.apache.wicket.PageReference;
-import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.markup.html.form.Form;
-import org.apache.wicket.model.PropertyModel;
-
-public class MailTemplateModal extends AbstractModalPanel<MailTemplateTO> {
-
-    private static final long serialVersionUID = 2053048734388383021L;
-
-    private final MailTemplateTO mailTemplateTO;
-
-    public MailTemplateModal(
-            final BaseModal<MailTemplateTO> modal,
-            final MailTemplateTO mailTemplateTO,
-            final PageReference pageRef) {
-        super(modal, pageRef);
-        this.mailTemplateTO = mailTemplateTO;
-
-        final AjaxTextFieldPanel key
-                = new AjaxTextFieldPanel("key", "key", new PropertyModel<String>(mailTemplateTO, "key"), false);
-        key.setOutputMarkupPlaceholderTag(true);
-        add(key.setRenderBodyOnly(true));
-    }
-
-    @Override
-    public MailTemplateTO getItem() {
-        return this.mailTemplateTO;
-    }
-
-    @Override
-    public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
-        try {
-            new NotificationRestClient().createTemplate(mailTemplateTO);
-            info(getString(Constants.OPERATION_SUCCEEDED));
-            modal.show(false);
-            modal.close(target);
-        } catch (SyncopeClientException e) {
-            LOG.error("While creating template for {}", mailTemplateTO.getKey(), e);
-            error(StringUtils.isBlank(e.getMessage()) ? e.getClass().getName() : e.getMessage());
-        }
-        SyncopeConsoleSession.get().getNotificationPanel().refresh(target);
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationTasks.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationTasks.java b/client/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationTasks.java
index 4d24824..68d2553 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationTasks.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/notifications/NotificationTasks.java
@@ -18,23 +18,20 @@
  */
 package org.apache.syncope.client.console.notifications;
 
-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.tasks.NotificationTaskDirectoryPanel;
 import org.apache.syncope.client.console.tasks.TaskExecutionDetails;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
-import org.apache.syncope.common.lib.to.NotificationTO;
 import org.apache.syncope.common.lib.to.NotificationTaskTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 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;
 import org.apache.wicket.model.Model;
 import org.apache.wicket.model.StringResourceModel;
 
-public class NotificationTasks extends Panel implements ModalPanel<Serializable> {
+public class NotificationTasks extends Panel implements ModalPanel {
 
     private static final long serialVersionUID = 1066124171682570083L;
 
@@ -75,20 +72,4 @@ public class NotificationTasks extends Panel implements ModalPanel<Serializable>
             }
         });
     }
-
-    @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 NotificationTO getItem() {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/notifications/TemplateContentModal.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/notifications/TemplateContentModal.java b/client/console/src/main/java/org/apache/syncope/client/console/notifications/TemplateContentModal.java
new file mode 100644
index 0000000..416475d
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/notifications/TemplateContentModal.java
@@ -0,0 +1,124 @@
+/*
+ * 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.notifications;
+
+import java.io.Serializable;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.panels.AbstractModalPanel;
+import org.apache.syncope.client.console.rest.TemplateRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.common.lib.to.EntityTO;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.OnLoadHeaderItem;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.TextArea;
+import org.apache.wicket.model.PropertyModel;
+
+public class TemplateContentModal<T extends EntityTO, F> extends AbstractModalPanel<Serializable> {
+
+    private static final long serialVersionUID = 2053048734388383021L;
+
+    private final TemplateContent<F> content;
+
+    private final TemplateRestClient<T, F> restClient;
+
+    public TemplateContentModal(
+            final BaseModal<Serializable> modal,
+            final TemplateRestClient<T, F> restClient,
+            final TemplateContent<F> content,
+            final PageReference pageRef) {
+
+        super(modal, pageRef);
+        this.restClient = restClient;
+        this.content = content;
+
+        TextArea<String> templateDefArea = new TextArea<>("template", new PropertyModel<String>(content, "content"));
+        templateDefArea.setMarkupId("template").setOutputMarkupPlaceholderTag(true);
+        add(templateDefArea);
+    }
+
+    @Override
+    public void renderHead(final IHeaderResponse response) {
+        super.renderHead(response);
+        response.render(OnLoadHeaderItem.forScript(
+                "CodeMirror.fromTextArea(document.getElementById('template'), {"
+                + "  lineNumbers: true, "
+                + "  lineWrapping: true, "
+                + "  autoCloseTags: true, "
+                + "  mode: 'text/html', "
+                + "  autoRefresh: true"
+                + "}).on('change', updateTextArea);"));
+    }
+
+    @Override
+    public TemplateContent<F> getItem() {
+        return this.content;
+    }
+
+    @Override
+    public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+        try {
+            restClient.updateTemplateFormat(
+                    content.getKey(), content.getContent(), content.getFormat());
+            info(getString(Constants.OPERATION_SUCCEEDED));
+            modal.show(false);
+            modal.close(target);
+        } catch (Exception e) {
+            LOG.error("While updating template for {}", content.getKey(), e);
+            error(StringUtils.isBlank(e.getMessage()) ? e.getClass().getName() : e.getMessage());
+        }
+        SyncopeConsoleSession.get().getNotificationPanel().refresh(target);
+    }
+
+    public static class TemplateContent<F> implements Serializable {
+
+        private static final long serialVersionUID = -1756961687134322845L;
+
+        private final String key;
+
+        private String content;
+
+        private final F format;
+
+        public TemplateContent(final String key, final F format) {
+            this.key = key;
+            this.format = format;
+        }
+
+        public String getKey() {
+            return key;
+        }
+
+        public String getContent() {
+            return content;
+        }
+
+        public void setContent(final String content) {
+            this.content = content;
+        }
+
+        public F getFormat() {
+            return format;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/notifications/TemplateModal.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/notifications/TemplateModal.java b/client/console/src/main/java/org/apache/syncope/client/console/notifications/TemplateModal.java
new file mode 100644
index 0000000..aa85776
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/notifications/TemplateModal.java
@@ -0,0 +1,76 @@
+/*
+ * 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.notifications;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.panels.AbstractModalPanel;
+import org.apache.syncope.client.console.rest.TemplateRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.EntityTO;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.PropertyModel;
+
+public class TemplateModal<T extends EntityTO, F> extends AbstractModalPanel<T> {
+
+    private static final long serialVersionUID = 2053048734388383021L;
+
+    private final T templateTO;
+
+    private TemplateRestClient<T, F> restClient;
+
+    public TemplateModal(
+            final BaseModal<T> modal,
+            final TemplateRestClient<T, F> restClient,
+            final T templateTO,
+            final PageReference pageRef) {
+        super(modal, pageRef);
+        this.restClient = restClient;
+        this.templateTO = templateTO;
+
+        final AjaxTextFieldPanel key
+                = new AjaxTextFieldPanel("key", "key", new PropertyModel<String>(templateTO, "key"), false);
+        key.setOutputMarkupPlaceholderTag(true);
+        add(key.setRenderBodyOnly(true));
+    }
+
+    @Override
+    public T getItem() {
+        return this.templateTO;
+    }
+
+    @Override
+    public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+        try {
+            restClient.createTemplate(templateTO);
+            info(getString(Constants.OPERATION_SUCCEEDED));
+            modal.show(false);
+            modal.close(target);
+        } catch (SyncopeClientException e) {
+            LOG.error("While creating template for {}", templateTO.getKey(), e);
+            error(StringUtils.isBlank(e.getMessage()) ? e.getClass().getName() : e.getMessage());
+        }
+        SyncopeConsoleSession.get().getNotificationPanel().refresh(target);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/pages/Reports.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/Reports.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/Reports.java
index f089554..c01da4c 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/pages/Reports.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/Reports.java
@@ -18,7 +18,23 @@
  */
 package org.apache.syncope.client.console.pages;
 
+import de.agilecoders.wicket.core.markup.html.bootstrap.tabs.AjaxBootstrapTabbedPanel;
+import java.util.ArrayList;
+import java.util.List;
 import org.apache.syncope.client.console.BookmarkablePageLinkBuilder;
+import org.apache.syncope.client.console.panels.MultilevelPanel;
+import org.apache.syncope.client.console.reports.ReportDirectoryPanel;
+import org.apache.syncope.client.console.reports.ReportExecutionDetails;
+import org.apache.syncope.client.console.reports.ReportTemplateDirectoryPanel;
+import org.apache.syncope.common.lib.to.ReportTO;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+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.ResourceModel;
+import org.apache.wicket.model.StringResourceModel;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 
 public class Reports extends BasePage {
@@ -29,5 +45,49 @@ public class Reports extends BasePage {
         super(parameters);
 
         body.add(BookmarkablePageLinkBuilder.build("dashboard", "dashboardBr", Dashboard.class));
+
+        WebMarkupContainer content = new WebMarkupContainer("content");
+        content.setOutputMarkupId(true);
+        content.setMarkupId("reports");
+        content.add(new AjaxBootstrapTabbedPanel<>("tabbedPanel", buildTabList()));
+        body.add(content);
+    }
+
+    private List<ITab> buildTabList() {
+        final List<ITab> tabs = new ArrayList<>();
+
+        tabs.add(new AbstractTab(new ResourceModel("reports")) {
+
+            private static final long serialVersionUID = -6815067322125799251L;
+
+            @Override
+            public Panel getPanel(final String panelId) {
+                final MultilevelPanel mlp = new MultilevelPanel(panelId);
+                mlp.setFirstLevel(new ReportDirectoryPanel(mlp, getPageReference()) {
+
+                    private static final long serialVersionUID = -2195387360323687302L;
+
+                    @Override
+                    protected void viewTask(final ReportTO reportTO, final AjaxRequestTarget target) {
+                        mlp.next(
+                                new StringResourceModel("report.view", this, new Model<>(reportTO)).getObject(),
+                                new ReportExecutionDetails(reportTO, getPageReference()),
+                                target);
+                    }
+                });
+                return mlp;
+            }
+        });
+
+        tabs.add(new AbstractTab(new ResourceModel("report.templates")) {
+
+            private static final long serialVersionUID = -6815067322125799251L;
+
+            @Override
+            public Panel getPanel(final String panelId) {
+                return new ReportTemplateDirectoryPanel(panelId, getPageReference());
+            }
+        });
+        return tabs;
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractModalPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractModalPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractModalPanel.java
index c69f2b1..fe84533 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractModalPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractModalPanel.java
@@ -32,7 +32,8 @@ import org.apache.wicket.markup.html.panel.Panel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class AbstractModalPanel<T extends Serializable> extends Panel implements ModalPanel<T> {
+public class AbstractModalPanel<T extends Serializable> extends Panel
+        implements SubmitableModalPanel, WizardModalPanel<T> {
 
     private static final long serialVersionUID = 8611724965544132636L;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/panels/AjaxDataTablePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AjaxDataTablePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AjaxDataTablePanel.java
index 017659b..e06090a 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AjaxDataTablePanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AjaxDataTablePanel.java
@@ -30,6 +30,7 @@ import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxFormChoic
 import org.apache.syncope.client.console.bulk.BulkActionModal;
 import org.apache.syncope.client.console.bulk.BulkContent;
 import org.apache.syncope.client.console.panels.DirectoryPanel.EventDataWrapper;
+import org.apache.syncope.client.console.rest.RestClient;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.CheckGroupColumn;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.AjaxFallbackDataTable;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
@@ -65,7 +66,7 @@ public final class AjaxDataTablePanel<T extends Serializable, S> extends DataTab
 
         private final Collection<ActionLink.ActionType> bulkActions = new ArrayList<>();
 
-        private BaseRestClient bulkActionExecutor;
+        private RestClient bulkActionExecutor;
 
         private String itemKeyField;
 
@@ -108,7 +109,7 @@ public final class AjaxDataTablePanel<T extends Serializable, S> extends DataTab
 
         public Builder<T, S> setBulkActions(
                 final Collection<ActionLink.ActionType> bulkActions,
-                final BaseRestClient bulkActionExecutor,
+                final RestClient bulkActionExecutor,
                 final String itemKeyField) {
             this.bulkActions.clear();
             if (bulkActions != null) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/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 fdfbc65..c393285 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
@@ -64,7 +64,8 @@ public class AnyTypeClassesPanel extends TypesDirectoryPanel<AnyTypeClassTO, Any
             private static final long serialVersionUID = -6388405037134399367L;
 
             @Override
-            public ModalPanel<AnyTypeClassTO> build(final String id, final int index, final AjaxWizard.Mode mode) {
+            public WizardModalPanel<AnyTypeClassTO> build(
+                    final String id, final int index, final AjaxWizard.Mode mode) {
                 final AnyTypeClassTO modelObject = newModelObject();
                 return new AnyTypeClassModalPanel(modal, modelObject, pageRef) {
 
@@ -88,6 +89,7 @@ public class AnyTypeClassesPanel extends TypesDirectoryPanel<AnyTypeClassTO, Any
                     }
                 };
             }
+
         }, true);
 
         initResultTable();

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypesPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypesPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypesPanel.java
index 6b3c042..6c1d71a 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypesPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyTypesPanel.java
@@ -65,7 +65,7 @@ public class AnyTypesPanel extends TypesDirectoryPanel<AnyTypeTO, AnyTypeProvide
             private static final long serialVersionUID = -6388405037134399367L;
 
             @Override
-            public ModalPanel<AnyTypeTO> build(final String id, final int index, final AjaxWizard.Mode mode) {
+            public WizardModalPanel<AnyTypeTO> build(final String id, final int index, final AjaxWizard.Mode mode) {
                 final AnyTypeTO modelObject = newModelObject();
                 return new AnyTypeModalPanel(modal, modelObject, pageRef) {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDirectoryPanel.java
index 056e7fd..99dde2e 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjectDirectoryPanel.java
@@ -41,14 +41,13 @@ 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.markup.html.form.Form;
 import org.apache.wicket.model.CompoundPropertyModel;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.ResourceModel;
 
 public abstract class ConnObjectDirectoryPanel
         extends DirectoryPanel<ConnObjectTO, ConnObjectTO, ConnObjectDataProvider, ResourceRestClient>
-        implements ModalPanel<ConnObjectTO> {
+        implements ModalPanel {
 
     private static final long serialVersionUID = 4986172040062752781L;
 
@@ -84,21 +83,6 @@ public abstract class ConnObjectDirectoryPanel
     }
 
     @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 ConnObjectTO getItem() {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
-
-    @Override
     protected ConnObjectDataProvider dataProvider() {
         return new ConnObjectDataProvider(rows);
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjects.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjects.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjects.java
index 3317315..f261ddc 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjects.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ConnObjects.java
@@ -18,7 +18,6 @@
  */
 package org.apache.syncope.client.console.panels;
 
-import java.io.Serializable;
 import java.util.ArrayList;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.Transformer;
@@ -32,12 +31,11 @@ import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
-import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.Model;
 import org.apache.wicket.model.StringResourceModel;
 
-public class ConnObjects extends Panel implements ModalPanel<Serializable> {
+public class ConnObjects extends Panel implements ModalPanel {
 
     private static final long serialVersionUID = -1143512993584984838L;
 
@@ -96,21 +94,6 @@ public class ConnObjects extends Panel implements ModalPanel<Serializable> {
         });
     }
 
-    @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.");
-    }
-
     private class NextableConnObjectDirectoryPanel extends ConnObjectDirectoryPanel {
 
         private static final long serialVersionUID = 956427874406567048L;

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/panels/DirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/DirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/DirectoryPanel.java
index 4207df4..b31d297 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/DirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/DirectoryPanel.java
@@ -26,7 +26,7 @@ import org.apache.syncope.client.console.PreferenceManager;
 import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.commons.DirectoryDataProvider;
 import org.apache.syncope.client.console.pages.BasePage;
-import org.apache.syncope.client.console.rest.BaseRestClient;
+import org.apache.syncope.client.console.rest.RestClient;
 import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
@@ -44,7 +44,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public abstract class DirectoryPanel<
-        T extends Serializable, W extends Serializable, DP extends DirectoryDataProvider<T>, E extends BaseRestClient>
+        T extends Serializable, W extends Serializable, DP extends DirectoryDataProvider<T>, E extends RestClient>
         extends WizardMgtPanel<W> {
 
     private static final long serialVersionUID = -9170191461250434024L;
@@ -309,7 +309,7 @@ public abstract class DirectoryPanel<
 
     protected abstract Collection<ActionLink.ActionType> getBulkActions();
 
-    public abstract static class Builder<T extends Serializable, W extends Serializable, E extends BaseRestClient>
+    public abstract static class Builder<T extends Serializable, W extends Serializable, E extends RestClient>
             extends WizardMgtPanel.Builder<W> {
 
         private static final long serialVersionUID = 5088962796986706805L;

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/panels/FailureMessageModal.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/FailureMessageModal.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/FailureMessageModal.java
index ecf64c9..5aac8b3 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/FailureMessageModal.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/FailureMessageModal.java
@@ -21,13 +21,11 @@ package org.apache.syncope.client.console.panels;
 import java.io.Serializable;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
 import org.apache.wicket.PageReference;
-import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.markup.html.basic.Label;
-import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.Model;
 
-public class FailureMessageModal<T extends Serializable> extends Panel implements ModalPanel<T> {
+public class FailureMessageModal<T extends Serializable> extends Panel implements ModalPanel {
 
     private static final long serialVersionUID = 9216117990503199258L;
 
@@ -41,19 +39,4 @@ public class FailureMessageModal<T extends Serializable> extends Panel implement
         }
         add(executionFailureMessage.setOutputMarkupId(true));
     }
-
-    @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 T getItem() {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/panels/ModalPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ModalPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ModalPanel.java
index ef1e015..eb6df35 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ModalPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ModalPanel.java
@@ -19,15 +19,7 @@
 package org.apache.syncope.client.console.panels;
 
 import java.io.Serializable;
-import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.request.component.IRequestableComponent;
 
-public interface ModalPanel<T extends Serializable> extends IRequestableComponent, Serializable {
-
-    void onSubmit(AjaxRequestTarget target, Form<?> form);
-
-    void onError(AjaxRequestTarget target, Form<?> form);
-
-    T getItem();
+public interface ModalPanel extends IRequestableComponent, Serializable {
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/panels/ParametersPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/ParametersPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/ParametersPanel.java
index 5c83530..32cbe72 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/ParametersPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/ParametersPanel.java
@@ -100,7 +100,7 @@ public class ParametersPanel extends DirectoryPanel<
             private static final long serialVersionUID = 1995192603527154740L;
 
             @Override
-            public ModalPanel<AttrTO> build(final String id, final int index, final AjaxWizard.Mode mode) {
+            public WizardModalPanel<AttrTO> build(final String id, final int index, final AjaxWizard.Mode mode) {
                 return new ParametersCreateModalPanel(modal, newModelObject(), pageRef);
             }
         }, true);

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipTypesPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipTypesPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipTypesPanel.java
index 314ce42..1eabedb 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipTypesPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RelationshipTypesPanel.java
@@ -66,7 +66,8 @@ public class RelationshipTypesPanel extends TypesDirectoryPanel<RelationshipType
             private static final long serialVersionUID = -6388405037134399367L;
 
             @Override
-            public ModalPanel<RelationshipTypeTO> build(final String id, final int index, final AjaxWizard.Mode mode) {
+            public WizardModalPanel<RelationshipTypeTO> build(
+                    final String id, final int index, final AjaxWizard.Mode mode) {
                 final RelationshipTypeTO modelObject = newModelObject();
                 return new RelationshipTypeModalPanel(modal, modelObject, pageRef) {
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/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 7d61e47..9c2094f 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
@@ -94,7 +94,7 @@ public class SchemaTypePanel extends TypesDirectoryPanel<AbstractSchemaTO, Schem
                 private static final long serialVersionUID = -6388405037134399367L;
 
                 @Override
-                public ModalPanel<AbstractSchemaTO> build(
+                public WizardModalPanel<AbstractSchemaTO> build(
                         final String id, final int index, final AjaxWizard.Mode mode) {
                     final AbstractSchemaTO modelObject = newModelObject();
                     return new SchemaModalPanel(modal, modelObject, pageRef) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/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 50ae8c9..be9cdf1 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
@@ -74,7 +74,8 @@ public class SecurityQuestionsPanel extends DirectoryPanel<
             private static final long serialVersionUID = -6388405037134399367L;
 
             @Override
-            public ModalPanel<SecurityQuestionTO> build(final String id, final int index, final AjaxWizard.Mode mode) {
+            public WizardModalPanel<SecurityQuestionTO> build(
+                    final String id, final int index, final AjaxWizard.Mode mode) {
                 final SecurityQuestionTO modelObject = newModelObject();
                 return new SecurityQuestionsModalPanel(modal, modelObject, pageRef);
             }

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/panels/StartAtTogglePanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/StartAtTogglePanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/StartAtTogglePanel.java
new file mode 100644
index 0000000..bae12a6
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/StartAtTogglePanel.java
@@ -0,0 +1,105 @@
+/*
+ * 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 java.io.Serializable;
+import java.util.Date;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.rest.ExecutionRestClient;
+import org.apache.syncope.client.console.wicket.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
+import org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
+import org.apache.syncope.client.console.wicket.markup.html.form.DateTimeFieldPanel;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxSubmitLink;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.Model;
+
+public abstract class StartAtTogglePanel extends TogglePanel<Serializable> {
+
+    private static final long serialVersionUID = -3195479265440591519L;
+
+    private String key = null;
+
+    public StartAtTogglePanel(final WebMarkupContainer container) {
+        super("startAt");
+
+        final Form<?> form = new Form<>("startAtForm");
+        addInnerObject(form);
+
+        final Model<Date> startAtDateModel = new Model<>();
+
+        final DateTimeFieldPanel startAtDate = new DateTimeFieldPanel(
+                "startAtDate", "startAtDate", startAtDateModel, SyncopeConstants.DATE_PATTERNS[3]);
+
+        startAtDate.setReadOnly(true).hideLabel();
+        form.add(startAtDate);
+
+        final AjaxCheckBoxPanel startAtCheck = new AjaxCheckBoxPanel(
+                "startAtCheck", "startAtCheck", new Model<>(false), false);
+
+        form.add(startAtCheck);
+
+        startAtCheck.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                target.add(startAtDate.setModelObject(null).setReadOnly(!startAtCheck.getModelObject()));
+            }
+        });
+
+        form.add(new AjaxSubmitLink("startAt", form) {
+
+            private static final long serialVersionUID = -7978723352517770644L;
+
+            @Override
+            protected void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+                try {
+                    getRestClient().startExecution(key, startAtDateModel.getObject());
+                    info(getString(Constants.OPERATION_SUCCEEDED));
+                    toggle(target, false);
+                    target.add(container);
+                } catch (SyncopeClientException e) {
+                    error(StringUtils.isBlank(e.getMessage()) ? e.getClass().getName() : e.getMessage());
+                    LOG.error("While running propagation task {}", key, e);
+                }
+                SyncopeConsoleSession.get().getNotificationPanel().refresh(target);
+            }
+
+            @Override
+            protected void onError(final AjaxRequestTarget target, final Form<?> form) {
+                SyncopeConsoleSession.get().getNotificationPanel().refresh(target);
+            }
+
+        });
+    }
+
+    public void setExecutionDetail(final String key, final String header, final AjaxRequestTarget target) {
+        this.key = key;
+        setHeader(target, header);
+    }
+
+    protected abstract ExecutionRestClient getRestClient();
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/panels/SubmitableModalPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/SubmitableModalPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/SubmitableModalPanel.java
new file mode 100644
index 0000000..a7ce5dd
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/SubmitableModalPanel.java
@@ -0,0 +1,29 @@
+/*
+ * 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.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.html.form.Form;
+
+public interface SubmitableModalPanel extends ModalPanel {
+
+    void onSubmit(final AjaxRequestTarget target, final Form<?> form);
+
+    void onError(final AjaxRequestTarget target, final Form<?> form);
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/panels/TypeExtensionDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/TypeExtensionDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/TypeExtensionDirectoryPanel.java
index f2a32c2..17a8535 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/TypeExtensionDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/TypeExtensionDirectoryPanel.java
@@ -54,7 +54,7 @@ import org.apache.wicket.model.StringResourceModel;
 
 public class TypeExtensionDirectoryPanel
         extends DirectoryPanel<TypeExtensionTO, TypeExtensionTO, TypeExtensionDataProvider, BaseRestClient>
-        implements ModalPanel<Serializable> {
+        implements SubmitableModalPanel {
 
     private static final long serialVersionUID = -4117015319209624858L;
 
@@ -172,11 +172,6 @@ public class TypeExtensionDirectoryPanel
         return Collections.emptyList();
     }
 
-    @Override
-    public TypeExtensionTO getItem() {
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
-
     protected class TypeExtensionDataProvider extends DirectoryDataProvider<TypeExtensionTO> {
 
         private static final long serialVersionUID = 4533123471004692755L;

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/panels/WizardModalPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/WizardModalPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/WizardModalPanel.java
new file mode 100644
index 0000000..706e9f5
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/WizardModalPanel.java
@@ -0,0 +1,26 @@
+/*
+ * 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 java.io.Serializable;
+
+public interface WizardModalPanel<T extends Serializable> extends ModalPanel {
+
+    T getItem();
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ae52b12e/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java
new file mode 100644
index 0000000..f2055b9
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/reports/ReportDirectoryPanel.java
@@ -0,0 +1,261 @@
+/*
+ * 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.reports;
+
+import static org.apache.wicket.Component.ENABLE;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.commons.lang3.SerializationUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.DirectoryDataProvider;
+import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
+import org.apache.syncope.client.console.panels.DirectoryPanel;
+import org.apache.syncope.client.console.panels.MultilevelPanel;
+import org.apache.syncope.client.console.rest.ReportRestClient;
+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.BooleanPropertyColumn;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.KeyPropertyColumn;
+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.client.console.wizards.AjaxWizard;
+import org.apache.syncope.common.lib.types.StandardEntitlement;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.ReportTO;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.event.Broadcast;
+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.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.model.StringResourceModel;
+
+/**
+ * Reports page.
+ */
+public abstract class ReportDirectoryPanel
+        extends DirectoryPanel<ReportTO, ReportTO, DirectoryDataProvider<ReportTO>, ReportRestClient> {
+
+    private static final long serialVersionUID = 4984337552918213290L;
+
+    private final ReportStartAtTogglePanel startAt;
+
+    protected ReportDirectoryPanel(final MultilevelPanel multiLevelPanelRef, final PageReference pageRef) {
+        super(MultilevelPanel.FIRST_LEVEL_ID, pageRef, true);
+        this.restClient = new ReportRestClient();
+
+        this.addNewItemPanelBuilder(new ReportWizardBuilder(new ReportTO(), pageRef), true);
+        MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, ENABLE, StandardEntitlement.REPORT_CREATE);
+
+        initResultTable();
+
+        startAt = new ReportStartAtTogglePanel(container);
+        addInnerObject(startAt);
+    }
+
+    @Override
+    protected List<IColumn<ReportTO, String>> getColumns() {
+        final List<IColumn<ReportTO, String>> columns = new ArrayList<>();
+
+        columns.add(new KeyPropertyColumn<ReportTO>(
+                new StringResourceModel("key", this, null), "key", "key"));
+
+        columns.add(new PropertyColumn<ReportTO, String>(new StringResourceModel(
+                "name", this, null), "name", "name"));
+
+        columns.add(new DatePropertyColumn<ReportTO>(
+                new StringResourceModel("lastExec", this, null), "lastExec", "lastExec"));
+
+        columns.add(new DatePropertyColumn<ReportTO>(
+                new StringResourceModel("nextExec", this, null), "nextExec", "nextExec"));
+
+        columns.add(new DatePropertyColumn<ReportTO>(
+                new StringResourceModel("start", this, null), "start", "start"));
+
+        columns.add(new DatePropertyColumn<ReportTO>(
+                new StringResourceModel("end", this, null), "end", "end"));
+
+        columns.add(new PropertyColumn<ReportTO, String>(
+                new StringResourceModel("latestExecStatus", this, null), "latestExecStatus", "latestExecStatus"));
+
+        columns.add(new BooleanPropertyColumn<ReportTO>(
+                new StringResourceModel("active", this, null), "active", "active"));
+
+        columns.add(new ActionColumn<ReportTO, String>(new ResourceModel("actions")) {
+
+            private static final long serialVersionUID = 2054811145491901166L;
+
+            @Override
+            public ActionLinksPanel<ReportTO> getActions(final String componentId, final IModel<ReportTO> model) {
+
+                final ReportTO reportTO = model.getObject();
+
+                final ActionLinksPanel<ReportTO> panel = ActionLinksPanel.<ReportTO>builder().
+                        add(new ActionLink<ReportTO>() {
+
+                            private static final long serialVersionUID = -3722207913631435501L;
+
+                            @Override
+                            public void onClick(final AjaxRequestTarget target, final ReportTO modelObject) {
+                                final ReportTO clone = SerializationUtils.clone(model.getObject());
+                                clone.setKey(null);
+                                send(ReportDirectoryPanel.this, Broadcast.EXACT,
+                                        new AjaxWizard.EditItemActionEvent<>(clone, target));
+                            }
+                        }, ActionLink.ActionType.CLONE, StandardEntitlement.REPORT_CREATE).
+                        add(new ActionLink<ReportTO>() {
+
+                            private static final long serialVersionUID = -3722207913631435501L;
+
+                            @Override
+                            public void onClick(final AjaxRequestTarget target, final ReportTO modelObject) {
+                                send(ReportDirectoryPanel.this, Broadcast.EXACT,
+                                        new AjaxWizard.EditItemActionEvent<>(
+                                                restClient.read(model.getObject().getKey()), target));
+                            }
+                        }, ActionLink.ActionType.EDIT, StandardEntitlement.REPORT_UPDATE).
+                        add(new ActionLink<ReportTO>() {
+
+                            private static final long serialVersionUID = -3722207913631435501L;
+
+                            @Override
+                            public void onClick(final AjaxRequestTarget target, final ReportTO modelObject) {
+                                viewTask(reportTO, target);
+                            }
+                        }, ActionLink.ActionType.VIEW, StandardEntitlement.REPORT_READ).
+                        add(new ActionLink<ReportTO>() {
+
+                            private static final long serialVersionUID = -3722207913631435501L;
+
+                            @Override
+                            public void onClick(final AjaxRequestTarget target, final ReportTO ignore) {
+                                startAt.setExecutionDetail(
+                                        model.getObject().getKey(), model.getObject().getName(), target);
+                                startAt.toggle(target, true);
+                            }
+                        }, ActionLink.ActionType.EXECUTE, StandardEntitlement.REPORT_EXECUTE).
+                        add(new ActionLink<ReportTO>() {
+
+                            private static final long serialVersionUID = -3722207913631435501L;
+
+                            @Override
+                            public void onClick(final AjaxRequestTarget target, final ReportTO modelObject) {
+                                try {
+                                    restClient.delete(reportTO.getKey());
+                                    info(getString(Constants.OPERATION_SUCCEEDED));
+                                    target.add(container);
+                                } catch (SyncopeClientException e) {
+                                    LOG.error("While deleting {}", reportTO.getKey(), e);
+                                    error(StringUtils.isBlank(e.getMessage())
+                                            ? e.getClass().getName() : e.getMessage());
+                                }
+                                SyncopeConsoleSession.get().getNotificationPanel().refresh(target);
+                            }
+                        }, ActionLink.ActionType.DELETE, StandardEntitlement.REPORT_DELETE).build(componentId);
+
+                return panel;
+            }
+
+            @Override
+            public ActionLinksPanel<ReportTO> getHeader(final String componentId) {
+                final ActionLinksPanel.Builder<ReportTO> panel = ActionLinksPanel.builder();
+
+                return panel.add(new ActionLink<ReportTO>() {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target, final ReportTO 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.EXECUTE);
+        bulkActions.add(ActionType.DELETE);
+        return bulkActions;
+    }
+
+    @Override
+    protected ReportDataProvider dataProvider() {
+        return new ReportDataProvider(rows);
+    }
+
+    @Override
+    protected String paginatorRowsKey() {
+        return Constants.PREF_PROPAGATION_TASKS_PAGINATOR_ROWS;
+    }
+
+    protected abstract void viewTask(final ReportTO reportTO, final AjaxRequestTarget target);
+
+    protected class ReportDataProvider extends DirectoryDataProvider<ReportTO> {
+
+        private static final long serialVersionUID = 4725679400450513556L;
+
+        private final SortableDataProviderComparator<ReportTO> comparator;
+
+        private final List<ReportTO> reports;
+
+        public ReportDataProvider(final int paginatorRows) {
+            super(paginatorRows);
+            this.reports = restClient.list();
+
+            //Default sorting
+            setSort("key", SortOrder.DESCENDING);
+            comparator = new SortableDataProviderComparator<>(this);
+
+            Collections.sort(this.reports, comparator);
+        }
+
+        @Override
+        public Iterator<ReportTO> iterator(final long first, final long count) {
+            return this.reports.subList((int) first, (int) (first + count)).iterator();
+        }
+
+        @Override
+        public long size() {
+            return reports.size();
+        }
+
+        @Override
+        public IModel<ReportTO> model(final ReportTO object) {
+            return new CompoundPropertyModel<>(object);
+        }
+    }
+}