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/10/09 15:08:48 UTC

[3/6] syncope git commit: [SYNCOPE-1369] Some refinements + admin console suport

[SYNCOPE-1369] Some refinements + admin console suport


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

Branch: refs/heads/2_1_X
Commit: ff37c3f763b967d928a5dd5d4764b54694ca299f
Parents: e1b88c2
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Tue Oct 9 17:08:13 2018 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Tue Oct 9 17:08:13 2018 +0200

----------------------------------------------------------------------
 .../console/SyncopeConsoleApplication.java      |   4 +-
 .../client/console/commons/Constants.java       |   2 -
 .../client/console/rest/ReportRestClient.java   |   2 -
 .../console/tasks/SchedTaskDirectoryPanel.java  |   6 +-
 .../client/console/approvals/Approval.java      | 201 -----------
 .../console/approvals/ApprovalDetails.java      |  63 ----
 .../approvals/ApprovalDirectoryPanel.java       | 352 ------------------
 .../client/console/approvals/ApprovalModal.java |  82 -----
 .../syncope/client/console/pages/Approvals.java |  41 ---
 .../syncope/client/console/pages/Flowable.java  |   7 -
 .../client/console/pages/UserRequests.java      |  74 ++++
 .../panels/UserRequestDirectoryPanel.java       | 163 +++++++++
 .../console/panels/UserRequestFormDetails.java  |  62 ++++
 .../panels/UserRequestFormDirectoryPanel.java   | 353 +++++++++++++++++++
 .../console/panels/UserRequestFormModal.java    |  79 +++++
 .../console/panels/UserRequestFormPanel.java    | 200 +++++++++++
 .../console/rest/UserRequestRestClient.java     |  18 +
 .../client/console/widgets/ApprovalsWidget.java | 128 -------
 .../console/widgets/UserRequestFormsWidget.java | 128 +++++++
 .../client/console/approvals/Approval.html      |  31 --
 .../console/approvals/Approval.properties       |  18 -
 .../console/approvals/ApprovalDetails.html      |  23 --
 .../client/console/approvals/ApprovalModal.html |  23 --
 .../console/approvals/ApprovalModal.properties  |  17 -
 .../approvals/ApprovalModal_it.properties       |  17 -
 .../approvals/ApprovalModal_ja.properties       |  17 -
 .../approvals/ApprovalModal_pt_BR.properties    |  17 -
 .../approvals/ApprovalModal_ru.properties       |  17 -
 .../console/approvals/Approval_it.properties    |  18 -
 .../console/approvals/Approval_ja.properties    |  18 -
 .../console/approvals/Approval_pt_BR.properties |  18 -
 .../console/approvals/Approval_ru.properties    |  20 --
 .../syncope/client/console/pages/Approvals.html |  35 --
 .../client/console/pages/Approvals.properties   |  34 --
 .../console/pages/Approvals_it.properties       |  34 --
 .../console/pages/Approvals_ja.properties       |  34 --
 .../console/pages/Approvals_pt_BR.properties    |  34 --
 .../console/pages/Approvals_ru.properties       |  52 ---
 .../client/console/pages/UserRequests.html      |  35 ++
 .../console/pages/UserRequests.properties       |  38 ++
 .../console/pages/UserRequests_it.properties    |  38 ++
 .../console/pages/UserRequests_ja.properties    |  38 ++
 .../console/pages/UserRequests_pt_BR.properties |  38 ++
 .../console/pages/UserRequests_ru.properties    |  56 +++
 .../console/panels/UserRequestFormDetails.html  |  23 ++
 .../console/panels/UserRequestFormModal.html    |  23 ++
 .../panels/UserRequestFormModal.properties      |  17 +
 .../panels/UserRequestFormModal_it.properties   |  17 +
 .../panels/UserRequestFormModal_ja.properties   |  17 +
 .../UserRequestFormModal_pt_BR.properties       |  17 +
 .../panels/UserRequestFormModal_ru.properties   |  17 +
 .../console/panels/UserRequestFormPanel.html    |  31 ++
 .../panels/UserRequestFormPanel.properties      |  18 +
 .../panels/UserRequestFormPanel_it.properties   |  18 +
 .../panels/UserRequestFormPanel_ja.properties   |  18 +
 .../UserRequestFormPanel_pt_BR.properties       |  18 +
 .../panels/UserRequestFormPanel_ru.properties   |  20 ++
 .../console/widgets/ApprovalsWidget.properties  |  21 --
 .../widgets/ApprovalsWidget_it.properties       |  21 --
 .../widgets/ApprovalsWidget_ja.properties       |  21 --
 .../widgets/ApprovalsWidget_pt_BR.properties    |  21 --
 .../widgets/ApprovalsWidget_ru.properties       |  22 --
 .../widgets/UserRequestFormsWidget.properties   |  20 ++
 .../UserRequestFormsWidget_it.properties        |  20 ++
 .../UserRequestFormsWidget_ja.properties        |  20 ++
 .../UserRequestFormsWidget_pt_BR.properties     |  20 ++
 .../UserRequestFormsWidget_ru.properties        |  21 ++
 .../syncope/common/lib/to/UserRequest.java      |  21 +-
 .../impl/FlowableUserRequestHandler.java        |  91 ++---
 .../syncope/fit/core/UserRequestITCase.java     |   4 +-
 70 files changed, 1744 insertions(+), 1518 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/ff37c3f7/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleApplication.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleApplication.java b/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleApplication.java
index 2e15b19..f03f823 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleApplication.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/SyncopeConsoleApplication.java
@@ -62,7 +62,7 @@ import org.apache.wicket.protocol.http.WebApplication;
 import org.apache.wicket.request.resource.AbstractResource;
 import org.apache.wicket.request.resource.IResource;
 import org.apache.wicket.request.resource.ResourceReference;
