You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2018/07/12 10:23:58 UTC

[2/2] syncope git commit: [SYNCOPE-1336] Pagination and sorting controls added

[SYNCOPE-1336] Pagination and sorting controls added


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

Branch: refs/heads/master
Commit: c3ce309a141379f54243f41a09a63d8ed320747a
Parents: 98f8e0e
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Jul 12 11:46:05 2018 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Jul 12 12:23:46 2018 +0200

----------------------------------------------------------------------
 .../approvals/ApprovalDirectoryPanel.java       | 19 ++---
 .../console/commons/TaskDataProvider.java       |  4 -
 .../console/rest/UserWorkflowRestClient.java    | 14 +++-
 .../client/console/widgets/AlertWidget.java     | 34 +++-----
 .../client/console/widgets/ApprovalsWidget.java | 85 +++-----------------
 .../console/widgets/RemediationsWidget.java     | 50 +-----------
 .../client/console/widgets/AlertWidget.html     |  6 +-
 .../widgets/ApprovalsWidget$InnerPanel.html     | 27 -------
 .../widgets/RemediationsWidget$InnerPanel.html  | 26 ------
 .../common/rest/api/beans/TaskQuery.java        |  1 -
 .../rest/api/beans/WorkflowFormQuery.java       | 32 ++++++++
 .../rest/api/service/UserWorkflowService.java   |  6 +-
 .../syncope/core/logic/UserWorkflowLogic.java   |  9 ++-
 .../core/persistence/jpa/dao/JPATaskDAO.java    | 18 ++---
 .../cxf/service/UserWorkflowServiceImpl.java    | 11 ++-
 .../core/workflow/api/WorkflowAdapter.java      | 11 ++-
 .../flowable/FlowableUserWorkflowAdapter.java   | 80 ++++++++++++------
 .../java/DefaultAnyObjectWorkflowAdapter.java   |  8 +-
 .../java/DefaultGroupWorkflowAdapter.java       |  8 +-
 .../java/DefaultUserWorkflowAdapter.java        |  7 +-
 .../syncope/fit/core/SchedTaskITCase.java       |  7 +-
 .../syncope/fit/core/UserWorkflowITCase.java    | 44 +++++-----
 22 files changed, 217 insertions(+), 290 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
index 81783cd..65e7124 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
@@ -29,10 +29,10 @@ 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.rest.UserWorkflowRestClient;
 import org.apache.syncope.client.console.approvals.ApprovalDirectoryPanel.ApprovalProvider;
+import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
 import org.apache.syncope.client.console.layout.FormLayoutInfoUtils;
 import org.apache.syncope.client.console.layout.UserFormLayoutInfo;
 import org.apache.syncope.client.console.pages.BasePage;
@@ -118,14 +118,15 @@ public class ApprovalDirectoryPanel
         columns.add(new PropertyColumn<>(
                 new ResourceModel("taskId"), "taskId", "taskId"));
         columns.add(new PropertyColumn<>(
-                new ResourceModel("key"), "key", "key"));
+                new ResourceModel("key"), "key"));
         columns.add(new PropertyColumn<>(
-                new ResourceModel("username"), "username", "username"));
+                new ResourceModel("username"), "username"));
         columns.add(new DatePropertyColumn<>(
                 new ResourceModel("createTime"), "createTime", "createTime"));
         columns.add(new DatePropertyColumn<>(
                 new ResourceModel("dueDate"), "dueDate", "dueDate"));
-        columns.add(new PropertyColumn<>(new ResourceModel("owner"), "owner", "owner"));
+        columns.add(new PropertyColumn<>(
+                new ResourceModel("owner"), "owner", "owner"));
 
         return columns;
     }
@@ -258,20 +259,20 @@ public class ApprovalDirectoryPanel
 
         public ApprovalProvider(final int paginatorRows) {
             super(paginatorRows);
+
             setSort("createTime", SortOrder.ASCENDING);
-            this.comparator = new SortableDataProviderComparator<>(this);
+            comparator = new SortableDataProviderComparator<>(this);
         }
 
         @Override
         public Iterator<WorkflowFormTO> iterator(final long first, final long count) {
-            final List<WorkflowFormTO> list = restClient.getForms();
-            Collections.sort(list, comparator);
-            return list.subList((int) first, (int) first + (int) count).iterator();
+            int page = ((int) first / paginatorRows);
+            return restClient.getForms((page < 0 ? 0 : page) + 1, paginatorRows, getSort()).iterator();
         }
 
         @Override
         public long size() {
-            return restClient.getForms().size();
+            return restClient.countForms();
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/client/console/src/main/java/org/apache/syncope/client/console/commons/TaskDataProvider.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/TaskDataProvider.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/TaskDataProvider.java
index 50f6fe7..b68ab42 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/TaskDataProvider.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/TaskDataProvider.java
@@ -40,10 +40,6 @@ public abstract class TaskDataProvider<T extends TaskTO> extends DirectoryDataPr
         this.taskType = taskType;
     }
 