-import org.apache.wicket.resource.DynamicJQueryResourceReference;
+import org.apache.wicket.resource.JQueryResourceReference;
 import org.apache.wicket.util.lang.Args;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -190,7 +190,7 @@ public class SyncopeConsoleApplication extends AuthenticatedWebApplication {
 
         getResourceSettings().setThrowExceptionOnMissingResource(true);
 
-        getJavaScriptLibrarySettings().setJQueryReference(new DynamicJQueryResourceReference());
+        getJavaScriptLibrarySettings().setJQueryReference(JQueryResourceReference.getV2());
 
         getSecuritySettings().setAuthorizationStrategy(new MetaDataRoleAuthorizationStrategy(this));
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/ff37c3f7/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java
index 48b58137..2e60aa9 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/Constants.java
@@ -123,8 +123,6 @@ public final class Constants {
 
     public static final String PREF_ACCESS_TOKEN_PAGINATOR_ROWS = "accessToken.paginator.rows";
 
-    public static final String PREF_WORKFLOW_FORM_PAGINATOR_ROWS = "workflow.paginator.rows";
-
     public static final String PREF_REMEDIATION_PAGINATOR_ROWS = "remediation.paginator.rows";
 
     public static final String PREF_RESOURCES_PAGINATOR_ROWS = "resources.paginator.rows";

http://git-wip-us.apache.org/repos/asf/syncope/blob/ff37c3f7/client/console/src/main/java/org/apache/syncope/client/console/rest/ReportRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/ReportRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/ReportRestClient.java
index 8b60941..a80cdcb 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/ReportRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/ReportRestClient.java
@@ -18,8 +18,6 @@
  */
 package org.apache.syncope.client.console.rest;
 
-import static org.apache.syncope.client.console.rest.BaseRestClient.getStatus;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;

http://git-wip-us.apache.org/repos/asf/syncope/blob/ff37c3f7/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java
index 0dc445d..c333f34 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/tasks/SchedTaskDirectoryPanel.java
@@ -229,8 +229,7 @@ public abstract class SchedTaskDirectoryPanel<T extends SchedTaskTO>
                         new AjaxWizard.EditItemActionEvent<>(clone, target).setResourceModel(
                                 new StringResourceModel("inner.task.clone",
                                         SchedTaskDirectoryPanel.this,
-                                        Model.of(Pair.of(
-                                                ActionLink.ActionType.CLONE, model.getObject())))));
+                                        Model.of(Pair.of(ActionLink.ActionType.CLONE, model.getObject())))));
             }
         }, ActionLink.ActionType.CLONE, StandardEntitlement.TASK_CREATE);
 
@@ -241,8 +240,7 @@ public abstract class SchedTaskDirectoryPanel<T extends SchedTaskTO>
             @Override
             public void onClick(final AjaxRequestTarget target, final T ignore) {
                 SchedTaskDirectoryPanel.this.getTogglePanel().close(target);
-                startAt.setExecutionDetail(
-                        model.getObject().getKey(), model.getObject().getName(), target);
+                startAt.setExecutionDetail(model.getObject().getKey(), model.getObject().getName(), target);
                 startAt.toggle(target, true);
             }
         }, ActionLink.ActionType.EXECUTE, StandardEntitlement.TASK_EXECUTE);

http://git-wip-us.apache.org/repos/asf/syncope/blob/ff37c3f7/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/Approval.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/Approval.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/Approval.java
deleted file mode 100644
index 6a66afc..0000000
--- a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/Approval.java
+++ /dev/null
@@ -1,201 +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.approvals;
-
-import java.text.ParseException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.math.NumberUtils;
-import org.apache.commons.lang3.time.FastDateFormat;
-import org.apache.syncope.client.console.commons.MapChoiceRenderer;
-import org.apache.syncope.client.console.panels.MultilevelPanel;
-import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
-import org.apache.syncope.client.console.wicket.markup.html.form.AjaxSpinnerFieldPanel;
-import org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
-import org.apache.syncope.client.console.wicket.markup.html.form.AjaxDateTimeFieldPanel;
-import org.apache.syncope.client.console.wicket.markup.html.form.FieldPanel;
-import org.apache.syncope.common.lib.to.UserRequestFormProperty;
-import org.apache.syncope.common.lib.to.UserRequestForm;
-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.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;
-import org.apache.wicket.model.PropertyModel;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public abstract class Approval extends Panel {
-
-    private static final long serialVersionUID = -8847854414429745216L;
-
-    protected static final Logger LOG = LoggerFactory.getLogger(Approval.class);
-
-    public Approval(final PageReference pageRef, final UserRequestForm formTO) {
-        super(MultilevelPanel.FIRST_LEVEL_ID);
-
-        IModel<List<UserRequestFormProperty>> formProps = new LoadableDetachableModel<List<UserRequestFormProperty>>() {
-
-            private static final long serialVersionUID = 3169142472626817508L;
-
-            @Override
-            protected List<UserRequestFormProperty> load() {
-                return formTO.getProperties();
-            }
-        };
-
-        ListView<UserRequestFormProperty> propView = new ListView<UserRequestFormProperty>("propView", formProps) {
-
-            private static final long serialVersionUID = 9101744072914090143L;
-
-            @Override
-            @SuppressWarnings({ "unchecked", "rawtypes" })
-            protected void populateItem(final ListItem<UserRequestFormProperty> item) {
-                final UserRequestFormProperty prop = item.getModelObject();
-
-                String label = StringUtils.isBlank(prop.getName()) ? prop.getId() : prop.getName();
-
-                FieldPanel field;
-                switch (prop.getType()) {
-                    case Boolean:
-                        field = new AjaxDropDownChoicePanel("value", label, new PropertyModel<String>(prop, "value") {
-
-                            private static final long serialVersionUID = -3743432456095828573L;
-
-                            @Override
-                            public String getObject() {
-                                return StringUtils.isBlank(prop.getValue())
-                                        ? null
-                                        : prop.getValue().equals("true") ? "Yes" : "No";
-                            }
-
-                            @Override
-                            public void setObject(final String object) {
-                                prop.setValue(String.valueOf(object.equalsIgnoreCase("yes")));
-                            }
-
-                        }, false).setChoices(Arrays.asList(new String[] { "Yes", "No" }));
-                        break;
-
-                    case Date:
-                        FastDateFormat formatter = FastDateFormat.getInstance(prop.getDatePattern());
-                        field = new AjaxDateTimeFieldPanel("value", label, new PropertyModel<Date>(prop, "value") {
-
-                            private static final long serialVersionUID = -3743432456095828573L;
-
-                            @Override
-                            public Date getObject() {
-                                try {
-                                    return StringUtils.isBlank(prop.getValue())
-                                            ? null
-                                            : formatter.parse(prop.getValue());
-                                } catch (ParseException e) {
-                                    LOG.error("Unparsable date: {}", prop.getValue(), e);
-                                    return null;
-                                }
-                            }
-
-                            @Override
-                            public void setObject(final Date object) {
-                                prop.setValue(formatter.format(object));
-                            }
-
-                        }, prop.getDatePattern());
-                        break;
-
-                    case Enum:
-                        field = new AjaxDropDownChoicePanel(
-                                "value", label, new PropertyModel<String>(prop, "value"), false).
-                                setChoiceRenderer(new MapChoiceRenderer(prop.getEnumValues())).
-                                setChoices(new ArrayList<>(prop.getEnumValues().keySet()));
-                        break;
-
-                    case Dropdown:
-                        field = new AjaxDropDownChoicePanel(
-                                "value", label, new PropertyModel<String>(prop, "value"), false).
-                                setChoiceRenderer(new MapChoiceRenderer(prop.getDropdownValues())).
-                                setChoices(new ArrayList<>(prop.getDropdownValues().keySet()));
-                        break;
-
-                    case Long:
-                        field = new AjaxSpinnerFieldPanel.Builder<Long>().build(
-                                "value",
-                                label,
-                                Long.class,
-                                new PropertyModel<Long>(prop, "value") {
-
-                            private static final long serialVersionUID = -7688359318035249200L;
-
-                            @Override
-                            public Long getObject() {
-                                return StringUtils.isBlank(prop.getValue())
-                                        ? null
-                                        : NumberUtils.toLong(prop.getValue());
-                            }
-
-                            @Override
-                            public void setObject(final Long object) {
-                                prop.setValue(String.valueOf(object));
-                            }
-                        });
-                        break;
-
-                    case String:
-                    default:
-                        field = new AjaxTextFieldPanel("value", label, new PropertyModel<>(prop, "value"), false);
-                        break;
-                }
-
-                field.setReadOnly(!prop.isWritable());
-                if (prop.isRequired()) {
-                    field.addRequiredLabel();
-                }
-
-                item.add(field);
-            }
-        };
-
-        AjaxLink<String> userDetails = new AjaxLink<String>("userDetails") {
-
-            private static final long serialVersionUID = -4804368561204623354L;
-
-            @Override
-            public void onClick(final AjaxRequestTarget target) {
-                viewDetails(target);
-            }
-        };
-        MetaDataRoleAuthorizationStrategy.authorize(userDetails, ENABLE, StandardEntitlement.USER_READ);
-
-        boolean enabled = formTO.getUserTO() != null;
-        userDetails.setVisible(enabled).setEnabled(enabled);
-
-        add(propView);
-        add(userDetails);
-    }
-
-    protected abstract void viewDetails(final AjaxRequestTarget target);
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ff37c3f7/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDetails.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDetails.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDetails.java
deleted file mode 100644
index 9606824..0000000
--- a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDetails.java
+++ /dev/null
@@ -1,63 +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.approvals;
-
-import org.apache.syncope.client.console.layout.UserFormLayoutInfo;
-import org.apache.syncope.client.console.panels.MultilevelPanel;
-import org.apache.syncope.client.console.rest.AnyTypeRestClient;
-import org.apache.syncope.client.console.wizards.AjaxWizard;
-import org.apache.syncope.client.console.wizards.any.UserWizardBuilder;
-import org.apache.syncope.common.lib.AnyOperations;
-import org.apache.syncope.common.lib.to.UserTO;
-import org.apache.syncope.common.lib.to.UserRequestForm;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
-import org.apache.wicket.PageReference;
-
-public class ApprovalDetails extends MultilevelPanel.SecondLevel {
-
-    private static final long serialVersionUID = -8847854414429745216L;
-
-    public ApprovalDetails(final PageReference pageRef, final UserRequestForm formTO) {
-        super(MultilevelPanel.SECOND_LEVEL_ID);
-
-        final UserTO newUserTO;
-        final UserTO previousUserTO;
-        if (formTO.getUserPatch() == null) {
-            newUserTO = formTO.getUserTO();
-            previousUserTO = null;
-        } else if (formTO.getUserTO() == null) {
-            // make it stronger by handling possible NPE
-            previousUserTO = new UserTO();
-            previousUserTO.setKey(formTO.getUserPatch().getKey());
-            newUserTO = AnyOperations.patch(previousUserTO, formTO.getUserPatch());
-        } else {
-            formTO.getUserTO().setKey(formTO.getUserPatch().getKey());
-            newUserTO = AnyOperations.patch(formTO.getUserTO(), formTO.getUserPatch());
-            previousUserTO = formTO.getUserTO();
-        }
-
-        add(new UserWizardBuilder(
-                previousUserTO,
-                newUserTO,
-                new AnyTypeRestClient().read(AnyTypeKind.USER.name()).getClasses(),
-                new UserFormLayoutInfo(),
-                pageRef).
-                build(AjaxWizard.Mode.READONLY));
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ff37c3f7/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
deleted file mode 100644
index 577ea65..0000000
--- a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDirectoryPanel.java
+++ /dev/null
@@ -1,352 +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.approvals;
-
-import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import org.apache.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.panels.DirectoryPanel;
-import org.apache.syncope.client.console.rest.UserRequestRestClient;
-import org.apache.syncope.client.console.approvals.ApprovalDirectoryPanel.ApprovalProvider;
-import org.apache.syncope.client.console.layout.FormLayoutInfoUtils;
-import org.apache.syncope.client.console.layout.UserFormLayoutInfo;
-import org.apache.syncope.client.console.pages.BasePage;
-import org.apache.syncope.client.console.rest.AnyTypeRestClient;
-import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
-import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
-import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
-import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
-import org.apache.syncope.client.console.widgets.ApprovalsWidget;
-import org.apache.syncope.client.console.wizards.AjaxWizard;
-import org.apache.syncope.client.console.wizards.any.AnyWrapper;
-import org.apache.syncope.client.console.wizards.any.UserWizardBuilder;
-import org.apache.syncope.common.lib.AnyOperations;
-import org.apache.syncope.common.lib.SyncopeClientException;
-import org.apache.syncope.common.lib.patch.PasswordPatch;
-import org.apache.syncope.common.lib.patch.UserPatch;
-import org.apache.syncope.common.lib.to.ProvisioningResult;
-import org.apache.syncope.common.lib.to.UserTO;
-import org.apache.syncope.common.lib.to.UserRequestForm;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
-import org.apache.syncope.common.lib.types.FlowableEntitlement;
-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.ajax.markup.html.modal.ModalWindow;
-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.Model;
-import org.apache.wicket.model.ResourceModel;
-
-public class ApprovalDirectoryPanel
-        extends DirectoryPanel<UserRequestForm, UserRequestForm, ApprovalProvider, UserRequestRestClient> {
-
-    private static final long serialVersionUID = -7122136682275797903L;
-
-    protected final BaseModal<UserRequestForm> manageApprovalModal = new BaseModal<UserRequestForm>("outer") {
-
-        private static final long serialVersionUID = 389935548143327858L;
-
-        @Override
-        protected void onConfigure() {
-            super.onConfigure();
-            addSubmitButton();
-            size(Modal.Size.Large);
-        }
-
-    };
-
-    public ApprovalDirectoryPanel(final String id, final PageReference pageReference) {
-        super(id, pageReference, true);
-        disableCheckBoxes();
-        setFooterVisibility(false);
-        modal.size(Modal.Size.Large);
-
-        addOuterObject(manageApprovalModal);
-
-        manageApprovalModal.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
-
-            private static final long serialVersionUID = 8804221891699487139L;
-
-            @Override
-            public void onClose(final AjaxRequestTarget target) {
-                updateResultTable(target);
-
-                Serializable widget = SyncopeConsoleSession.get().getAttribute(ApprovalsWidget.class.getName());
-                if (widget instanceof ApprovalsWidget) {
-                    ((ApprovalsWidget) widget).refreshLatestAlerts(target);
-                }
-
-                manageApprovalModal.show(false);
-            }
-        });
-
-        restClient = new UserRequestRestClient();
-
-        initResultTable();
-
-        MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, FlowableEntitlement.USER_REQUEST_FORM_SUBMIT);
-    }
-
-    @Override
-    protected List<IColumn<UserRequestForm, String>> getColumns() {
-        List<IColumn<UserRequestForm, String>> columns = new ArrayList<>();
-
-        columns.add(new PropertyColumn<>(
-                new ResourceModel("bpmnProcess"), "bpmnProcess", "bpmnProcess"));
-        columns.add(new PropertyColumn<>(
-                new ResourceModel("key"), "formKey", "formKey"));
-        columns.add(new PropertyColumn<>(
-                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"));
-
-        return columns;
-    }
-
-    @Override
-    public ActionsPanel<UserRequestForm> getActions(final IModel<UserRequestForm> model) {
-        final ActionsPanel<UserRequestForm> panel = super.getActions(model);
-
-        panel.add(new ActionLink<UserRequestForm>() {
-
-            private static final long serialVersionUID = -3722207913631435501L;
-
-            @Override
-            public void onClick(final AjaxRequestTarget target, final UserRequestForm ignore) {
-                claimForm(model.getObject().getTaskId());
-                SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
-                ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
-                target.add(container);
-            }
-        }, ActionLink.ActionType.CLAIM, FlowableEntitlement.USER_REQUEST_FORM_CLAIM);
-
-        panel.add(new ActionLink<UserRequestForm>() {
-
-            private static final long serialVersionUID = -3722207913631435501L;
-
-            @Override
-            public void onClick(final AjaxRequestTarget target, final UserRequestForm ignore) {
-                manageApprovalModal.setFormModel(new CompoundPropertyModel<>(model.getObject()));
-
-                target.add(manageApprovalModal.setContent(
-                        new ApprovalModal(manageApprovalModal, pageRef, model.getObject()) {
-
-                    private static final long serialVersionUID = 5546519445061007248L;
-
-                    @Override
-                    public void onSubmit(final AjaxRequestTarget target) {
-                        try {
-                            super.onSubmit(target);
-
-                            ApprovalDirectoryPanel.this.getTogglePanel().close(target);
-                        } catch (SyncopeClientException e) {
-                            SyncopeConsoleSession.get().error(getString(Constants.ERROR) + ": " + e.getMessage());
-                        }
-                        ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
-                    }
-
-                }));
-
-                manageApprovalModal.header(new Model<>(getString("approval.manage", new Model<>(model.getObject()))));
-                manageApprovalModal.show(true);
-            }
-
-            @Override
-            protected boolean statusCondition(final UserRequestForm modelObject) {
-                return SyncopeConsoleSession.get().getSelfTO().getUsername().
-                        equals(model.getObject().getOwner());
-            }
-
-        }, ActionLink.ActionType.MANAGE_APPROVAL, FlowableEntitlement.USER_REQUEST_FORM_SUBMIT);
-
-        // SYNCOPE-1200 edit user while in approval state
-        panel.add(new ActionLink<UserRequestForm>() {
-
-            private static final long serialVersionUID = -3722207913631435501L;
-
-            @Override
-            public void onClick(final AjaxRequestTarget target, final UserRequestForm ignore) {
-                modal.setFormModel(new CompoundPropertyModel<>(model.getObject()));
-
-                UserRequestForm formTO = model.getObject();
-                UserTO newUserTO;
-                UserTO previousUserTO;
-                if (formTO.getUserPatch() == null) {
-                    newUserTO = formTO.getUserTO();
-                    previousUserTO = null;
-                } else if (formTO.getUserTO() == null) {
-                    // make it stronger by handling possible NPE
-                    previousUserTO = new UserTO();
-                    previousUserTO.setKey(formTO.getUserPatch().getKey());
-                    newUserTO = AnyOperations.patch(previousUserTO, formTO.getUserPatch());
-                } else {
-                    previousUserTO = formTO.getUserTO();
-                    formTO.getUserTO().setKey(formTO.getUserPatch().getKey());
-                    formTO.getUserTO().setPassword(null);
-                    newUserTO = AnyOperations.patch(formTO.getUserTO(), formTO.getUserPatch());
-                }
-
-                AjaxWizard.EditItemActionEvent<UserTO> editItemActionEvent =
-                        new AjaxWizard.EditItemActionEvent<>(newUserTO, target);
-                editItemActionEvent.forceModalPanel(new ApprovalUserWizardBuilder(
-                        model.getObject(),
-                        previousUserTO,
-                        newUserTO,
-                        new AnyTypeRestClient().read(AnyTypeKind.USER.name()).getClasses(),
-                        FormLayoutInfoUtils.fetch(Collections.singletonList(AnyTypeKind.USER.name())).getLeft(),
-                        pageRef
-                ).build(BaseModal.CONTENT_ID, AjaxWizard.Mode.EDIT));
-
-                send(ApprovalDirectoryPanel.this, Broadcast.EXACT, editItemActionEvent);
-            }
-
-            @Override
-            protected boolean statusCondition(final UserRequestForm modelObject) {
-                return SyncopeConsoleSession.get().getSelfTO().getUsername().
-                        equals(model.getObject().getOwner());
-            }
-
-        }, ActionLink.ActionType.EDIT_APPROVAL, FlowableEntitlement.USER_REQUEST_FORM_SUBMIT);
-
-        return panel;
-    }
-
-    @Override
-    protected ApprovalProvider dataProvider() {
-        return new ApprovalProvider(rows);
-    }
-
-    @Override
-    protected String paginatorRowsKey() {
-        return Constants.PREF_WORKFLOW_FORM_PAGINATOR_ROWS;
-    }
-
-    public static class ApprovalProvider extends DirectoryDataProvider<UserRequestForm> {
-
-        private static final long serialVersionUID = -2311716167583335852L;
-
-        private final UserRequestRestClient restClient = new UserRequestRestClient();
-
-        public ApprovalProvider(final int paginatorRows) {
-            super(paginatorRows);
-
-            setSort("createTime", SortOrder.ASCENDING);
-        }
-
-        @Override
-        public Iterator<UserRequestForm> iterator(final long first, final long count) {
-            int page = ((int) first / paginatorRows);
-            return restClient.getForms((page < 0 ? 0 : page) + 1, paginatorRows, getSort()).iterator();
-        }
-
-        @Override
-        public long size() {
-            return restClient.countForms();
-        }
-
-        @Override
-        public IModel<UserRequestForm> model(final UserRequestForm form) {
-            return new IModel<UserRequestForm>() {
-
-                private static final long serialVersionUID = -2566070996511906708L;
-
-                @Override
-                public UserRequestForm getObject() {
-                    return form;
-                }
-            };
-        }
-    }
-
-    @Override
-    protected Collection<ActionLink.ActionType> getBatches() {
-        return Collections.<ActionLink.ActionType>emptyList();
-    }
-
-    private void claimForm(final String taskId) {
-        try {
-            restClient.claimForm(taskId);
-        } catch (SyncopeClientException scee) {
-            SyncopeConsoleSession.get().error(getString(Constants.ERROR) + ": " + scee.getMessage());
-        }
-    }
-
-    private class ApprovalUserWizardBuilder extends UserWizardBuilder {
-
-        private static final long serialVersionUID = 1854981134836384069L;
-
-        private final UserRequestForm formTO;
-
-        ApprovalUserWizardBuilder(
-                final UserRequestForm formTO,
-                final UserTO previousUserTO,
-                final UserTO userTO,
-                final List<String> anyTypeClasses,
-                final UserFormLayoutInfo formLayoutInfo,
-                final PageReference pageRef) {
-
-            super(previousUserTO, userTO, anyTypeClasses, formLayoutInfo, pageRef);
-            this.formTO = formTO;
-        }
-
-        @Override
-        protected Serializable onApplyInternal(final AnyWrapper<UserTO> modelObject) {
-            UserTO inner = modelObject.getInnerObject();
-
-            UserPatch patch = AnyOperations.diff(inner, formTO.getUserTO(), false);
-
-            if (StringUtils.isNotBlank(inner.getPassword())) {
-                PasswordPatch passwordPatch = new PasswordPatch.Builder().
-                        value(inner.getPassword()).onSyncope(true).resources(inner.
-                        getResources()).
-                        build();
-                patch.setPassword(passwordPatch);
-            }
-
-            // update just if it is changed
-            ProvisioningResult<UserTO> result;
-            if (patch.isEmpty()) {
-                result = new ProvisioningResult<>();
-                result.setEntity(inner);
-            } else {
-                result = userRestClient.update(getOriginalItem().getInnerObject().getETagValue(), patch);
-                restClient.getForm(result.getEntity().getKey()).ifPresent(form -> claimForm(form.getTaskId()));
-            }
-
-            return result;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ff37c3f7/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalModal.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalModal.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalModal.java
deleted file mode 100644
index 0cae1c8..0000000
--- a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalModal.java
+++ /dev/null
@@ -1,82 +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.approvals;
-
-import org.apache.syncope.client.console.SyncopeConsoleSession;
-import org.apache.syncope.client.console.commons.Constants;
-import org.apache.syncope.client.console.pages.BasePage;
-import org.apache.syncope.client.console.panels.MultilevelPanel;
-import org.apache.syncope.client.console.rest.UserRequestRestClient;
-import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
-import org.apache.syncope.common.lib.to.UserRequestForm;
-import org.apache.wicket.PageReference;
-import org.apache.wicket.ajax.AjaxRequestTarget;
-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 SubmitableModalPanel, WizardModalPanel<UserRequestForm> {
-
-    private static final long serialVersionUID = -8847854414429745216L;
-
-    private final UserRequestRestClient restClient = new UserRequestRestClient();
-
-    private final BaseModal<?> modal;
-
-    private final UserRequestForm formTO;
-
-    private final PageReference pageRef;
-
-    public ApprovalModal(final BaseModal<?> modal, final PageReference pageRef, final UserRequestForm formTO) {
-        super(BaseModal.CONTENT_ID);
-        this.modal = modal;
-        this.formTO = formTO;
-        this.pageRef = pageRef;
-
-        MultilevelPanel mlp = new MultilevelPanel("approval");
-        mlp.setFirstLevel(new Approval(pageRef, formTO) {
-
-            private static final long serialVersionUID = -2195387360323687302L;
-
-            @Override
-            protected void viewDetails(final AjaxRequestTarget target) {
-                mlp.next(getString("approval.details"), new ApprovalDetails(pageRef, formTO), target);
-            }
-        });
-        add(mlp);
-    }
-
-    @Override
-    public void onSubmit(final AjaxRequestTarget target) {
-        this.restClient.submitForm(formTO);
-        this.modal.show(false);
-        this.modal.close(target);
-        SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
-    }
-
-    @Override
-    public void onError(final AjaxRequestTarget target) {
-        ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
-    }
-
-    @Override
-    public UserRequestForm getItem() {
-        return this.formTO;
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ff37c3f7/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/Approvals.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/Approvals.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/Approvals.java
deleted file mode 100644
index 0dbc4db..0000000
--- a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/Approvals.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.client.console.pages;
-
-import org.apache.syncope.client.console.BookmarkablePageLinkBuilder;
-import org.apache.syncope.client.console.approvals.ApprovalDirectoryPanel;
-import org.apache.wicket.markup.html.WebMarkupContainer;
-import org.apache.wicket.request.mapper.parameter.PageParameters;
-
-public class Approvals extends BasePage {
-
-    private static final long serialVersionUID = -1100228004207271271L;
-
-    public Approvals(final PageParameters parameters) {
-        super(parameters);
-
-        body.add(BookmarkablePageLinkBuilder.build("dashboard", "dashboardBr", Dashboard.class));
-
-        WebMarkupContainer content = new WebMarkupContainer("content");
-        content.setOutputMarkupId(true);
-        body.add(content);
-
-        content.add(new ApprovalDirectoryPanel("wfPanel", getPageReference()));
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ff37c3f7/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/Flowable.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/Flowable.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/Flowable.java
index 8062a77..a533897 100644
--- a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/Flowable.java
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/Flowable.java
@@ -19,7 +19,6 @@
 package org.apache.syncope.client.console.pages;
 
 import org.apache.syncope.client.console.BookmarkablePageLinkBuilder;
-import org.apache.syncope.client.console.SyncopeConsoleSession;
 import org.apache.syncope.client.console.annotations.ExtPage;
 import org.apache.syncope.client.console.panels.BpmnProcessDirectoryPanel;
 import org.apache.syncope.client.console.wizards.WizardMgtPanel;
@@ -57,11 +56,5 @@ public class Flowable extends BaseExtPage {
         MetaDataRoleAuthorizationStrategy.authorize(bpmnProcessesPanel, ENABLE, FlowableEntitlement.BPMN_PROCESS_LIST);
 
         content.add(bpmnProcessesPanel);
-
-        if (SyncopeConsoleSession.get().getPlatformInfo().getUserWorkflowAdapter().contains("Flowable")) {
-            disabled.setVisible(false);
-        } else {
-            bpmnProcessesPanel.setVisible(false);
-        }
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/ff37c3f7/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/UserRequests.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/UserRequests.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/UserRequests.java
new file mode 100644
index 0000000..c23e1ad
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/pages/UserRequests.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.pages;
+
+import 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.UserRequestFormDirectoryPanel;
+import org.apache.syncope.client.console.panels.UserRequestDirectoryPanel;
+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.ResourceModel;
+import org.apache.wicket.request.mapper.parameter.PageParameters;
+
+public class UserRequests extends BasePage {
+
+    private static final long serialVersionUID = -1100228004207271271L;
+
+    public UserRequests(final PageParameters parameters) {
+        super(parameters);
+
+        body.add(BookmarkablePageLinkBuilder.build("dashboard", "dashboardBr", Dashboard.class));
+
+        WebMarkupContainer content = new WebMarkupContainer("content");
+        content.setOutputMarkupId(true);
+        content.setMarkupId("userRequests");
+        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("userRequestForms")) {
+
+            private static final long serialVersionUID = -6815067322125799251L;
+
+            @Override
+            public Panel getPanel(final String panelId) {
+                return new UserRequestFormDirectoryPanel(panelId, getPageReference());
+            }
+        });
+
+        tabs.add(new AbstractTab(new ResourceModel("activeRequests")) {
+
+            private static final long serialVersionUID = -6815067322125799251L;
+
+            @Override
+            public Panel getPanel(final String panelId) {
+                return new UserRequestDirectoryPanel(panelId, getPageReference());
+            }
+        });
+        return tabs;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ff37c3f7/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestDirectoryPanel.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestDirectoryPanel.java
new file mode 100644
index 0000000..3c043ac
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestDirectoryPanel.java
@@ -0,0 +1,163 @@
+/*
+ * 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 de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
+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.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.pages.BasePage;
+import org.apache.syncope.client.console.panels.UserRequestDirectoryPanel.UserRequestProvider;
+import org.apache.syncope.client.console.rest.UserRequestRestClient;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.UserRequest;
+import org.apache.syncope.common.lib.types.FlowableEntitlement;
+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.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.IModel;
+import org.apache.wicket.model.ResourceModel;
+
+public class UserRequestDirectoryPanel
+        extends DirectoryPanel<UserRequest, UserRequest, UserRequestProvider, UserRequestRestClient> {
+
+    private static final long serialVersionUID = -5346161040211617763L;
+
+    private static final String PREF_USER_REQUEST_PAGINATOR_ROWS = "userrequest.paginator.rows";
+
+    public UserRequestDirectoryPanel(final String id, final PageReference pageReference) {
+        super(id, pageReference, true);
+        disableCheckBoxes();
+        setFooterVisibility(false);
+        modal.size(Modal.Size.Large);
+
+        restClient = new UserRequestRestClient();
+
+        initResultTable();
+
+        MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, FlowableEntitlement.USER_REQUEST_LIST);
+    }
+
+    @Override
+    protected List<IColumn<UserRequest, String>> getColumns() {
+        List<IColumn<UserRequest, String>> columns = new ArrayList<>();
+
+        columns.add(new PropertyColumn<>(
+                new ResourceModel("bpmnProcess"), "bpmnProcess", "bpmnProcess"));
+        columns.add(new DatePropertyColumn<>(
+                new ResourceModel("startTime"), "startTime", "startTime"));
+        columns.add(new PropertyColumn<>(
+                new ResourceModel("username"), "username"));
+        columns.add(new PropertyColumn<>(
+                new ResourceModel("activityId"), "activityId"));
+
+        return columns;
+    }
+
+    @Override
+    public ActionsPanel<UserRequest> getActions(final IModel<UserRequest> model) {
+        final ActionsPanel<UserRequest> panel = super.getActions(model);
+
+        panel.add(new ActionLink<UserRequest>() {
+
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target, final UserRequest ignore) {
+                try {
+                    restClient.cancelRequest(model.getObject().getExecutionId(), null);
+                    SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+                    target.add(container);
+                    UserRequestDirectoryPanel.this.getTogglePanel().close(target);
+                } catch (SyncopeClientException e) {
+                    SyncopeConsoleSession.get().error(StringUtils.isBlank(e.getMessage())
+                            ? e.getClass().getName() : e.getMessage());
+                    LOG.error("While canceling execution {}", model.getObject().getExecutionId(), e);
+                }
+                ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+            }
+        }, ActionLink.ActionType.DELETE, FlowableEntitlement.USER_REQUEST_CANCEL, true);
+
+        return panel;
+    }
+
+    @Override
+    protected UserRequestProvider dataProvider() {
+        return new UserRequestProvider(rows);
+    }
+
+    @Override
+    protected String paginatorRowsKey() {
+        return PREF_USER_REQUEST_PAGINATOR_ROWS;
+    }
+
+    @Override
+    protected Collection<ActionLink.ActionType> getBatches() {
+        return Collections.<ActionLink.ActionType>emptyList();
+    }
+
+    protected static class UserRequestProvider extends DirectoryDataProvider<UserRequest> {
+
+        private static final long serialVersionUID = -1392420250782313734L;
+
+        private final UserRequestRestClient restClient = new UserRequestRestClient();
+
+        public UserRequestProvider(final int paginatorRows) {
+            super(paginatorRows);
+
+            setSort("startTime", SortOrder.ASCENDING);
+        }
+
+        @Override
+        public Iterator<UserRequest> iterator(final long first, final long count) {
+            int page = ((int) first / paginatorRows);
+            return restClient.getUserRequests((page < 0 ? 0 : page) + 1, paginatorRows, getSort()).iterator();
+        }
+
+        @Override
+        public long size() {
+            return restClient.countUserRequests();
+        }
+
+        @Override
+        public IModel<UserRequest> model(final UserRequest request) {
+            return new IModel<UserRequest>() {
+
+                private static final long serialVersionUID = -2566070996511906708L;
+
+                @Override
+                public UserRequest getObject() {
+                    return request;
+                }
+            };
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ff37c3f7/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestFormDetails.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestFormDetails.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestFormDetails.java
new file mode 100644
index 0000000..9c29105
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestFormDetails.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import org.apache.syncope.client.console.layout.UserFormLayoutInfo;
+import org.apache.syncope.client.console.rest.AnyTypeRestClient;
+import org.apache.syncope.client.console.wizards.AjaxWizard;
+import org.apache.syncope.client.console.wizards.any.UserWizardBuilder;
+import org.apache.syncope.common.lib.AnyOperations;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.to.UserRequestForm;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.wicket.PageReference;
+
+public class UserRequestFormDetails extends MultilevelPanel.SecondLevel {
+
+    private static final long serialVersionUID = -8847854414429745216L;
+
+    public UserRequestFormDetails(final PageReference pageRef, final UserRequestForm formTO) {
+        super(MultilevelPanel.SECOND_LEVEL_ID);
+
+        final UserTO newUserTO;
+        final UserTO previousUserTO;
+        if (formTO.getUserPatch() == null) {
+            newUserTO = formTO.getUserTO();
+            previousUserTO = null;
+        } else if (formTO.getUserTO() == null) {
+            // make it stronger by handling possible NPE
+            previousUserTO = new UserTO();
+            previousUserTO.setKey(formTO.getUserPatch().getKey());
+            newUserTO = AnyOperations.patch(previousUserTO, formTO.getUserPatch());
+        } else {
+            formTO.getUserTO().setKey(formTO.getUserPatch().getKey());
+            newUserTO = AnyOperations.patch(formTO.getUserTO(), formTO.getUserPatch());
+            previousUserTO = formTO.getUserTO();
+        }
+
+        add(new UserWizardBuilder(
+                previousUserTO,
+                newUserTO,
+                new AnyTypeRestClient().read(AnyTypeKind.USER.name()).getClasses(),
+                new UserFormLayoutInfo(),
+                pageRef).
+                build(AjaxWizard.Mode.READONLY));
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ff37c3f7/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestFormDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestFormDirectoryPanel.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestFormDirectoryPanel.java
new file mode 100644
index 0000000..bf82896
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestFormDirectoryPanel.java
@@ -0,0 +1,353 @@
+/*
+ * 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 de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.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.rest.UserRequestRestClient;
+import org.apache.syncope.client.console.panels.UserRequestFormDirectoryPanel.UserRequestFormProvider;
+import org.apache.syncope.client.console.layout.FormLayoutInfoUtils;
+import org.apache.syncope.client.console.layout.UserFormLayoutInfo;
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.syncope.client.console.rest.AnyTypeRestClient;
+import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
+import org.apache.syncope.client.console.widgets.UserRequestFormsWidget;
+import org.apache.syncope.client.console.wizards.AjaxWizard;
+import org.apache.syncope.client.console.wizards.any.AnyWrapper;
+import org.apache.syncope.client.console.wizards.any.UserWizardBuilder;
+import org.apache.syncope.common.lib.AnyOperations;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.patch.PasswordPatch;
+import org.apache.syncope.common.lib.patch.UserPatch;
+import org.apache.syncope.common.lib.to.ProvisioningResult;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.syncope.common.lib.to.UserRequestForm;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.syncope.common.lib.types.FlowableEntitlement;
+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.ajax.markup.html.modal.ModalWindow;
+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.Model;
+import org.apache.wicket.model.ResourceModel;
+
+public class UserRequestFormDirectoryPanel
+        extends DirectoryPanel<UserRequestForm, UserRequestForm, UserRequestFormProvider, UserRequestRestClient> {
+
+    private static final long serialVersionUID = -7122136682275797903L;
+
+    private static final String PREF_USER_REQUEST_FORM_PAGINATOR_ROWS = "userrequestform.paginator.rows";
+
+    protected final BaseModal<UserRequestForm> manageFormModal = new BaseModal<UserRequestForm>("outer") {
+
+        private static final long serialVersionUID = 389935548143327858L;
+
+        @Override
+        protected void onConfigure() {
+            super.onConfigure();
+            addSubmitButton();
+            size(Modal.Size.Large);
+        }
+
+    };
+
+    public UserRequestFormDirectoryPanel(final String id, final PageReference pageReference) {
+        super(id, pageReference, true);
+        disableCheckBoxes();
+        setFooterVisibility(false);
+        modal.size(Modal.Size.Large);
+
+        addOuterObject(manageFormModal);
+
+        manageFormModal.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
+
+            private static final long serialVersionUID = 8804221891699487139L;
+
+            @Override
+            public void onClose(final AjaxRequestTarget target) {
+                updateResultTable(target);
+
+                Serializable widget = SyncopeConsoleSession.get().getAttribute(UserRequestFormsWidget.class.getName());
+                if (widget instanceof UserRequestFormsWidget) {
+                    ((UserRequestFormsWidget) widget).refreshLatestAlerts(target);
+                }
+
+                manageFormModal.show(false);
+            }
+        });
+
+        restClient = new UserRequestRestClient();
+
+        initResultTable();
+
+        MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, FlowableEntitlement.USER_REQUEST_FORM_SUBMIT);
+    }
+
+    @Override
+    protected List<IColumn<UserRequestForm, String>> getColumns() {
+        List<IColumn<UserRequestForm, String>> columns = new ArrayList<>();
+
+        columns.add(new PropertyColumn<>(
+                new ResourceModel("bpmnProcess"), "bpmnProcess", "bpmnProcess"));
+        columns.add(new PropertyColumn<>(
+                new ResourceModel("key"), "formKey", "formKey"));
+        columns.add(new PropertyColumn<>(
+                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"));
+
+        return columns;
+    }
+
+    @Override
+    public ActionsPanel<UserRequestForm> getActions(final IModel<UserRequestForm> model) {
+        final ActionsPanel<UserRequestForm> panel = super.getActions(model);
+
+        panel.add(new ActionLink<UserRequestForm>() {
+
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target, final UserRequestForm ignore) {
+                claimForm(model.getObject().getTaskId());
+                SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+                ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+                target.add(container);
+            }
+        }, ActionLink.ActionType.CLAIM, FlowableEntitlement.USER_REQUEST_FORM_CLAIM);
+
+        panel.add(new ActionLink<UserRequestForm>() {
+
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target, final UserRequestForm ignore) {
+                manageFormModal.setFormModel(new CompoundPropertyModel<>(model.getObject()));
+
+                target.add(manageFormModal.setContent(new UserRequestFormModal(manageFormModal, pageRef, model.
+                        getObject()) {
+
+                    private static final long serialVersionUID = 5546519445061007248L;
+
+                    @Override
+                    public void onSubmit(final AjaxRequestTarget target) {
+                        try {
+                            super.onSubmit(target);
+
+                            UserRequestFormDirectoryPanel.this.getTogglePanel().close(target);
+                        } catch (SyncopeClientException e) {
+                            SyncopeConsoleSession.get().error(getString(Constants.ERROR) + ": " + e.getMessage());
+                        }
+                        ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+                    }
+
+                }));
+
+                manageFormModal.header(new Model<>(getString("form.manage", new Model<>(model.getObject()))));
+                manageFormModal.show(true);
+            }
+
+            @Override
+            protected boolean statusCondition(final UserRequestForm modelObject) {
+                return SyncopeConsoleSession.get().getSelfTO().getUsername().
+                        equals(model.getObject().getOwner());
+            }
+
+        }, ActionLink.ActionType.MANAGE_APPROVAL, FlowableEntitlement.USER_REQUEST_FORM_SUBMIT);
+
+        // SYNCOPE-1200 edit user while in approval state
+        panel.add(new ActionLink<UserRequestForm>() {
+
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target, final UserRequestForm ignore) {
+                modal.setFormModel(new CompoundPropertyModel<>(model.getObject()));
+
+                UserRequestForm formTO = model.getObject();
+                UserTO newUserTO;
+                UserTO previousUserTO;
+                if (formTO.getUserPatch() == null) {
+                    newUserTO = formTO.getUserTO();
+                    previousUserTO = null;
+                } else if (formTO.getUserTO() == null) {
+                    // make it stronger by handling possible NPE
+                    previousUserTO = new UserTO();
+                    previousUserTO.setKey(formTO.getUserPatch().getKey());
+                    newUserTO = AnyOperations.patch(previousUserTO, formTO.getUserPatch());
+                } else {
+                    previousUserTO = formTO.getUserTO();
+                    formTO.getUserTO().setKey(formTO.getUserPatch().getKey());
+                    formTO.getUserTO().setPassword(null);
+                    newUserTO = AnyOperations.patch(formTO.getUserTO(), formTO.getUserPatch());
+                }
+
+                AjaxWizard.EditItemActionEvent<UserTO> editItemActionEvent =
+                        new AjaxWizard.EditItemActionEvent<>(newUserTO, target);
+                editItemActionEvent.forceModalPanel(new FormUserWizardBuilder(
+                        model.getObject(),
+                        previousUserTO,
+                        newUserTO,
+                        new AnyTypeRestClient().read(AnyTypeKind.USER.name()).getClasses(),
+                        FormLayoutInfoUtils.fetch(Collections.singletonList(AnyTypeKind.USER.name())).getLeft(),
+                        pageRef
+                ).build(BaseModal.CONTENT_ID, AjaxWizard.Mode.EDIT));
+
+                send(UserRequestFormDirectoryPanel.this, Broadcast.EXACT, editItemActionEvent);
+            }
+
+            @Override
+            protected boolean statusCondition(final UserRequestForm modelObject) {
+                return SyncopeConsoleSession.get().getSelfTO().getUsername().
+                        equals(model.getObject().getOwner());
+            }
+
+        }, ActionLink.ActionType.EDIT_APPROVAL, FlowableEntitlement.USER_REQUEST_FORM_SUBMIT);
+
+        return panel;
+    }
+
+    @Override
+    protected UserRequestFormProvider dataProvider() {
+        return new UserRequestFormProvider(rows);
+    }
+
+    @Override
+    protected String paginatorRowsKey() {
+        return PREF_USER_REQUEST_FORM_PAGINATOR_ROWS;
+    }
+
+    protected static class UserRequestFormProvider extends DirectoryDataProvider<UserRequestForm> {
+
+        private static final long serialVersionUID = -2311716167583335852L;
+
+        private final UserRequestRestClient restClient = new UserRequestRestClient();
+
+        public UserRequestFormProvider(final int paginatorRows) {
+            super(paginatorRows);
+
+            setSort("createTime", SortOrder.ASCENDING);
+        }
+
+        @Override
+        public Iterator<UserRequestForm> iterator(final long first, final long count) {
+            int page = ((int) first / paginatorRows);
+            return restClient.getForms((page < 0 ? 0 : page) + 1, paginatorRows, getSort()).iterator();
+        }
+
+        @Override
+        public long size() {
+            return restClient.countForms();
+        }
+
+        @Override
+        public IModel<UserRequestForm> model(final UserRequestForm form) {
+            return new IModel<UserRequestForm>() {
+
+                private static final long serialVersionUID = -2566070996511906708L;
+
+                @Override
+                public UserRequestForm getObject() {
+                    return form;
+                }
+            };
+        }
+    }
+
+    @Override
+    protected Collection<ActionLink.ActionType> getBatches() {
+        return Collections.<ActionLink.ActionType>emptyList();
+    }
+
+    private void claimForm(final String taskId) {
+        try {
+            restClient.claimForm(taskId);
+        } catch (SyncopeClientException scee) {
+            SyncopeConsoleSession.get().error(getString(Constants.ERROR) + ": " + scee.getMessage());
+        }
+    }
+
+    private class FormUserWizardBuilder extends UserWizardBuilder {
+
+        private static final long serialVersionUID = 1854981134836384069L;
+
+        private final UserRequestForm formTO;
+
+        FormUserWizardBuilder(
+                final UserRequestForm formTO,
+                final UserTO previousUserTO,
+                final UserTO userTO,
+                final List<String> anyTypeClasses,
+                final UserFormLayoutInfo formLayoutInfo,
+                final PageReference pageRef) {
+
+            super(previousUserTO, userTO, anyTypeClasses, formLayoutInfo, pageRef);
+            this.formTO = formTO;
+        }
+
+        @Override
+        protected Serializable onApplyInternal(final AnyWrapper<UserTO> modelObject) {
+            UserTO inner = modelObject.getInnerObject();
+
+            UserPatch patch = AnyOperations.diff(inner, formTO.getUserTO(), false);
+
+            if (StringUtils.isNotBlank(inner.getPassword())) {
+                PasswordPatch passwordPatch = new PasswordPatch.Builder().
+                        value(inner.getPassword()).onSyncope(true).resources(inner.
+                        getResources()).
+                        build();
+                patch.setPassword(passwordPatch);
+            }
+
+            // update just if it is changed
+            ProvisioningResult<UserTO> result;
+            if (patch.isEmpty()) {
+                result = new ProvisioningResult<>();
+                result.setEntity(inner);
+            } else {
+                result = userRestClient.update(getOriginalItem().getInnerObject().getETagValue(), patch);
+                restClient.getForm(result.getEntity().getKey()).ifPresent(form -> claimForm(form.getTaskId()));
+            }
+
+            return result;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/ff37c3f7/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestFormModal.java
----------------------------------------------------------------------
diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestFormModal.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestFormModal.java
new file mode 100644
index 0000000..07a7950
--- /dev/null
+++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestFormModal.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.pages.BasePage;
+import org.apache.syncope.client.console.rest.UserRequestRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.syncope.common.lib.to.UserRequestForm;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.html.panel.Panel;
+
+public class UserRequestFormModal extends Panel implements SubmitableModalPanel, WizardModalPanel<UserRequestForm> {
+
+    private static final long serialVersionUID = -8847854414429745216L;
+
+    private final UserRequestRestClient restClient = new UserRequestRestClient();
+
+    private final BaseModal<?> modal;
+
+    private final UserRequestForm formTO;
+
+    private final PageReference pageRef;
+
+    public UserRequestFormModal(final BaseModal<?> modal, final PageReference pageRef, final UserRequestForm formTO) {
+        super(BaseModal.CONTENT_ID);
+        this.modal = modal;
+        this.formTO = formTO;
+        this.pageRef = pageRef;
+
+        MultilevelPanel mlp = new MultilevelPanel("userRequestForm");
+        mlp.setFirstLevel(new UserRequestFormPanel(pageRef, formTO) {
+
+            private static final long serialVersionUID = -2195387360323687302L;
+
+            @Override
+            protected void viewDetails(final AjaxRequestTarget target) {
+                mlp.next(getString("userRequest.details"), new UserRequestFormDetails(pageRef, formTO), target);
+            }
+        });
+        add(mlp);
+    }
+
+    @Override
+    public void onSubmit(final AjaxRequestTarget target) {
+        this.restClient.submitForm(formTO);
+        this.modal.show(false);
+        this.modal.close(target);
+        SyncopeConsoleSession.get().info(getString(Constants.OPERATION_SUCCEEDED));
+    }
+
+    @Override
+    public void onError(final AjaxRequestTarget target) {
+        ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
+    }
+
+    @Override
+    public UserRequestForm getItem() {
+        return this.formTO;
+    }
+}