-    public SortableDataProviderComparator<T> getComparator() {
-        return comparator;
-    }
-
     @Override
     public IModel<T> model(final T object) {
         return new CompoundPropertyModel<>(object);

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/client/console/src/main/java/org/apache/syncope/client/console/rest/UserWorkflowRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/UserWorkflowRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/UserWorkflowRestClient.java
index fc42f9b..8ccf057 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/UserWorkflowRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/UserWorkflowRestClient.java
@@ -21,14 +21,24 @@ package org.apache.syncope.client.console.rest;
 import java.util.List;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.to.WorkflowFormTO;
+import org.apache.syncope.common.rest.api.beans.WorkflowFormQuery;
 import org.apache.syncope.common.rest.api.service.UserWorkflowService;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
 
 public class UserWorkflowRestClient extends BaseRestClient {
 
     private static final long serialVersionUID = -4785231164900813921L;
 
-    public List<WorkflowFormTO> getForms() {
-        return getService(UserWorkflowService.class).getForms();
+    public int countForms() {
+        return getService(UserWorkflowService.class).
+                getForms(new WorkflowFormQuery.Builder().page(1).size(1).build()).
+                getTotalCount();
+    }
+
+    public List<WorkflowFormTO> getForms(final int page, final int size, final SortParam<String> sort) {
+        return getService(UserWorkflowService.class).
+                getForms(new WorkflowFormQuery.Builder().page(page).size(size).orderBy(toOrderBy(sort)).build()).
+                getResult();
     }
 
     public WorkflowFormTO getFormForUser(final String userKey) {

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/client/console/src/main/java/org/apache/syncope/client/console/widgets/AlertWidget.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/widgets/AlertWidget.java b/client/console/src/main/java/org/apache/syncope/client/console/widgets/AlertWidget.java
index ac32d17..f564ac8 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/widgets/AlertWidget.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/widgets/AlertWidget.java
@@ -25,8 +25,6 @@ import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.link.AbstractLink;
-import org.apache.wicket.markup.html.list.ListItem;
-import org.apache.wicket.markup.html.list.ListView;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.LoadableDetachableModel;
@@ -39,14 +37,14 @@ public abstract class AlertWidget<T extends Serializable> extends Panel {
 
     protected static final Logger LOG = LoggerFactory.getLogger(AlertWidget.class);
 
+    protected static final int MAX_SIZE = 5;
+
     protected final Label linkAlertsNumber;
 
     protected final Label headerAlertsNumber;
 
     protected final WebMarkupContainer latestAlertsList;
 
-    protected final ListView<T> latestFive;
-
     protected IModel<List<T>> latestAlerts;
 
     public AlertWidget(final String id) {
@@ -61,7 +59,7 @@ public abstract class AlertWidget<T extends Serializable> extends Panel {
 
             @Override
             protected Integer load() {
-                return AlertWidget.this.latestAlerts.getObject().size();
+                return getLatestAlertsSize();
             }
         };
 
@@ -72,7 +70,7 @@ public abstract class AlertWidget<T extends Serializable> extends Panel {
             @Override
             protected List<T> load() {
                 final List<T> latest = AlertWidget.this.latestAlerts.getObject();
-                return latest.subList(0, latest.size() < 6 ? latest.size() : 5);
+                return latest.subList(0, latest.size() <= MAX_SIZE ? latest.size() : MAX_SIZE);
             }
         };
 
@@ -98,31 +96,20 @@ public abstract class AlertWidget<T extends Serializable> extends Panel {
         headerAlertsNumber.setOutputMarkupId(true);
         add(headerAlertsNumber);
 
+        add(getEventsLink("alertsLink"));
+
         latestAlertsList = new WebMarkupContainer("latestAlertsList");
         latestAlertsList.setOutputMarkupId(true);
         add(latestAlertsList);
+    }
 
-        latestFive = new ListView<T>("latestAlerts", items) {
-
-            private static final long serialVersionUID = 4949588177564901031L;
-
-            @Override
-            protected void populateItem(final ListItem<T> item) {
-                item.add(getAlertLink("alert", item.getModelObject()).setRenderBodyOnly(true));
-            }
-        };
-        latestAlertsList.add(latestFive.setReuseItems(false).setOutputMarkupId(true));
-
-        add(getEventsLink("alertsLink"));
+    protected int getLatestAlertsSize() {
+        return latestAlerts.getObject().size();
     }
 
     protected abstract IModel<List<T>> getLatestAlerts();
 
-    protected Panel getAlertLink(final String panelid, final T alert) {
-        return new AlertLink<>(panelid, alert);
-    }
-
-    protected abstract AbstractLink getEventsLink(final String linkid);
+    protected abstract AbstractLink getEventsLink(String linkid);
 
     protected abstract Icon getIcon(String iconid);
 
@@ -135,5 +122,4 @@ public abstract class AlertWidget<T extends Serializable> extends Panel {
             add(new Label("alert", alert.toString()));
         }
     }
-
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/client/console/src/main/java/org/apache/syncope/client/console/widgets/ApprovalsWidget.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/widgets/ApprovalsWidget.java b/client/console/src/main/java/org/apache/syncope/client/console/widgets/ApprovalsWidget.java
index 9f8ac62..ee47619 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/widgets/ApprovalsWidget.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/widgets/ApprovalsWidget.java
@@ -22,10 +22,7 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.image.Icon;
 import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesomeIconTypeBuilder;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
-import java.util.stream.Collectors;
-import org.apache.commons.lang3.StringUtils;
 import org.apache.syncope.client.console.BookmarkablePageLinkBuilder;
 import org.apache.syncope.client.console.SyncopeConsoleSession;
 import org.apache.syncope.client.console.pages.Approvals;
@@ -35,17 +32,12 @@ import org.apache.syncope.common.lib.to.WorkflowFormTO;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.ajax.markup.html.AjaxLink;
 import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
-import org.apache.wicket.markup.ComponentTag;
-import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
 import org.apache.wicket.markup.html.WebPage;
-import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.link.AbstractLink;
 import org.apache.wicket.markup.html.link.BookmarkablePageLink;
-import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.IModel;
-import org.apache.wicket.model.ResourceModel;
 import org.apache.wicket.model.util.ListModel;
 import org.apache.wicket.util.time.Duration;
 
@@ -78,13 +70,13 @@ public class ApprovalsWidget extends AlertWidget<WorkflowFormTO> {
         latestAlerts.getObject().clear();
         latestAlerts.getObject().addAll(lastApprovals);
 
-        linkAlertsNumber.setDefaultModelObject(latestAlerts.getObject().size());
+        int latestAlertSize = getLatestAlertsSize();
+        linkAlertsNumber.setDefaultModelObject(latestAlertSize);
         target.add(linkAlertsNumber);
 
-        headerAlertsNumber.setDefaultModelObject(latestAlerts.getObject().size());
+        headerAlertsNumber.setDefaultModelObject(latestAlertSize);
         target.add(headerAlertsNumber);
 
-        latestFive.removeAll();
         target.add(latestAlertsList);
 
         lastApprovals.clear();
@@ -92,6 +84,14 @@ public class ApprovalsWidget extends AlertWidget<WorkflowFormTO> {
     }
 
     @Override
+    protected int getLatestAlertsSize() {
+        return SyncopeConsoleSession.get().owns(StandardEntitlement.WORKFLOW_FORM_LIST)
+                && SyncopeConsoleSession.get().owns(StandardEntitlement.WORKFLOW_FORM_READ)
+                ? restClient.countForms()
+                : 0;
+    }
+
+    @Override
     protected IModel<List<WorkflowFormTO>> getLatestAlerts() {
         return new ListModel<WorkflowFormTO>() {
 
@@ -103,9 +103,7 @@ public class ApprovalsWidget extends AlertWidget<WorkflowFormTO> {
                 if (SyncopeConsoleSession.get().owns(StandardEntitlement.WORKFLOW_FORM_LIST)
                         && SyncopeConsoleSession.get().owns(StandardEntitlement.WORKFLOW_FORM_READ)) {
 
-                    updatedApprovals = restClient.getForms().stream().
-                            sorted(Comparator.comparing(WorkflowFormTO::getCreateTime)).
-                            collect(Collectors.toList());
+                    updatedApprovals = restClient.getForms(1, MAX_SIZE, new SortParam<>("createTime", true));
                 } else {
                     updatedApprovals = Collections.<WorkflowFormTO>emptyList();
                 }
@@ -116,11 +114,6 @@ public class ApprovalsWidget extends AlertWidget<WorkflowFormTO> {
     }
 
     @Override
-    protected Panel getAlertLink(final String panelid, final WorkflowFormTO event) {
-        return new ApprovalsWidget.InnerPanel(panelid, event);
-    }
-
-    @Override
     protected AbstractLink getEventsLink(final String linkid) {
         BookmarkablePageLink<Approvals> approvals = BookmarkablePageLinkBuilder.build(linkid, Approvals.class);
         MetaDataRoleAuthorizationStrategy.authorize(approvals, WebPage.ENABLE, StandardEntitlement.WORKFLOW_FORM_LIST);
@@ -132,56 +125,4 @@ public class ApprovalsWidget extends AlertWidget<WorkflowFormTO> {
         return new Icon(iconid,
                 FontAwesomeIconTypeBuilder.on(FontAwesomeIconTypeBuilder.FontAwesomeGraphic.handshake_o).build());
     }
-
-    public static final class InnerPanel extends Panel {
-
-        private static final long serialVersionUID = 3829642687027801451L;
-
-        public InnerPanel(final String id, final WorkflowFormTO alert) {
-            super(id);
-
-            final AjaxLink<String> approval = new AjaxLink<String>("approval") {
-
-                private static final long serialVersionUID = 7021195294339489084L;
-
-                @Override
-                public void onClick(final AjaxRequestTarget target) {
-                    // do nothing
-                }
-
-                @Override
-                protected void onComponentTag(final ComponentTag tag) {
-                    super.onComponentTag(tag);
-                    if (StringUtils.isNotBlank(alert.getUsername())) {
-                        tag.put("title", alert.getUsername().trim());
-                    }
-                }
-            };
-
-            add(approval);
-
-            approval.add(new Label("key", new ResourceModel(alert.getKey(), alert.getKey())).
-                    setRenderBodyOnly(true));
-
-            approval.add(new Label("owner", alert.getOwner()));
-
-            approval.add(new Label("createTime",
-                    SyncopeConsoleSession.get().getDateFormat().format(alert.getCreateTime())).
-                    setRenderBodyOnly(true));
-
-            WebMarkupContainer dueDateContainer = new WebMarkupContainer("dueDateContainer");
-            dueDateContainer.setOutputMarkupId(true);
-            approval.add(dueDateContainer);
-
-            if (alert.getDueDate() == null) {
-                dueDateContainer.add(new Label("dueDate"));
-                dueDateContainer.setVisible(false);
-            } else {
-                dueDateContainer.add(new Label("dueDate",
-                        SyncopeConsoleSession.get().getDateFormat().format(alert.getDueDate())).
-                        setRenderBodyOnly(true));
-            }
-        }
-
-    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/client/console/src/main/java/org/apache/syncope/client/console/widgets/RemediationsWidget.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/widgets/RemediationsWidget.java b/client/console/src/main/java/org/apache/syncope/client/console/widgets/RemediationsWidget.java
index 287fdbc..79e0ec4 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/widgets/RemediationsWidget.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/widgets/RemediationsWidget.java
@@ -34,14 +34,10 @@ import org.apache.syncope.common.lib.to.RemediationTO;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
-import org.apache.wicket.ajax.markup.html.AjaxLink;
 import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
-import org.apache.wicket.markup.ComponentTag;
 import org.apache.wicket.markup.html.WebPage;
-import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.link.AbstractLink;
 import org.apache.wicket.markup.html.link.BookmarkablePageLink;
-import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.util.ListModel;
 import org.apache.wicket.util.time.Duration;
@@ -75,13 +71,13 @@ public class RemediationsWidget extends AlertWidget<RemediationTO> {
         latestAlerts.getObject().clear();
         latestAlerts.getObject().addAll(lastRemediations);
 
-        linkAlertsNumber.setDefaultModelObject(latestAlerts.getObject().size());
+        int latestAlertSize = getLatestAlertsSize();
+        linkAlertsNumber.setDefaultModelObject(latestAlertSize);
         target.add(linkAlertsNumber);
 
-        headerAlertsNumber.setDefaultModelObject(latestAlerts.getObject().size());
+        headerAlertsNumber.setDefaultModelObject(latestAlertSize);
         target.add(headerAlertsNumber);
 
-        latestFive.removeAll();
         target.add(latestAlertsList);
 
         lastRemediations.clear();
@@ -113,11 +109,6 @@ public class RemediationsWidget extends AlertWidget<RemediationTO> {
     }
 
     @Override
-    protected Panel getAlertLink(final String panelid, final RemediationTO event) {
-        return new RemediationsWidget.InnerPanel(panelid, event);
-    }
-
-    @Override
     protected AbstractLink getEventsLink(final String linkid) {
         BookmarkablePageLink<Remediations> remediations = BookmarkablePageLinkBuilder.build(linkid, Remediations.class);
         MetaDataRoleAuthorizationStrategy.authorize(remediations, WebPage.ENABLE, StandardEntitlement.REMEDIATION_LIST);
@@ -129,39 +120,4 @@ public class RemediationsWidget extends AlertWidget<RemediationTO> {
         return new Icon(iconid,
                 FontAwesomeIconTypeBuilder.on(FontAwesomeIconTypeBuilder.FontAwesomeGraphic.medkit).build());
     }
-
-    public static final class InnerPanel extends Panel {
-
-        private static final long serialVersionUID = 8074027899915634928L;
-
-        public InnerPanel(final String id, final RemediationTO alert) {
-            super(id);
-
-            AjaxLink<String> approval = new AjaxLink<String>("remediation") {
-
-                private static final long serialVersionUID = 7021195294339489084L;
-
-                @Override
-                public void onClick(final AjaxRequestTarget target) {
-                    // do nothing
-                }
-
-                @Override
-                protected void onComponentTag(final ComponentTag tag) {
-                    super.onComponentTag(tag);
-                    tag.put("title", alert.getRemoteName().trim());
-                }
-            };
-
-            add(approval);
-
-            approval.add(new Label("label", alert.getOperation().name() + " " + alert.getAnyType()));
-
-            approval.add(new Label("resource", alert.getResource()));
-
-            approval.add(new Label("instant",
-                    SyncopeConsoleSession.get().getDateFormat().format(alert.getInstant())).
-                    setRenderBodyOnly(true));
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/AlertWidget.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/AlertWidget.html b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/AlertWidget.html
index e9a6433..4d75003 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/AlertWidget.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/AlertWidget.html
@@ -27,11 +27,7 @@ under the License.
         <wicket:message key="summary"><span wicket:id="number"/></wicket:message>
       </li>
       <li>
-        <ul wicket:id="latestAlertsList" class="menu">
-          <li class="todoitem" wicket:id="latestAlerts">
-            <span wicket:id="alert">[ALERT]</span>
-          </li>
-        </ul>
+        <span wicket:id="latestAlertsList"/>
       </li>
       <li class="footer">
         <a href="#" wicket:id="alertsLink"><wicket:message key="alerts.view.all">View all alerts</wicket:message></a>

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/ApprovalsWidget$InnerPanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/ApprovalsWidget$InnerPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/ApprovalsWidget$InnerPanel.html
deleted file mode 100644
index 6976d65..0000000
--- a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/ApprovalsWidget$InnerPanel.html
+++ /dev/null
@@ -1,27 +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.
--->
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <wicket:panel>
-    <a href="#" wicket:id="approval" style="cursor: not-allowed;">
-      <h3><small class="pull-right" wicket:id="owner"/> <p wicket:id="key"/></h3>
-      <small wicket:id="dueDateContainer" class="pull-right"><i class="fa fa-hourglass-end"></i> <p wicket:id="dueDate"/></small>
-      <small><i class="fa fa-clock-o"></i> <p wicket:id="createTime"/></small>
-    </a>
-  </wicket:panel>
-</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/RemediationsWidget$InnerPanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/RemediationsWidget$InnerPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/widgets/RemediationsWidget$InnerPanel.html
deleted file mode 100644
index 3ffaa88..0000000
--- a/client/console/src/main/resources/org/apache/syncope/client/console/widgets/RemediationsWidget$InnerPanel.html
+++ /dev/null
@@ -1,26 +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.
--->
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org">
-  <wicket:panel>
-    <a href="#" wicket:id="remediation" style="cursor: not-allowed;">
-      <h3><small class="pull-right" wicket:id="resource"/> <p wicket:id="label"/></h3>
-      <small><i class="fa fa-clock-o"></i> <p wicket:id="instant"/></small>
-    </a>
-  </wicket:panel>
-</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/TaskQuery.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/TaskQuery.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/TaskQuery.java
index c96d7b2..f5cdecc 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/TaskQuery.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/TaskQuery.java
@@ -137,5 +137,4 @@ public class TaskQuery extends AbstractQuery {
     public void setDetails(final Boolean details) {
         this.details = details;
     }
-
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/WorkflowFormQuery.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/WorkflowFormQuery.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/WorkflowFormQuery.java
new file mode 100644
index 0000000..c3454bf
--- /dev/null
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/beans/WorkflowFormQuery.java
@@ -0,0 +1,32 @@
+/*
+ * 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.common.rest.api.beans;
+
+public class WorkflowFormQuery extends AbstractQuery {
+
+    private static final long serialVersionUID = -4762457303770028554L;
+
+    public static class Builder extends AbstractQuery.Builder<WorkflowFormQuery, Builder> {
+
+        @Override
+        protected WorkflowFormQuery newInstance() {
+            return new WorkflowFormQuery();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserWorkflowService.java
----------------------------------------------------------------------
diff --git a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserWorkflowService.java b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserWorkflowService.java
index 5dbe7d5..ee65b7e 100644
--- a/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserWorkflowService.java
+++ b/common/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/UserWorkflowService.java
@@ -23,6 +23,7 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirements;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import java.util.List;
 import javax.validation.constraints.NotNull;
+import javax.ws.rs.BeanParam;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
@@ -31,9 +32,11 @@ import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import org.apache.syncope.common.lib.SyncopeConstants;
+import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.to.WorkflowFormTO;
 import org.apache.syncope.common.lib.to.WorkflowTaskTO;
+import org.apache.syncope.common.rest.api.beans.WorkflowFormQuery;
 
 /**
  * REST operations related to user workflow.
@@ -48,12 +51,13 @@ public interface UserWorkflowService extends JAXRSService {
     /**
      * Returns a list of all available workflow forms.
      *
+     * @param query query conditions
      * @return list of all available workflow forms
      */
     @GET
     @Path("forms")
     @Produces({ MediaType.APPLICATION_JSON, SyncopeConstants.APPLICATION_YAML, MediaType.APPLICATION_XML })
-    List<WorkflowFormTO> getForms();
+    PagedResult<WorkflowFormTO> getForms(@BeanParam WorkflowFormQuery query);
 
     /**
      * Returns a list of available forms for the given user key.

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/core/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowLogic.java
----------------------------------------------------------------------
diff --git a/core/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowLogic.java b/core/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowLogic.java
index 8171ca9..8023c25 100644
--- a/core/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowLogic.java
+++ b/core/logic/src/main/java/org/apache/syncope/core/logic/UserWorkflowLogic.java
@@ -29,6 +29,7 @@ import org.apache.syncope.common.lib.to.WorkflowFormTO;
 import org.apache.syncope.common.lib.to.WorkflowTaskTO;
 import org.apache.syncope.common.lib.types.StandardEntitlement;
 import org.apache.syncope.core.persistence.api.dao.UserDAO;
+import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationManager;
 import org.apache.syncope.core.provisioning.api.propagation.PropagationTaskExecutor;
@@ -90,8 +91,12 @@ public class UserWorkflowLogic extends AbstractTransactionalLogic<WorkflowFormTO
 
     @PreAuthorize("hasRole('" + StandardEntitlement.WORKFLOW_FORM_LIST + "')")
     @Transactional(readOnly = true)
-    public List<WorkflowFormTO> getForms() {
-        return uwfAdapter.getForms();
+    public Pair<Integer, List<WorkflowFormTO>> getForms(
+            final int page,
+            final int size,
+            final List<OrderByClause> orderByClauses) {
+
+        return uwfAdapter.getForms(page, size, orderByClauses);
     }
 
     @PreAuthorize("hasRole('" + StandardEntitlement.WORKFLOW_TASK_LIST + "') "

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java
----------------------------------------------------------------------
diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java
index aac70c1..9e71908 100644
--- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/JPATaskDAO.java
@@ -22,7 +22,6 @@ import java.lang.reflect.Field;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.function.Predicate;
 import javax.persistence.DiscriminatorValue;
 import javax.persistence.ManyToOne;
 import javax.persistence.OneToMany;
@@ -378,17 +377,14 @@ public class JPATaskDAO extends AbstractDAO<Task> implements TaskDAO {
 
         List<Object> queryParameters = new ArrayList<>();
 
-        boolean orderByTaskExecInfo = orderByClauses.stream().anyMatch(new Predicate<OrderByClause>() {
+        boolean orderByTaskExecInfo = orderByClauses.stream().
+                anyMatch(clause -> clause.getField().equals("start")
+                || clause.getField().equals("end")
+                || clause.getField().equals("latestExecStatus")
+                || clause.getField().equals("status"));
 
-            @Override
-            public boolean test(final OrderByClause t) {
-                return t.getField().equals("start")
-                        || t.getField().equals("end")
-                        || t.getField().equals("latestExecStatus")
-                        || t.getField().equals("status");
-            }
-        });
-        StringBuilder queryString = buildFindAllQuery(type,
+        StringBuilder queryString = buildFindAllQuery(
+                type,
                 resource,
                 notification,
                 anyTypeKind,

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserWorkflowServiceImpl.java
----------------------------------------------------------------------
diff --git a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserWorkflowServiceImpl.java b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserWorkflowServiceImpl.java
index 8022f36..7a25cb8 100644
--- a/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserWorkflowServiceImpl.java
+++ b/core/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/UserWorkflowServiceImpl.java
@@ -19,16 +19,19 @@
 package org.apache.syncope.core.rest.cxf.service;
 
 import java.util.List;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.to.WorkflowFormTO;
 import org.apache.syncope.common.lib.to.WorkflowTaskTO;
+import org.apache.syncope.common.rest.api.beans.WorkflowFormQuery;
 import org.apache.syncope.common.rest.api.service.UserWorkflowService;
 import org.apache.syncope.core.logic.UserWorkflowLogic;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 @Service
-public class UserWorkflowServiceImpl implements UserWorkflowService {
+public class UserWorkflowServiceImpl extends AbstractServiceImpl implements UserWorkflowService {
 
     @Autowired
     private UserWorkflowLogic logic;
@@ -49,8 +52,10 @@ public class UserWorkflowServiceImpl implements UserWorkflowService {
     }
 
     @Override
-    public List<WorkflowFormTO> getForms() {
-        return logic.getForms();
+    public PagedResult<WorkflowFormTO> getForms(final WorkflowFormQuery query) {
+        Pair<Integer, List<WorkflowFormTO>> result = logic.getForms(
+                query.getPage(), query.getSize(), getOrderByClauses(query.getOrderBy()));
+        return buildPagedResult(result.getRight(), query.getPage(), query.getSize(), result.getLeft());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/WorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/WorkflowAdapter.java b/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/WorkflowAdapter.java
index 3b44487..07ca5b4 100644
--- a/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/WorkflowAdapter.java
+++ b/core/workflow-api/src/main/java/org/apache/syncope/core/workflow/api/WorkflowAdapter.java
@@ -19,9 +19,11 @@
 package org.apache.syncope.core.workflow.api;
 
 import java.util.List;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.patch.AnyPatch;
 import org.apache.syncope.common.lib.to.WorkflowFormTO;
 import org.apache.syncope.common.lib.to.WorkflowTaskTO;
+import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.provisioning.api.WorkflowResult;
 
 public interface WorkflowAdapter {
@@ -32,11 +34,14 @@ public interface WorkflowAdapter {
     String getPrefix();
 
     /**
-     * Get all defined forms for current workflow process instances.
+     * Get the forms for current workflow process instances matching the provided parameters.
      *
-     * @return list of defined forms
+     * @param page result page
+     * @param size items per page
+     * @param orderByClauses sort conditions
+     * @return total number of forms, list of forms matching the provided parameters
      */
-    List<WorkflowFormTO> getForms();
+    Pair<Integer, List<WorkflowFormTO>> getForms(int page, int size, List<OrderByClause> orderByClauses);
 
     /**
      * Get form for given workflowId (if present).

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/core/workflow-flowable/src/main/java/org/apache/syncope/core/workflow/flowable/FlowableUserWorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/core/workflow-flowable/src/main/java/org/apache/syncope/core/workflow/flowable/FlowableUserWorkflowAdapter.java b/core/workflow-flowable/src/main/java/org/apache/syncope/core/workflow/flowable/FlowableUserWorkflowAdapter.java
index 9255cb1..8738d88 100644
--- a/core/workflow-flowable/src/main/java/org/apache/syncope/core/workflow/flowable/FlowableUserWorkflowAdapter.java
+++ b/core/workflow-flowable/src/main/java/org/apache/syncope/core/workflow/flowable/FlowableUserWorkflowAdapter.java
@@ -52,6 +52,7 @@ import org.apache.syncope.core.spring.BeanUtils;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException;
 import org.apache.syncope.core.persistence.api.attrvalue.validation.ParsingValidationException;
 import org.apache.syncope.core.persistence.api.dao.NotFoundException;
+import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.provisioning.api.WorkflowResult;
 import org.apache.syncope.core.workflow.flowable.spring.DomainProcessEngine;
@@ -67,7 +68,6 @@ import org.flowable.bpmn.model.SequenceFlow;
 import org.flowable.editor.constants.ModelDataJsonConstants;
 import org.flowable.editor.language.json.converter.BpmnJsonConverter;
 import org.flowable.common.engine.api.FlowableException;
-import org.flowable.common.engine.api.query.Query;
 import org.flowable.engine.form.FormProperty;
 import org.flowable.engine.form.FormType;
 import org.flowable.engine.form.TaskFormData;
@@ -78,6 +78,7 @@ import org.flowable.engine.repository.Model;
 import org.flowable.engine.repository.ProcessDefinition;
 import org.flowable.engine.runtime.ProcessInstance;
 import org.flowable.task.api.Task;
+import org.flowable.task.api.TaskQuery;
 import org.flowable.task.api.history.HistoricTaskInstance;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.transaction.annotation.Transactional;
@@ -597,56 +598,87 @@ public class FlowableUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
 
     @Transactional(readOnly = true)
     @Override
-    public List<WorkflowFormTO> getForms() {
-        List<WorkflowFormTO> forms = new ArrayList<>();
+    public Pair<Integer, List<WorkflowFormTO>> getForms(
+            final int page, final int size, final List<OrderByClause> orderByClauses) {
+
+        Pair<Integer, List<WorkflowFormTO>> forms = null;
 
         String authUser = AuthContextUtils.getUsername();
         if (adminUser.equals(authUser)) {
-            forms.addAll(getForms(engine.getTaskService().createTaskQuery().
-                    taskVariableValueEquals(TASK_IS_FORM, Boolean.TRUE)));
+            forms = getForms(engine.getTaskService().createTaskQuery().
+                    taskVariableValueEquals(TASK_IS_FORM, Boolean.TRUE), page, size, orderByClauses);
         } else {
             User user = userDAO.findByUsername(authUser);
             if (user == null) {
                 throw new NotFoundException("Syncope User " + authUser);
             }
 
-            forms.addAll(getForms(engine.getTaskService().createTaskQuery().
+            forms = getForms(engine.getTaskService().createTaskQuery().
                     taskVariableValueEquals(TASK_IS_FORM, Boolean.TRUE).
-                    taskCandidateOrAssigned(user.getKey())));
+                    taskCandidateOrAssigned(user.getKey()), page, size, orderByClauses);
 
             List<String> candidateGroups = new ArrayList<>();
             userDAO.findAllGroupNames(user).forEach(group -> {
                 candidateGroups.add(group);
             });
             if (!candidateGroups.isEmpty()) {
-                forms.addAll(getForms(engine.getTaskService().createTaskQuery().
+                forms = getForms(engine.getTaskService().createTaskQuery().
                         taskVariableValueEquals(TASK_IS_FORM, Boolean.TRUE).
-                        taskCandidateGroupIn(candidateGroups)));
+                        taskCandidateGroupIn(candidateGroups), page, size, orderByClauses);
             }
         }
 
-        return forms;
+        return forms == null
+                ? Pair.of(0, Collections.<WorkflowFormTO>emptyList())
+                : forms;
     }
 
-    protected <T extends Query<?, ?>, U extends Object> List<WorkflowFormTO> getForms(final Query<T, U> query) {
-        List<WorkflowFormTO> forms = new ArrayList<>();
+    protected Pair<Integer, List<WorkflowFormTO>> getForms(
+            final TaskQuery query, final int page, final int size, final List<OrderByClause> orderByClauses) {
 
-        query.list().forEach(obj -> {
-            try {
-                if (obj instanceof HistoricTaskInstance) {
-                    forms.add(getFormTO((HistoricTaskInstance) obj));
-                } else if (obj instanceof Task) {
-                    forms.add(getFormTO((Task) obj));
+        TaskQuery sortedQuery = query;
+        for (OrderByClause clause : orderByClauses) {
+            boolean ack = true;
+            switch (clause.getField().trim()) {
+                case "taskId":
+                    sortedQuery = sortedQuery.orderByTaskId();
+                    break;
+
+                case "createTime":
+                    sortedQuery = sortedQuery.orderByTaskCreateTime();
+                    break;
+
+                case "dueDate":
+                    sortedQuery = sortedQuery.orderByTaskDueDate();
+                    break;
+
+                case "owner":
+                    sortedQuery = sortedQuery.orderByTaskOwner();
+                    break;
+
+                default:
+                    LOG.warn("Form sort request by {}: unsupported, ignoring", clause.getField().trim());
+                    ack = false;
+            }
+            if (ack) {
+                if (clause.getDirection() == OrderByClause.Direction.ASC) {
+                    sortedQuery = sortedQuery.asc();
                 } else {
-                    throw new FlowableException(
-                            "Failure retrieving form", new IllegalArgumentException("Invalid task type"));
+                    sortedQuery = sortedQuery.desc();
                 }
-            } catch (FlowableException e) {
-                LOG.debug("No form found for task {}", obj, e);
             }
-        });
+        }
+
+        List<WorkflowFormTO> result = sortedQuery.listPage(size * (page <= 0 ? 0 : page - 1), size).stream().
+                map(task -> {
+                    if (task instanceof HistoricTaskInstance) {
+                        return getFormTO((HistoricTaskInstance) task);
+                    } else {
+                        return getFormTO(task);
+                    }
+                }).collect(Collectors.toList());
 
-        return forms;
+        return Pair.of((int) query.count(), result);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultAnyObjectWorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultAnyObjectWorkflowAdapter.java b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultAnyObjectWorkflowAdapter.java
index 7e984df..6cd0468 100644
--- a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultAnyObjectWorkflowAdapter.java
+++ b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultAnyObjectWorkflowAdapter.java
@@ -21,6 +21,7 @@ package org.apache.syncope.core.workflow.java;
 import java.io.OutputStream;
 import java.util.Collections;
 import java.util.List;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.patch.AnyObjectPatch;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.WorkflowDefinitionTO;
@@ -28,6 +29,7 @@ import org.apache.syncope.common.lib.to.WorkflowFormTO;
 import org.apache.syncope.common.lib.to.WorkflowTaskTO;
 import org.apache.syncope.core.provisioning.api.PropagationByResource;
 import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.anyobject.AnyObject;
 import org.apache.syncope.core.provisioning.api.WorkflowResult;
 import org.apache.syncope.core.workflow.api.WorkflowDefinitionFormat;
@@ -67,8 +69,10 @@ public class DefaultAnyObjectWorkflowAdapter extends AbstractAnyObjectWorkflowAd
     }
 
     @Override
-    public List<WorkflowFormTO> getForms() {
-        return Collections.emptyList();
+    public Pair<Integer, List<WorkflowFormTO>> getForms(
+            final int page, final int size, final List<OrderByClause> orderByClauses) {
+
+        return Pair.of(0, Collections.<WorkflowFormTO>emptyList());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultGroupWorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultGroupWorkflowAdapter.java b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultGroupWorkflowAdapter.java
index 228561e..c10a3aa 100644
--- a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultGroupWorkflowAdapter.java
+++ b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultGroupWorkflowAdapter.java
@@ -21,6 +21,7 @@ package org.apache.syncope.core.workflow.java;
 import java.io.OutputStream;
 import java.util.Collections;
 import java.util.List;
+import org.apache.commons.lang3.tuple.Pair;
 import org.apache.syncope.common.lib.patch.GroupPatch;
 import org.apache.syncope.common.lib.to.GroupTO;
 import org.apache.syncope.common.lib.to.WorkflowDefinitionTO;
@@ -28,6 +29,7 @@ import org.apache.syncope.common.lib.to.WorkflowFormTO;
 import org.apache.syncope.common.lib.to.WorkflowTaskTO;
 import org.apache.syncope.core.provisioning.api.PropagationByResource;
 import org.apache.syncope.common.lib.types.ResourceOperation;
+import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.group.Group;
 import org.apache.syncope.core.provisioning.api.WorkflowResult;
 import org.apache.syncope.core.workflow.api.WorkflowDefinitionFormat;
@@ -67,8 +69,10 @@ public class DefaultGroupWorkflowAdapter extends AbstractGroupWorkflowAdapter {
     }
 
     @Override
-    public List<WorkflowFormTO> getForms() {
-        return Collections.emptyList();
+    public Pair<Integer, List<WorkflowFormTO>> getForms(
+            final int page, final int size, final List<OrderByClause> orderByClauses) {
+
+        return Pair.of(0, Collections.<WorkflowFormTO>emptyList());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
----------------------------------------------------------------------
diff --git a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
index ce9e77b..ebb3445 100644
--- a/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
+++ b/core/workflow-java/src/main/java/org/apache/syncope/core/workflow/java/DefaultUserWorkflowAdapter.java
@@ -31,6 +31,7 @@ import org.apache.syncope.common.lib.to.WorkflowTaskTO;
 import org.apache.syncope.core.provisioning.api.PropagationByResource;
 import org.apache.syncope.common.lib.types.ResourceOperation;
 import org.apache.syncope.core.persistence.api.dao.ConfDAO;
+import org.apache.syncope.core.persistence.api.dao.search.OrderByClause;
 import org.apache.syncope.core.persistence.api.entity.user.User;
 import org.apache.syncope.core.provisioning.api.WorkflowResult;
 import org.apache.syncope.core.workflow.api.WorkflowDefinitionFormat;
@@ -156,8 +157,10 @@ public class DefaultUserWorkflowAdapter extends AbstractUserWorkflowAdapter {
     }
 
     @Override
-    public List<WorkflowFormTO> getForms() {
-        return Collections.emptyList();
+    public Pair<Integer, List<WorkflowFormTO>> getForms(
+            final int page, final int size, final List<OrderByClause> orderByClauses) {
+
+        return Pair.of(0, Collections.<WorkflowFormTO>emptyList());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SchedTaskITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SchedTaskITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SchedTaskITCase.java
index a3af47d..dc0066d 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SchedTaskITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/SchedTaskITCase.java
@@ -47,6 +47,7 @@ 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.ExecQuery;
 import org.apache.syncope.common.rest.api.beans.TaskQuery;
+import org.apache.syncope.common.rest.api.beans.WorkflowFormQuery;
 import org.apache.syncope.common.rest.api.service.TaskService;
 import org.apache.syncope.fit.FlowableDetector;
 import org.apache.syncope.fit.core.reference.TestSampleJobDelegate;
@@ -143,7 +144,8 @@ public class SchedTaskITCase extends AbstractTaskITCase {
 
         execTask(taskService, TaskType.SCHEDULED, "e95555d2-1b09-42c8-b25b-f4c4ec598989", "JOB_FIRED", 50, false);
 
-        List<WorkflowFormTO> forms = userWorkflowService.getForms();
+        List<WorkflowFormTO> forms = userWorkflowService.getForms(
+                new WorkflowFormQuery.Builder().page(1).size(1000).build()).getResult();
         assertFalse(forms.isEmpty());
         forms.forEach(form -> {
             userWorkflowService.claimForm(form.getTaskId());
@@ -152,7 +154,8 @@ public class SchedTaskITCase extends AbstractTaskITCase {
             userWorkflowService.submitForm(form);
         });
 
-        forms = userWorkflowService.getForms();
+        forms = userWorkflowService.getForms(
+                new WorkflowFormQuery.Builder().page(1).size(1000).build()).getResult();
         assertTrue(forms.isEmpty());
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/c3ce309a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java
----------------------------------------------------------------------
diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java
index e3fa1c0..24dc61d 100644
--- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java
+++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/UserWorkflowITCase.java
@@ -41,12 +41,14 @@ import org.apache.syncope.common.lib.patch.StringPatchItem;
 import org.apache.syncope.common.lib.patch.StringReplacePatchItem;
 import org.apache.syncope.common.lib.patch.UserPatch;
 import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.PagedResult;
 import org.apache.syncope.common.lib.to.ProvisioningResult;
 import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.to.WorkflowFormTO;
 import org.apache.syncope.common.lib.to.WorkflowTaskTO;
 import org.apache.syncope.common.lib.types.ClientExceptionType;
 import org.apache.syncope.common.lib.types.PatchOperation;
+import org.apache.syncope.common.rest.api.beans.WorkflowFormQuery;
 import org.apache.syncope.common.rest.api.service.UserSelfService;
 import org.apache.syncope.common.rest.api.service.UserWorkflowService;
 import org.apache.syncope.fit.AbstractITCase;
@@ -141,9 +143,9 @@ public class UserWorkflowITCase extends AbstractITCase {
         assumeTrue(FlowableDetector.isFlowableEnabledForUsers(syncopeService));
 
         // read forms *before* any operation
-        List<WorkflowFormTO> forms = userWorkflowService.getForms();
-        assertNotNull(forms);
-        int preForms = forms.size();
+        PagedResult<WorkflowFormTO> forms =
+                userWorkflowService.getForms(new WorkflowFormQuery.Builder().page(1).size(1000).build());
+        int preForms = forms.getTotalCount();
 
         UserTO userTO = UserITCase.getUniqueSampleTO("createWithApproval@syncope.apache.org");
         userTO.getResources().add(RESOURCE_NAME_TESTDB);
@@ -175,9 +177,8 @@ public class UserWorkflowITCase extends AbstractITCase {
         assertNotNull(exception);
 
         // 2. request if there is any pending form for user just created
-        forms = userWorkflowService.getForms();
-        assertNotNull(forms);
-        assertEquals(preForms + 1, forms.size());
+        forms = userWorkflowService.getForms(new WorkflowFormQuery.Builder().page(1).size(1000).build());
+        assertEquals(preForms + 1, forms.getTotalCount());
 
         // 3. as admin, request for changes: still pending approval
         String updatedUsername = "changed-" + UUID.randomUUID().toString();
@@ -227,9 +228,9 @@ public class UserWorkflowITCase extends AbstractITCase {
         assumeTrue(FlowableDetector.isFlowableEnabledForUsers(syncopeService));
 
         // read forms *before* any operation
-        List<WorkflowFormTO> forms = userWorkflowService.getForms();
-        assertNotNull(forms);
-        int preForms = forms.size();
+        PagedResult<WorkflowFormTO> forms = userWorkflowService.getForms(
+                new WorkflowFormQuery.Builder().page(1).size(1000).build());
+        int preForms = forms.getTotalCount();
 
         UserTO created = createUser(UserITCase.getUniqueSampleTO("updateApproval@syncope.apache.org")).getEntity();
         assertNotNull(created);
@@ -245,9 +246,8 @@ public class UserWorkflowITCase extends AbstractITCase {
         assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
         assertEquals("updateApproval", userService.read(created.getKey()).getStatus());
 
-        forms = userWorkflowService.getForms();
-        assertNotNull(forms);
-        assertEquals(preForms + 1, forms.size());
+        forms = userWorkflowService.getForms(new WorkflowFormQuery.Builder().page(1).size(1000).build());
+        assertEquals(preForms + 1, forms.getTotalCount());
 
         WorkflowFormTO form = userWorkflowService.getFormForUser(created.getKey());
         assertNotNull(form);
@@ -299,9 +299,9 @@ public class UserWorkflowITCase extends AbstractITCase {
         assumeTrue(FlowableDetector.isFlowableEnabledForUsers(syncopeService));
 
         // read forms *before* any operation
-        List<WorkflowFormTO> forms = userWorkflowService.getForms();
-        assertNotNull(forms);
-        int preForms = forms.size();
+        PagedResult<WorkflowFormTO> forms = userWorkflowService.getForms(
+                new WorkflowFormQuery.Builder().page(1).size(1000).build());
+        int preForms = forms.getTotalCount();
 
         UserTO userTO = UserITCase.getUniqueSampleTO("issueSYNCOPE15@syncope.apache.org");
         userTO.getResources().clear();
@@ -324,8 +324,8 @@ public class UserWorkflowITCase extends AbstractITCase {
         assertEquals(userTO.getCreationDate(), userTO.getLastChangeDate());
 
         // 2. request if there is any pending form for user just created
-        forms = userWorkflowService.getForms();
-        assertEquals(preForms + 1, forms.size());
+        forms = userWorkflowService.getForms(new WorkflowFormQuery.Builder().page(1).size(1000).build());
+        assertEquals(preForms + 1, forms.getTotalCount());
 
         WorkflowFormTO form = userWorkflowService.getFormForUser(userTO.getKey());
         assertNotNull(form);
@@ -348,12 +348,14 @@ public class UserWorkflowITCase extends AbstractITCase {
         // 6. submit approve
         userTO = userWorkflowService.submitForm(form);
         assertNotNull(userTO);
-        assertEquals(preForms, userWorkflowService.getForms().size());
+        assertEquals(
+                preForms,
+                userWorkflowService.getForms(
+                        new WorkflowFormQuery.Builder().page(1).size(1000).build()).getTotalCount());
         assertNull(userWorkflowService.getFormForUser(userTO.getKey()));
 
         // 7.check that no more forms are still to be processed
-        forms = userWorkflowService.getForms();
-        assertEquals(preForms, forms.size());
+        forms = userWorkflowService.getForms(new WorkflowFormQuery.Builder().page(1).size(1000).build());
+        assertEquals(preForms, forms.getTotalCount());
     }
-
 }