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 2016/04/26 17:46:33 UTC

[3/4] syncope git commit: [SYNCOPE-790] Now binding JSON configuration to role which allows to selectively enable user / group / anyObject wizard steps, customize plain / derived / virtual attributes appearance order and even providing custom class

[SYNCOPE-790] Now binding JSON configuration to role which allows to selectively enable user / group / anyObject wizard steps, customize plain / derived / virtual attributes appearance order and even providing custom class


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

Branch: refs/heads/master
Commit: 5b47ab2354a0272ad9c5d3298d8a1fc2565a0c1f
Parents: 8dc9ec5
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Tue Apr 26 17:45:57 2016 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Tue Apr 26 17:46:19 2016 +0200

----------------------------------------------------------------------
 .../console/approvals/ApprovalDetails.java      |  16 +--
 .../approvals/ApprovalDirectoryPanel.java       |   2 +-
 .../client/console/commons/AttrLayoutType.java  |  95 ------------
 .../syncope/client/console/commons/Mode.java    |   1 -
 .../console/layout/AbstractAnyFormLayout.java   | 110 ++++++++++++++
 .../syncope/client/console/layout/AnyForm.java  |  27 ++++
 .../client/console/layout/AnyObjectForm.java    |  25 ++++
 .../console/layout/AnyObjectFormLayoutInfo.java |  43 ++++++
 .../console/layout/ConsoleLayoutInfoModal.java  | 114 +++++++++++++++
 .../console/layout/FormLayoutInfoUtils.java     | 144 +++++++++++++++++++
 .../client/console/layout/GroupForm.java        |  25 ++++
 .../console/layout/GroupFormLayoutInfo.java     |  63 ++++++++
 .../syncope/client/console/layout/UserForm.java |  25 ++++
 .../console/layout/UserFormLayoutInfo.java      |  63 ++++++++
 .../notifications/MailTemplateContentModal.java |  15 +-
 .../MailTemplateDirectoryPanel.java             |  13 +-
 .../syncope/client/console/pages/BasePage.java  |   6 -
 .../syncope/client/console/pages/Layouts.java   |  33 -----
 .../syncope/client/console/panels/AnyPanel.java |  55 ++++---
 .../syncope/client/console/panels/Realm.java    |  12 +-
 .../console/panels/RoleDirectoryPanel.java      |  25 ++++
 .../panels/XMLWorkflowEditorModalPanel.java     |   3 +
 .../console/rest/ConfigurationRestClient.java   |  30 +---
 .../console/rest/NotificationRestClient.java    |   6 +-
 .../client/console/rest/RoleRestClient.java     |  30 +++-
 .../client/console/rest/SchemaRestClient.java   |  17 ---
 .../wicket/markup/html/form/ActionLink.java     |   1 +
 .../markup/html/form/ActionLinksPanel.java      |  20 +++
 .../client/console/widgets/ApprovalsWidget.java |   5 +-
 .../wizards/AbstractModalPanelBuilder.java      |  22 +--
 .../console/wizards/ModalPanelBuilder.java      |  49 +++++++
 .../client/console/wizards/WizardMgtPanel.java  |  16 ++-
 .../console/wizards/any/AbstractAttrs.java      | 116 +++++++++++++--
 .../wizards/any/AnyObjectWizardBuilder.java     |  29 ++--
 .../console/wizards/any/AnyWizardBuilder.java   | 100 +++++++++----
 .../client/console/wizards/any/AuxClasses.java  |   9 +-
 .../client/console/wizards/any/DerAttrs.java    | 105 ++++++--------
 .../client/console/wizards/any/Details.java     |   5 +-
 .../console/wizards/any/GroupDetails.java       |   8 +-
 .../console/wizards/any/GroupWizardBuilder.java |  45 +++---
 .../client/console/wizards/any/PlainAttrs.java  | 134 ++++++-----------
 .../client/console/wizards/any/Roles.java       |   2 +-
 .../client/console/wizards/any/UserDetails.java |  11 +-
 .../wizards/any/UserInformationPanel.java       |  10 +-
 .../console/wizards/any/UserWizardBuilder.java  |  34 +++--
 .../client/console/wizards/any/VirAttrs.java    | 103 ++++++-------
 .../console/layout/ConsoleLayoutInfoModal.html  |  54 +++++++
 .../notifications/MailTemplateContentModal.html |  64 ++++-----
 .../syncope/client/console/pages/BasePage.html  |   1 -
 .../syncope/client/console/pages/Layouts.html   |  43 ------
 .../panels/XMLWorkflowEditorModalPanel.html     |   1 +
 .../markup/html/form/ActionLinksPanel.html      |   7 +-
 .../client/console/wizards/any/DerAttrs.html    |  25 ++--
 .../client/console/wizards/any/VirAttrs.html    |  25 ++--
 .../syncope/common/lib/to/WorkflowFormTO.java   |  20 +--
 .../common/rest/api/service/RoleService.java    |  32 +++++
 .../apache/syncope/core/logic/RoleLogic.java    |  35 ++++-
 .../core/persistence/api/entity/Role.java       |   4 +
 .../core/persistence/jpa/entity/JPARole.java    |  15 ++
 .../main/resources/domains/MasterContent.xml    |  14 --
 .../persistence/jpa/inner/MultitenancyTest.java |   2 +-
 .../persistence/jpa/inner/PlainSchemaTest.java  |   2 +-
 .../test/resources/domains/MasterContent.xml    |  16 +--
 .../src/test/resources/domains/TwoContent.xml   |  14 --
 .../core/rest/cxf/service/RoleServiceImpl.java  |  38 +++++
 .../activiti/ActivitiUserWorkflowAdapter.java   |   4 +-
 .../console/panels/CamelRoutesDetailsPanel.java |   2 +
 .../console/panels/CamelRoutesDetailsPanel.html |   1 +
 .../apache/syncope/fit/console/BaseITCase.java  |   4 -
 .../syncope/fit/core/MultitenancyITCase.java    |   2 +-
 .../syncope/fit/core/UserWorkflowITCase.java    |   4 +-
 71 files changed, 1485 insertions(+), 766 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDetails.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDetails.java b/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDetails.java
index c5787ed..d2d9c41 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDetails.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/approvals/ApprovalDetails.java
@@ -18,14 +18,12 @@
  */
 package org.apache.syncope.client.console.approvals;
 
-import java.util.List;
+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.rest.UserRestClient;
 import org.apache.syncope.client.console.wizards.AjaxWizard;
-import org.apache.syncope.client.console.wizards.any.AnyHandler;
 import org.apache.syncope.client.console.wizards.any.UserWizardBuilder;
-import org.apache.syncope.common.lib.to.UserTO;
 import org.apache.syncope.common.lib.to.WorkflowFormTO;
 import org.apache.syncope.common.lib.types.AnyTypeKind;
 import org.apache.wicket.PageReference;
@@ -37,12 +35,10 @@ public class ApprovalDetails extends MultilevelPanel.SecondLevel {
     public ApprovalDetails(final PageReference pageRef, final WorkflowFormTO formTO) {
         super(MultilevelPanel.SECOND_LEVEL_ID);
 
-        final UserTO userTO = new UserRestClient().read(formTO.getUserKey());
-        final List<String> anyTypeClasses = new AnyTypeRestClient().read(AnyTypeKind.USER.name()).getClasses();
-
-        final AjaxWizard<AnyHandler<UserTO>> wizard = new UserWizardBuilder(userTO, anyTypeClasses, pageRef).
-                build(AjaxWizard.Mode.READONLY);
-
-        add(wizard);
+        add(new UserWizardBuilder(new UserRestClient().read(formTO.getUsername()),
+                new AnyTypeRestClient().read(AnyTypeKind.USER.name()).getClasses(),
+                new UserFormLayoutInfo(),
+                pageRef).
+                build(AjaxWizard.Mode.READONLY));
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/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 bfe72e0..b176205 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
@@ -79,7 +79,7 @@ public class ApprovalDirectoryPanel
         columns.add(new PropertyColumn<WorkflowFormTO, String>(
                 new ResourceModel("key"), "key", "key"));
         columns.add(new PropertyColumn<WorkflowFormTO, String>(
-                new ResourceModel("description"), "description", "description"));
+                new ResourceModel("username"), "username", "username"));
         columns.add(new DatePropertyColumn<WorkflowFormTO>(
                 new ResourceModel("createTime"), "createTime", "createTime"));
         columns.add(new DatePropertyColumn<WorkflowFormTO>(

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/commons/AttrLayoutType.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/AttrLayoutType.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/AttrLayoutType.java
deleted file mode 100644
index 9aefe4c..0000000
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/AttrLayoutType.java
+++ /dev/null
@@ -1,95 +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.commons;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.syncope.common.lib.types.AnyTypeKind;
-
-public enum AttrLayoutType {
-
-    ADMIN_USER("admin.user.layout", Mode.ADMIN, AnyTypeKind.USER),
-    SELF_USER("self.user.layout", Mode.SELF, AnyTypeKind.USER),
-    ADMIN_GROUP("admin.group.layout", Mode.ADMIN, AnyTypeKind.GROUP),
-    SELF_GROUP("self.group.layout", Mode.SELF, AnyTypeKind.GROUP);
-
-    private final String confKey;
-
-    private final Mode mode;
-
-    private final AnyTypeKind anyTypeKind;
-
-    AttrLayoutType(final String confKey, final Mode mode, final AnyTypeKind anyTypeKind) {
-        this.confKey = confKey;
-        this.mode = mode;
-        this.anyTypeKind = anyTypeKind;
-    }
-
-    public String getConfKey() {
-        return confKey;
-    }
-
-    public Mode getMode() {
-        return mode;
-    }
-
-    public AnyTypeKind getAnyTypeKind() {
-        return anyTypeKind;
-    }
-
-    public static List<String> confKeys() {
-        List<String> confKeys = new ArrayList<>();
-        for (AttrLayoutType value : values()) {
-            confKeys.add(value.getConfKey());
-        }
-
-        return confKeys;
-    }
-
-    public static AttrLayoutType valueOf(final Mode mode, final AnyTypeKind anyTypeKind) {
-        AttrLayoutType result = null;
-        if (mode == Mode.ADMIN) {
-            switch (anyTypeKind) {
-                case USER:
-                    result = ADMIN_USER;
-                    break;
-
-                case GROUP:
-                    result = ADMIN_GROUP;
-                    break;
-
-                default:
-            }
-        } else if (mode == Mode.SELF) {
-            switch (anyTypeKind) {
-                case USER:
-                    result = SELF_USER;
-                    break;
-
-                case GROUP:
-                    result = SELF_GROUP;
-                    break;
-
-                default:
-            }
-        }
-
-        return result;
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/commons/Mode.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/commons/Mode.java b/client/console/src/main/java/org/apache/syncope/client/console/commons/Mode.java
index 27dad64..3d4c956 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/commons/Mode.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/commons/Mode.java
@@ -21,7 +21,6 @@ package org.apache.syncope.client.console.commons;
 public enum Mode {
 
     ADMIN,
-    SELF,
     TEMPLATE;
 
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/layout/AbstractAnyFormLayout.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/layout/AbstractAnyFormLayout.java b/client/console/src/main/java/org/apache/syncope/client/console/layout/AbstractAnyFormLayout.java
new file mode 100644
index 0000000..91c887a
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/layout/AbstractAnyFormLayout.java
@@ -0,0 +1,110 @@
+/*
+ * 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.layout;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.syncope.common.lib.to.AnyTO;
+
+public abstract class AbstractAnyFormLayout<A extends AnyTO, F extends AnyForm<A>> implements Serializable {
+
+    private static final long serialVersionUID = -6061683026789976508L;
+
+    private Class<F> formClass;
+
+    private boolean auxClasses = true;
+
+    private boolean plainAttrs = true;
+
+    private final List<String> whichPlainAttrs = new ArrayList<>();
+
+    private boolean derAttrs = true;
+
+    private final List<String> whichDerAttrs = new ArrayList<>();
+
+    private boolean virAttrs = true;
+
+    private final List<String> whichVirAttrs = new ArrayList<>();
+
+    private boolean resources = true;
+
+    protected abstract Class<? extends F> getDefaultFormClass();
+
+    public Class<? extends F> getFormClass() {
+        return formClass == null ? getDefaultFormClass() : formClass;
+    }
+
+    public void setFormClass(final Class<F> formClass) {
+        this.formClass = formClass;
+    }
+
+    public boolean isAuxClasses() {
+        return auxClasses;
+    }
+
+    public void setAuxClasses(final boolean auxClasses) {
+        this.auxClasses = auxClasses;
+    }
+
+    public boolean isPlainAttrs() {
+        return plainAttrs;
+    }
+
+    public void setPlainAttrs(final boolean plainAttrs) {
+        this.plainAttrs = plainAttrs;
+    }
+
+    public List<String> getWhichPlainAttrs() {
+        return whichPlainAttrs;
+    }
+
+    public boolean isDerAttrs() {
+        return derAttrs;
+    }
+
+    public void setDerAttrs(final boolean derAttrs) {
+        this.derAttrs = derAttrs;
+    }
+
+    public List<String> getWhichDerAttrs() {
+        return whichDerAttrs;
+    }
+
+    public boolean isVirAttrs() {
+        return virAttrs;
+    }
+
+    public void setVirAttrs(final boolean virAttrs) {
+        this.virAttrs = virAttrs;
+    }
+
+    public List<String> getWhichVirAttrs() {
+        return whichVirAttrs;
+    }
+
+    public boolean isResources() {
+        return resources;
+    }
+
+    public void setResources(final boolean resources) {
+        this.resources = resources;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyForm.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyForm.java b/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyForm.java
new file mode 100644
index 0000000..fc02efe
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyForm.java
@@ -0,0 +1,27 @@
+/*
+ * 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.layout;
+
+import org.apache.syncope.client.console.wizards.ModalPanelBuilder;
+import org.apache.syncope.client.console.wizards.any.AnyHandler;
+import org.apache.syncope.common.lib.to.AnyTO;
+
+public interface AnyForm<A extends AnyTO> extends ModalPanelBuilder<AnyHandler<A>> {
+
+}

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

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyObjectFormLayoutInfo.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyObjectFormLayoutInfo.java b/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyObjectFormLayoutInfo.java
new file mode 100644
index 0000000..211aa25
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/layout/AnyObjectFormLayoutInfo.java
@@ -0,0 +1,43 @@
+/*
+ * 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.layout;
+
+import org.apache.syncope.client.console.wizards.any.AnyObjectWizardBuilder;
+import org.apache.syncope.common.lib.to.AnyObjectTO;
+
+public class AnyObjectFormLayoutInfo extends AbstractAnyFormLayout<AnyObjectTO, AnyObjectForm> {
+
+    private static final long serialVersionUID = -5573691733739618500L;
+
+    private boolean relationships = true;
+
+    @Override
+    protected Class<? extends AnyObjectForm> getDefaultFormClass() {
+        return AnyObjectWizardBuilder.class;
+    }
+
+    public boolean isRelationships() {
+        return relationships;
+    }
+
+    public void setRelationships(final boolean relationships) {
+        this.relationships = relationships;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/layout/ConsoleLayoutInfoModal.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/layout/ConsoleLayoutInfoModal.java b/client/console/src/main/java/org/apache/syncope/client/console/layout/ConsoleLayoutInfoModal.java
new file mode 100644
index 0000000..2b48d49
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/layout/ConsoleLayoutInfoModal.java
@@ -0,0 +1,114 @@
+/*
+ * 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.layout;
+
+import java.io.Serializable;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.panels.AbstractModalPanel;
+import org.apache.syncope.client.console.rest.AnyTypeRestClient;
+import org.apache.syncope.client.console.rest.RoleRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.OnLoadHeaderItem;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.TextArea;
+import org.apache.wicket.model.PropertyModel;
+
+public class ConsoleLayoutInfoModal extends AbstractModalPanel<Serializable> {
+
+    private static final long serialVersionUID = -5110368813584745668L;
+
+    private final ConsoleLayoutInfo consoleLayoutInfo;
+
+    public ConsoleLayoutInfoModal(
+            final BaseModal<Serializable> modal,
+            final ConsoleLayoutInfo consoleLayoutInfo,
+            final PageReference pageRef) {
+
+        super(modal, pageRef);
+        this.consoleLayoutInfo = consoleLayoutInfo;
+
+        TextArea<String> consoleLayoutInfoDefArea =
+                new TextArea<>("consoleLayoutInfo", new PropertyModel<String>(consoleLayoutInfo, "content"));
+        consoleLayoutInfoDefArea.setMarkupId("consoleLayoutInfo").setOutputMarkupPlaceholderTag(true);
+        add(consoleLayoutInfoDefArea);
+    }
+
+    @Override
+    public void renderHead(final IHeaderResponse response) {
+        super.renderHead(response);
+        response.render(OnLoadHeaderItem.forScript(
+                "CodeMirror.fromTextArea(document.getElementById('consoleLayoutInfo'), {"
+                + "  lineNumbers: true, "
+                + "  lineWrapping: true, "
+                + "  matchBrackets: true,"
+                + "  autoCloseBrackets: true,"
+                + "  autoRefresh: true"
+                + "}).on('change', updateTextArea);"));
+    }
+
+    @Override
+    public ConsoleLayoutInfo getItem() {
+        return consoleLayoutInfo;
+    }
+
+    @Override
+    public void onSubmit(final AjaxRequestTarget target, final Form<?> form) {
+        try {
+            new RoleRestClient().setConsoleLayoutInfo(
+                    consoleLayoutInfo.getKey(), consoleLayoutInfo.getContent());
+            info(getString(Constants.OPERATION_SUCCEEDED));
+            modal.show(false);
+            modal.close(target);
+        } catch (Exception e) {
+            LOG.error("While updating onsole layout info for role {}", consoleLayoutInfo.getKey(), e);
+            error(StringUtils.isBlank(e.getMessage()) ? e.getClass().getName() : e.getMessage());
+        }
+        SyncopeConsoleSession.get().getNotificationPanel().refresh(target);
+    }
+
+    public static class ConsoleLayoutInfo implements Serializable {
+
+        private static final long serialVersionUID = 961267717148831831L;
+
+        private final String key;
+
+        private String content;
+
+        public ConsoleLayoutInfo(final String key) {
+            this.key = key;
+        }
+
+        public String getKey() {
+            return key;
+        }
+
+        public String getContent() {
+            return content;
+        }
+
+        public void setContent(final String content) {
+            this.content = FormLayoutInfoUtils.defaultConsoleLayoutInfoIfEmpty(content, new AnyTypeRestClient().list());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/layout/FormLayoutInfoUtils.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/layout/FormLayoutInfoUtils.java b/client/console/src/main/java/org/apache/syncope/client/console/layout/FormLayoutInfoUtils.java
new file mode 100644
index 0000000..a5caccb
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/layout/FormLayoutInfoUtils.java
@@ -0,0 +1,144 @@
+/*
+ * 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.layout;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Triple;
+import org.apache.syncope.client.console.SyncopeConsoleSession;
+import org.apache.syncope.client.console.rest.RoleRestClient;
+import org.apache.syncope.common.lib.to.AnyTO;
+import org.apache.syncope.common.lib.to.AnyTypeTO;
+import org.apache.syncope.common.lib.types.AnyTypeKind;
+import org.apache.wicket.PageReference;
+
+/**
+ * Utility methods for dealing with form layout information.
+ */
+public final class FormLayoutInfoUtils {
+
+    private static final RoleRestClient ROLE_REST_CLIENT = new RoleRestClient();
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    public static Triple<UserFormLayoutInfo, GroupFormLayoutInfo, Map<String, AnyObjectFormLayoutInfo>> fetch(
+            final List<AnyTypeTO> anyTypeTOs) {
+
+        List<String> ownedRoles = SyncopeConsoleSession.get().getSelfTO().getRoles();
+        try {
+            JsonNode tree = null;
+            for (int i = 0; i < ownedRoles.size() && tree == null; i++) {
+                String consoleLayoutInfo = ROLE_REST_CLIENT.readConsoleLayoutInfo(ownedRoles.get(i));
+                if (StringUtils.isNotBlank(consoleLayoutInfo)) {
+                    tree = MAPPER.readTree(consoleLayoutInfo);
+                }
+            }
+            if (tree == null) {
+                tree = MAPPER.createObjectNode();
+            }
+
+            UserFormLayoutInfo userFormLayoutInfo = tree.has(AnyTypeKind.USER.name())
+                    ? MAPPER.treeToValue(tree.get(AnyTypeKind.USER.name()), UserFormLayoutInfo.class)
+                    : new UserFormLayoutInfo();
+
+            GroupFormLayoutInfo groupFormLayoutInfo = tree.has(AnyTypeKind.USER.name())
+                    ? MAPPER.treeToValue(tree.get(AnyTypeKind.GROUP.name()), GroupFormLayoutInfo.class)
+                    : new GroupFormLayoutInfo();
+
+            Map<String, AnyObjectFormLayoutInfo> anyObjectFormLayoutInfos = new HashMap<>();
+            for (AnyTypeTO anyTypeTO : anyTypeTOs) {
+                if (!anyTypeTO.getKey().equals(AnyTypeKind.USER.name())
+                        && !anyTypeTO.getKey().equals(AnyTypeKind.GROUP.name())) {
+
+                    anyObjectFormLayoutInfos.put(
+                            anyTypeTO.getKey(),
+                            tree.has(anyTypeTO.getKey())
+                            ? MAPPER.treeToValue(tree.get(anyTypeTO.getKey()), AnyObjectFormLayoutInfo.class)
+                            : new AnyObjectFormLayoutInfo());
+                }
+            }
+
+            return Triple.of(userFormLayoutInfo, groupFormLayoutInfo, anyObjectFormLayoutInfos);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("While parsing console layout info for "
+                    + SyncopeConsoleSession.get().getSelfTO().getUsername(), e);
+        }
+    }
+
+    public static String defaultConsoleLayoutInfoIfEmpty(final String content, final List<AnyTypeTO> anyTypeTOs) {
+        String result;
+
+        if (StringUtils.isBlank(content)) {
+            try {
+                ObjectNode tree = MAPPER.createObjectNode();
+
+                tree.set(AnyTypeKind.USER.name(), MAPPER.valueToTree(new UserFormLayoutInfo()));
+                tree.set(AnyTypeKind.GROUP.name(), MAPPER.valueToTree(new GroupFormLayoutInfo()));
+                for (AnyTypeTO anyTypeTO : anyTypeTOs) {
+                    if (!anyTypeTO.getKey().equals(AnyTypeKind.USER.name())
+                            && !anyTypeTO.getKey().equals(AnyTypeKind.GROUP.name())) {
+
+                        tree.set(anyTypeTO.getKey(), MAPPER.valueToTree(new AnyObjectFormLayoutInfo()));
+                    }
+                }
+
+                result = MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(tree);
+            } catch (IOException e) {
+                throw new IllegalArgumentException("While generating default console layout info for "
+                        + SyncopeConsoleSession.get().getSelfTO().getUsername(), e);
+            }
+        } else {
+            try {
+                result = MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(MAPPER.readTree(content));
+            } catch (IOException e) {
+                result = content;
+            }
+        }
+
+        return result;
+    }
+
+    public static <A extends AnyTO, F extends AnyForm<A>, FL extends AbstractAnyFormLayout<A, F>> F instantiate(
+            final A anyTO,
+            final List<String> anyTypeClasses,
+            final FL anyFormLayout,
+            final PageReference pageRef) {
+
+        try {
+            return anyFormLayout.getFormClass().getConstructor(
+                    anyTO.getClass(),
+                    List.class,
+                    anyFormLayout.getClass(),
+                    pageRef.getClass()).
+                    newInstance(anyTO, anyTypeClasses, anyFormLayout, pageRef);
+        } catch (Exception e) {
+            throw new IllegalArgumentException("Could not instantiate " + anyFormLayout.getFormClass().getName(), e);
+        }
+    }
+
+    private FormLayoutInfoUtils() {
+        // private constructor for static utility class
+    }
+}

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

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/layout/GroupFormLayoutInfo.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/layout/GroupFormLayoutInfo.java b/client/console/src/main/java/org/apache/syncope/client/console/layout/GroupFormLayoutInfo.java
new file mode 100644
index 0000000..9296300
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/layout/GroupFormLayoutInfo.java
@@ -0,0 +1,63 @@
+/*
+ * 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.layout;
+
+import org.apache.syncope.client.console.wizards.any.GroupWizardBuilder;
+import org.apache.syncope.common.lib.to.GroupTO;
+
+public class GroupFormLayoutInfo extends AbstractAnyFormLayout<GroupTO, GroupForm> {
+
+    private static final long serialVersionUID = -5573691733739618500L;
+
+    private boolean ownership = true;
+
+    private boolean dynamicMemberships = true;
+
+    private boolean typeExtension = true;
+
+    @Override
+    protected Class<? extends GroupForm> getDefaultFormClass() {
+        return GroupWizardBuilder.class;
+    }
+
+    public boolean isOwnership() {
+        return ownership;
+    }
+
+    public void setOwnership(final boolean ownership) {
+        this.ownership = ownership;
+    }
+
+    public boolean isDynamicMemberships() {
+        return dynamicMemberships;
+    }
+
+    public void setDynamicMemberships(final boolean dynamicMemberships) {
+        this.dynamicMemberships = dynamicMemberships;
+    }
+
+    public boolean isTypeExtension() {
+        return typeExtension;
+    }
+
+    public void setTypeExtension(final boolean typeExtension) {
+        this.typeExtension = typeExtension;
+    }
+
+}

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

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/layout/UserFormLayoutInfo.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/layout/UserFormLayoutInfo.java b/client/console/src/main/java/org/apache/syncope/client/console/layout/UserFormLayoutInfo.java
new file mode 100644
index 0000000..c100143
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/layout/UserFormLayoutInfo.java
@@ -0,0 +1,63 @@
+/*
+ * 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.layout;
+
+import org.apache.syncope.client.console.wizards.any.UserWizardBuilder;
+import org.apache.syncope.common.lib.to.UserTO;
+
+public class UserFormLayoutInfo extends AbstractAnyFormLayout<UserTO, UserForm> {
+
+    private static final long serialVersionUID = -5573691733739618500L;
+
+    private boolean passwordManagement = true;
+
+    private boolean roles = true;
+
+    private boolean relationships = true;
+
+    @Override
+    protected Class<? extends UserForm> getDefaultFormClass() {
+        return UserWizardBuilder.class;
+    }
+
+    public boolean isPasswordManagement() {
+        return passwordManagement;
+    }
+
+    public void setPasswordManagement(final boolean passwordManagement) {
+        this.passwordManagement = passwordManagement;
+    }
+
+    public boolean isRoles() {
+        return roles;
+    }
+
+    public void setRoles(final boolean roles) {
+        this.roles = roles;
+    }
+
+    public boolean isRelationships() {
+        return relationships;
+    }
+
+    public void setRelationships(final boolean relationships) {
+        this.relationships = relationships;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateContentModal.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateContentModal.java b/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateContentModal.java
index 9603446..55804cb 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateContentModal.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateContentModal.java
@@ -25,7 +25,6 @@ import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.panels.AbstractModalPanel;
 import org.apache.syncope.client.console.rest.NotificationRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
-import org.apache.syncope.common.lib.AbstractBaseBean;
 import org.apache.syncope.common.lib.types.MailTemplateFormat;
 import org.apache.wicket.PageReference;
 import org.apache.wicket.ajax.AjaxRequestTarget;
@@ -39,12 +38,13 @@ public class MailTemplateContentModal extends AbstractModalPanel<Serializable> {
 
     private static final long serialVersionUID = 2053048734388383021L;
 
-    private final MailTemplateContentTO content;
+    private final MailTemplateContent content;
 
     public MailTemplateContentModal(
             final BaseModal<Serializable> modal,
-            final MailTemplateContentTO content,
+            final MailTemplateContent content,
             final PageReference pageRef) {
+
         super(modal, pageRef);
         this.content = content;
 
@@ -59,12 +59,15 @@ public class MailTemplateContentModal extends AbstractModalPanel<Serializable> {
         response.render(OnLoadHeaderItem.forScript(
                 "CodeMirror.fromTextArea(document.getElementById('template'), {"
                 + "  lineNumbers: true, "
+                + "  lineWrapping: true, "
+                + "  autoCloseTags: true, "
+                + "  mode: 'text/html', "
                 + "  autoRefresh: true"
                 + "}).on('change', updateTextArea);"));
     }
 
     @Override
-    public MailTemplateContentTO getItem() {
+    public MailTemplateContent getItem() {
         return this.content;
     }
 
@@ -83,7 +86,7 @@ public class MailTemplateContentModal extends AbstractModalPanel<Serializable> {
         SyncopeConsoleSession.get().getNotificationPanel().refresh(target);
     }
 
-    public static class MailTemplateContentTO extends AbstractBaseBean {
+    public static class MailTemplateContent implements Serializable {
 
         private static final long serialVersionUID = -1756961687134322845L;
 
@@ -93,7 +96,7 @@ public class MailTemplateContentModal extends AbstractModalPanel<Serializable> {
 
         private final MailTemplateFormat format;
 
-        public MailTemplateContentTO(final String key, final MailTemplateFormat format) {
+        public MailTemplateContent(final String key, final MailTemplateFormat format) {
             this.key = key;
             this.format = format;
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java
index 566d2b8..b6fee1a 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/notifications/MailTemplateDirectoryPanel.java
@@ -66,13 +66,12 @@ public class MailTemplateDirectoryPanel
         super(id, pageReference, true);
         disableCheckBoxes();
 
-        addOuterObject(utilityModal);
-        setWindowClosedReloadCallback(utilityModal);
-
         modal.size(Modal.Size.Small);
         modal.addSumbitButton();
         setFooterVisibility(true);
 
+        addOuterObject(utilityModal);
+        setWindowClosedReloadCallback(utilityModal);
         utilityModal.size(Modal.Size.Large);
         utilityModal.addSumbitButton();
 
@@ -114,8 +113,8 @@ public class MailTemplateDirectoryPanel
 
                     @Override
                     public void onClick(final AjaxRequestTarget target, final MailTemplateTO ignore) {
-                        MailTemplateContentModal.MailTemplateContentTO content =
-                                new MailTemplateContentModal.MailTemplateContentTO(
+                        MailTemplateContentModal.MailTemplateContent content =
+                                new MailTemplateContentModal.MailTemplateContent(
                                         model.getObject().getKey(), MailTemplateFormat.HTML);
                         content.setContent(
                                 restClient.readTemplateFormat(model.getObject().getKey(), MailTemplateFormat.HTML));
@@ -133,8 +132,8 @@ public class MailTemplateDirectoryPanel
 
                     @Override
                     public void onClick(final AjaxRequestTarget target, final MailTemplateTO ignore) {
-                        MailTemplateContentModal.MailTemplateContentTO content =
-                                new MailTemplateContentModal.MailTemplateContentTO(
+                        MailTemplateContentModal.MailTemplateContent content =
+                                new MailTemplateContentModal.MailTemplateContent(
                                         model.getObject().getKey(), MailTemplateFormat.TEXT);
                         content.setContent(
                                 restClient.readTemplateFormat(model.getObject().getKey(), MailTemplateFormat.TEXT));

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
index d504cef..b0425a9 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java
@@ -188,12 +188,6 @@ public class BasePage extends WebPage implements IAjaxIndicatorAware {
         MetaDataRoleAuthorizationStrategy.authorize(link, WebPage.ENABLE, StandardEntitlement.POLICY_LIST);
         liContainer.add(link);
 
-        liContainer = new WebMarkupContainer(getLIContainerId("layouts"));
-        confULContainer.add(liContainer);
-        link = BookmarkablePageLinkBuilder.build("layouts", Layouts.class);
-        MetaDataRoleAuthorizationStrategy.authorize(link, WebPage.ENABLE, StandardEntitlement.CONFIGURATION_LIST);
-        liContainer.add(link);
-
         liContainer = new WebMarkupContainer(getLIContainerId("notifications"));
         confULContainer.add(liContainer);
         link = BookmarkablePageLinkBuilder.build("notifications", Notifications.class);

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/pages/Layouts.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/Layouts.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/Layouts.java
deleted file mode 100644
index 24464da..0000000
--- a/client/console/src/main/java/org/apache/syncope/client/console/pages/Layouts.java
+++ /dev/null
@@ -1,33 +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.wicket.request.mapper.parameter.PageParameters;
-
-public class Layouts extends BasePage {
-
-    private static final long serialVersionUID = -1100228004207271271L;
-
-    public Layouts(final PageParameters parameters) {
-        super(parameters);
-
-        body.add(BookmarkablePageLinkBuilder.build("dashboard", "dashboardBr", Dashboard.class));
-    }
-}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyPanel.java
index f6aeaa5..9a3d8c6 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AnyPanel.java
@@ -18,7 +18,16 @@
  */
 package org.apache.syncope.client.console.panels;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Map;
+import org.apache.commons.lang3.tuple.Triple;
+import org.apache.syncope.client.console.layout.AnyObjectFormLayoutInfo;
+import org.apache.syncope.client.console.layout.FormLayoutInfoUtils;
+import org.apache.syncope.client.console.layout.GroupFormLayoutInfo;
+import org.apache.syncope.client.console.layout.UserFormLayoutInfo;
 import org.apache.syncope.client.console.panels.search.AbstractSearchPanel;
+import org.apache.syncope.client.console.panels.search.AnyObjectSearchPanel;
 import org.apache.syncope.client.console.panels.search.GroupSearchPanel;
 import org.apache.syncope.client.console.panels.search.SearchClause;
 import org.apache.syncope.client.console.panels.search.SearchClausePanel;
@@ -26,9 +35,6 @@ import org.apache.syncope.client.console.panels.search.SearchUtils;
 import org.apache.syncope.client.console.panels.search.UserSearchPanel;
 import org.apache.syncope.client.console.rest.AnyTypeClassRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.tabs.Accordion;
-import org.apache.syncope.client.console.wizards.any.AnyObjectWizardBuilder;
-import org.apache.syncope.client.console.wizards.any.GroupWizardBuilder;
-import org.apache.syncope.client.console.wizards.any.UserWizardBuilder;
 import org.apache.syncope.client.lib.SyncopeClient;
 import org.apache.syncope.common.lib.to.AnyObjectTO;
 import org.apache.syncope.common.lib.to.AnyTypeTO;
@@ -54,9 +60,6 @@ import org.apache.wicket.model.StringResourceModel;
 import org.apache.wicket.model.util.ListModel;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import java.util.ArrayList;
-import java.util.Collections;
-import org.apache.syncope.client.console.panels.search.AnyObjectSearchPanel;
 
 public class AnyPanel extends Panel {
 
@@ -70,6 +73,8 @@ public class AnyPanel extends Panel {
 
     private final AnyTypeClassRestClient anyTypeClassRestClient = new AnyTypeClassRestClient();
 
+    private final Triple<UserFormLayoutInfo, GroupFormLayoutInfo, Map<String, AnyObjectFormLayoutInfo>> formLayoutInfo;
+
     private final PageReference pageRef;
 
     private AbstractSearchPanel searchPanel;
@@ -78,10 +83,16 @@ public class AnyPanel extends Panel {
 
     @SuppressWarnings({ "unchecked", "unchecked" })
     public AnyPanel(
-            final String id, final AnyTypeTO anyTypeTO, final RealmTO realmTO, final PageReference pageRef) {
+            final String id,
+            final AnyTypeTO anyTypeTO,
+            final RealmTO realmTO,
+            final Triple<UserFormLayoutInfo, GroupFormLayoutInfo, Map<String, AnyObjectFormLayoutInfo>> formLayoutInfo,
+            final PageReference pageRef) {
+
         super(id);
         this.anyTypeTO = anyTypeTO;
         this.realmTO = realmTO;
+        this.formLayoutInfo = formLayoutInfo;
         this.pageRef = pageRef;
 
         // ------------------------
@@ -191,31 +202,39 @@ public class AnyPanel extends Panel {
         final String fiql;
         switch (anyTypeTO.getKind()) {
             case USER:
-                fiql = SyncopeClient.getUserSearchConditionBuilder().is("key").greaterThan(0).query();
+                fiql = SyncopeClient.getUserSearchConditionBuilder().is("key").notNullValue().query();
                 final UserTO userTO = new UserTO();
                 userTO.setRealm(realmTO.getFullPath());
                 panel = new UserDirectoryPanel.Builder(
                         anyTypeClassRestClient.list(anyTypeTO.getClasses()),
                         anyTypeTO.getKey(),
                         pageRef).setRealm(realmTO.getFullPath()).setFiltered(true).
-                        setFiql(fiql).addNewItemPanelBuilder(new UserWizardBuilder(
-                        userTO, anyTypeTO.getClasses(), pageRef)).build(id);
+                        setFiql(fiql).addNewItemPanelBuilder(FormLayoutInfoUtils.instantiate(
+                        userTO,
+                        anyTypeTO.getClasses(),
+                        formLayoutInfo.getLeft(),
+                        pageRef)).build(id);
                 MetaDataRoleAuthorizationStrategy.authorize(panel, WebPage.RENDER, StandardEntitlement.USER_LIST);
                 break;
+
             case GROUP:
-                fiql = SyncopeClient.getGroupSearchConditionBuilder().is("key").greaterThan(0).query();
+                fiql = SyncopeClient.getGroupSearchConditionBuilder().is("key").notNullValue().query();
                 final GroupTO groupTO = new GroupTO();
                 groupTO.setRealm(realmTO.getFullPath());
                 panel = new GroupDirectoryPanel.Builder(
                         anyTypeClassRestClient.list(anyTypeTO.getClasses()),
                         anyTypeTO.getKey(),
                         pageRef).setRealm(realmTO.getFullPath()).setFiltered(true).
-                        setFiql(fiql).addNewItemPanelBuilder(new GroupWizardBuilder(
-                        groupTO, anyTypeTO.getClasses(), pageRef)).build(id);
+                        setFiql(fiql).addNewItemPanelBuilder(FormLayoutInfoUtils.instantiate(
+                        groupTO,
+                        anyTypeTO.getClasses(),
+                        formLayoutInfo.getMiddle(),
+                        pageRef)).build(id);
                 // list of group is available to all authenticated users
                 break;
+
             case ANY_OBJECT:
-                fiql = SyncopeClient.getAnyObjectSearchConditionBuilder(anyTypeTO.getKey()).is("key").greaterThan(0).
+                fiql = SyncopeClient.getAnyObjectSearchConditionBuilder(anyTypeTO.getKey()).is("key").notNullValue().
                         query();
                 final AnyObjectTO anyObjectTO = new AnyObjectTO();
                 anyObjectTO.setRealm(realmTO.getFullPath());
@@ -224,11 +243,15 @@ public class AnyPanel extends Panel {
                         anyTypeClassRestClient.list(anyTypeTO.getClasses()),
                         anyTypeTO.getKey(),
                         pageRef).setRealm(realmTO.getFullPath()).setFiltered(true).
-                        setFiql(fiql).addNewItemPanelBuilder(new AnyObjectWizardBuilder(
-                        anyObjectTO, anyTypeTO.getClasses(), pageRef)).build(id);
+                        setFiql(fiql).addNewItemPanelBuilder(FormLayoutInfoUtils.instantiate(
+                        anyObjectTO,
+                        anyTypeTO.getClasses(),
+                        formLayoutInfo.getRight().get(anyTypeTO.getKey()),
+                        pageRef)).build(id);
                 MetaDataRoleAuthorizationStrategy.authorize(
                         panel, WebPage.RENDER, AnyEntitlement.LIST.getFor(anyTypeTO.getKey()));
                 break;
+
             default:
                 panel = new LabelPanel(id, null);
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
index 41d38ed..9ffb476 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/Realm.java
@@ -23,7 +23,13 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Map;
 import org.apache.commons.collections4.ComparatorUtils;
+import org.apache.commons.lang3.tuple.Triple;
+import org.apache.syncope.client.console.layout.AnyObjectFormLayoutInfo;
+import org.apache.syncope.client.console.layout.FormLayoutInfoUtils;
+import org.apache.syncope.client.console.layout.GroupFormLayoutInfo;
+import org.apache.syncope.client.console.layout.UserFormLayoutInfo;
 import org.apache.syncope.client.console.rest.AnyTypeRestClient;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
@@ -52,7 +58,6 @@ public abstract class Realm extends Panel {
 
     private final AnyTypeRestClient anyTypeRestClient = new AnyTypeRestClient();
 
-    @SuppressWarnings({ "unchecked", "unchecked" })
     public Realm(final String id, final RealmTO realmTO, final PageReference pageRef) {
         super(id);
         this.realmTO = realmTO;
@@ -112,6 +117,9 @@ public abstract class Realm extends Panel {
             }
         });
 
+        final Triple<UserFormLayoutInfo, GroupFormLayoutInfo, Map<String, AnyObjectFormLayoutInfo>> formLayoutInfo =
+                FormLayoutInfoUtils.fetch(anyTypeTOs);
+
         Collections.sort(anyTypeTOs, new AnyTypeComparator());
         for (final AnyTypeTO anyTypeTO : anyTypeTOs) {
             tabs.add(new AbstractTab(new Model<>(anyTypeTO.getKey())) {
@@ -120,7 +128,7 @@ public abstract class Realm extends Panel {
 
                 @Override
                 public Panel getPanel(final String panelId) {
-                    return new AnyPanel(panelId, anyTypeTO, realmTO, pageRef);
+                    return new AnyPanel(panelId, anyTypeTO, realmTO, formLayoutInfo, pageRef);
                 }
             });
         }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDirectoryPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDirectoryPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDirectoryPanel.java
index 755ed04..ba2d44b 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDirectoryPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RoleDirectoryPanel.java
@@ -18,7 +18,9 @@
  */
 package org.apache.syncope.client.console.panels;
 
+import org.apache.syncope.client.console.layout.ConsoleLayoutInfoModal;
 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.List;
@@ -29,6 +31,7 @@ import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.commons.RoleDataProvider;
 import org.apache.syncope.client.console.rest.RoleRestClient;
 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.ActionColumn;
+import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink.ActionType;
 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
@@ -51,6 +54,8 @@ public class RoleDirectoryPanel extends DirectoryPanel<RoleTO, RoleHandler, Role
 
     private static final long serialVersionUID = -1100228004207271270L;
 
+    protected final BaseModal<Serializable> utilityModal = new BaseModal<>("outer");
+
     protected RoleDirectoryPanel(final String id, final Builder builder) {
         super(id, builder);
         setShowResultPage(true);
@@ -58,6 +63,11 @@ public class RoleDirectoryPanel extends DirectoryPanel<RoleTO, RoleHandler, Role
         modal.size(Modal.Size.Large);
         initResultTable();
 
+        addOuterObject(utilityModal);
+        setWindowClosedReloadCallback(utilityModal);
+        utilityModal.size(Modal.Size.Large);
+        utilityModal.addSumbitButton();
+
         MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, ENABLE, StandardEntitlement.ROLE_CREATE);
     }
 
@@ -118,6 +128,21 @@ public class RoleDirectoryPanel extends DirectoryPanel<RoleTO, RoleHandler, Role
 
                     @Override
                     public void onClick(final AjaxRequestTarget target, final RoleTO ignore) {
+                        ConsoleLayoutInfoModal.ConsoleLayoutInfo info =
+                                new ConsoleLayoutInfoModal.ConsoleLayoutInfo(model.getObject().getKey());
+                        info.setContent(restClient.readConsoleLayoutInfo(model.getObject().getKey()));
+
+                        utilityModal.header(new ResourceModel("console.layout.info", "JSON Content"));
+                        utilityModal.setContent(new ConsoleLayoutInfoModal(utilityModal, info, pageRef));
+                        utilityModal.show(true);
+                        target.add(utilityModal);
+                    }
+                }, ActionLink.ActionType.LAYOUT_EDIT, StandardEntitlement.ROLE_UPDATE).add(new ActionLink<RoleTO>() {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target, final RoleTO ignore) {
                         try {
                             restClient.delete(model.getObject().getKey());
                             info(getString(Constants.OPERATION_SUCCEEDED));

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.java
index 5c4138d..fa73ec7 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/XMLWorkflowEditorModalPanel.java
@@ -89,6 +89,9 @@ public class XMLWorkflowEditorModalPanel extends AbstractModalPanel<String> {
         response.render(OnLoadHeaderItem.forScript(
                 "CodeMirror.fromTextArea(document.getElementById('workflowDefArea'), {"
                 + "  lineNumbers: true, "
+                + "  lineWrapping: true, "
+                + "  autoCloseTags: true, "
+                + "  mode: 'text/html', "
                 + "  autoRefresh: true"
                 + "}).on('change', updateTextArea);"));
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/rest/ConfigurationRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/ConfigurationRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/ConfigurationRestClient.java
index dfdd842..f8e4863 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/ConfigurationRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/ConfigurationRestClient.java
@@ -20,7 +20,6 @@ package org.apache.syncope.client.console.rest;
 
 import java.util.List;
 import javax.ws.rs.core.Response;
-import org.apache.syncope.client.console.commons.AttrLayoutType;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.to.AttrTO;
 import org.apache.syncope.common.rest.api.service.ConfigurationService;
@@ -32,17 +31,7 @@ public class ConfigurationRestClient extends BaseRestClient {
     private final SchemaRestClient schemaRestClient = new SchemaRestClient();
 
     public List<AttrTO> list() {
-        final List<AttrTO> attrTOs = getService(ConfigurationService.class).list();
-
-        for (AttrTO attrTO : attrTOs) {
-            for (AttrLayoutType type : AttrLayoutType.values()) {
-                if (type.getConfKey().equals(attrTO.getSchema())) {
-                    attrTOs.remove(attrTO);
-                }
-            }
-        }
-
-        return attrTOs;
+        return getService(ConfigurationService.class).list();
     }
 
     public AttrTO get(final String key) {
@@ -54,23 +43,6 @@ public class ConfigurationRestClient extends BaseRestClient {
         return null;
     }
 
-    public AttrTO readAttrLayout(final AttrLayoutType type) {
-        if (type == null) {
-            return null;
-        }
-
-        AttrTO attrLayout = get(type.getConfKey());
-        if (attrLayout == null) {
-            attrLayout = new AttrTO();
-            attrLayout.setSchema(type.getConfKey());
-        }
-        if (attrLayout.getValues().isEmpty()) {
-            attrLayout.getValues().addAll(schemaRestClient.getPlainSchemaNames());
-        }
-
-        return attrLayout;
-    }
-
     public void set(final AttrTO attrTO) {
         getService(ConfigurationService.class).set(attrTO);
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/rest/NotificationRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/NotificationRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/NotificationRestClient.java
index ebf581e..eb7d160 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/NotificationRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/NotificationRestClient.java
@@ -75,13 +75,13 @@ public class NotificationRestClient extends BaseRestClient {
                     getService(MailTemplateService.class).getFormat(key, format).getEntity()),
                     SyncopeConstants.DEFAULT_CHARSET);
         } catch (Exception e) {
-            LOG.info("Error retrieving mail tenplate content");
+            LOG.error("Error retrieving mail template {} as {}", key, format, e);
             return StringUtils.EMPTY;
         }
     }
 
-    public void updateTemplateFormat(final String key, final String str, final MailTemplateFormat format) {
+    public void updateTemplateFormat(final String key, final String content, final MailTemplateFormat format) {
         getService(MailTemplateService.class).setFormat(
-                key, format, IOUtils.toInputStream(str, SyncopeConstants.DEFAULT_CHARSET));
+                key, format, IOUtils.toInputStream(content, SyncopeConstants.DEFAULT_CHARSET));
     }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java
index 116c959..c5a93fb 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/RoleRestClient.java
@@ -18,9 +18,13 @@
  */
 package org.apache.syncope.client.console.rest;
 
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.syncope.common.lib.SyncopeConstants;
 import org.apache.syncope.common.lib.to.RoleTO;
 import org.apache.syncope.common.rest.api.service.RoleService;
 
@@ -29,7 +33,7 @@ import org.apache.syncope.common.rest.api.service.RoleService;
  */
 public class RoleRestClient extends BaseRestClient {
 
-    private static final long serialVersionUID = 1L;
+    private static final long serialVersionUID = -3161863874876938094L;
 
     public void delete(final String key) {
         getService(RoleService.class).delete(key);
@@ -47,10 +51,6 @@ public class RoleRestClient extends BaseRestClient {
         getService(RoleService.class).create(roleTO);
     }
 
-    public List<RoleTO> getAll() {
-        return getService(RoleService.class).list();
-    }
-
     public List<RoleTO> list() {
         return getService(RoleService.class).list();
     }
@@ -59,6 +59,26 @@ public class RoleRestClient extends BaseRestClient {
         return getService(RoleService.class).list().size();
     }
 
+    public String readConsoleLayoutInfo(final String roleKey) {
+        try {
+            return IOUtils.toString(InputStream.class.cast(
+                    getService(RoleService.class).getConsoleLayoutInfo(roleKey).getEntity()),
+                    SyncopeConstants.DEFAULT_CHARSET);
+        } catch (Exception e) {
+            LOG.error("Error retrieving console layout info for role {}", roleKey, e);
+            return StringUtils.EMPTY;
+        }
+    }
+
+    public void setConsoleLayoutInfo(final String roleKey, final String content) {
+        getService(RoleService.class).setConsoleLayoutInfo(
+                roleKey, IOUtils.toInputStream(content, SyncopeConstants.DEFAULT_CHARSET));
+    }
+
+    public void removeConsoleLayoutInfo(final String roleKey) {
+        getService(RoleService.class).removeConsoleLayoutInfo(roleKey);
+    }
+
     public List<String> getAllAvailableEntitlements() {
         List<String> entitlements = new ArrayList<>(getSyncopeService().platform().getEntitlements());
         Collections.sort(entitlements);

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java b/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java
index d6d5081..b7b1b45 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/rest/SchemaRestClient.java
@@ -19,9 +19,7 @@
 package org.apache.syncope.client.console.rest;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
-import java.util.ListIterator;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.syncope.common.lib.SyncopeClientException;
 import org.apache.syncope.common.lib.EntityTOUtils;
@@ -40,21 +38,6 @@ public class SchemaRestClient extends BaseRestClient {
 
     private static final long serialVersionUID = -2479730152700312373L;
 
-    public void filter(
-            final List<? extends AbstractSchemaTO> schemaTOs, final Collection<String> allowed, final boolean exclude) {
-
-        for (ListIterator<? extends AbstractSchemaTO> itor = schemaTOs.listIterator(); itor.hasNext();) {
-            AbstractSchemaTO schema = itor.next();
-            if (exclude) {
-                if (!allowed.contains(schema.getKey())) {
-                    itor.remove();
-                }
-            } else if (allowed.contains(schema.getKey())) {
-                itor.remove();
-            }
-        }
-    }
-
     public <T extends AbstractSchemaTO> List<T> getSchemas(final SchemaType schemaType, final String... kind) {
         List<T> schemas = new ArrayList<>();
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
index dc4d596..3d2007d 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLink.java
@@ -48,6 +48,7 @@ public abstract class ActionLink<T extends Serializable> implements Serializable
         EDIT("read"),
         HTML_EDIT("read"),
         TEXT_EDIT("read"),
+        LAYOUT_EDIT("read"),
         RESET("update"),
         ENABLE("update"),
         NOT_FOND("read"),

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java
index 075fc6d..3d6e4ee 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionLinksPanel.java
@@ -63,6 +63,7 @@ public final class ActionLinksPanel<T extends Serializable> extends Panel {
         super.add(new Fragment("panelEdit", "emptyFragment", this));
         super.add(new Fragment("panelHtmlEdit", "emptyFragment", this));
         super.add(new Fragment("panelTextEdit", "emptyFragment", this));
+        super.add(new Fragment("panelLayoutEdit", "emptyFragment", this));
         super.add(new Fragment("panelReset", "emptyFragment", this));
         super.add(new Fragment("panelEnable", "emptyFragment", this));
         super.add(new Fragment("panelNotFound", "emptyFragment", this));
@@ -347,6 +348,25 @@ public final class ActionLinksPanel<T extends Serializable> extends Panel {
                 }.setVisible(link.isEnabled(model.getObject())));
                 break;
 
+            case LAYOUT_EDIT:
+                fragment = new Fragment("panelLayoutEdit", "fragmentLayoutEdit", this);
+
+                fragment.addOrReplace(new IndicatingAjaxLink<Void>("layoutEditLink") {
+
+                    private static final long serialVersionUID = -1876519166660008562L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+                        link.onClick(target, model.getObject());
+                    }
+
+                    @Override
+                    public String getAjaxIndicatorMarkupId() {
+                        return disableIndicator ? StringUtils.EMPTY : super.getAjaxIndicatorMarkupId();
+                    }
+                }.setVisible(link.isEnabled(model.getObject())));
+                break;
+
             case ENABLE:
                 fragment = new Fragment("panelEnable", "fragmentEnable", this);
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/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 3e704c3..7a50226 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,7 +22,6 @@ import java.io.Serializable;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
-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;
@@ -142,9 +141,7 @@ public class ApprovalsWidget extends Panel {
                     @Override
                     protected void onComponentTag(final ComponentTag tag) {
                         super.onComponentTag(tag);
-                        if (StringUtils.isNotBlank(modelObject.getDescription())) {
-                            tag.put("title", modelObject.getDescription().trim());
-                        }
+                        tag.put("title", modelObject.getUsername());
                     }
                 };
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/AbstractModalPanelBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/AbstractModalPanelBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AbstractModalPanelBuilder.java
index 7209f26..7356e1e 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/AbstractModalPanelBuilder.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/AbstractModalPanelBuilder.java
@@ -20,10 +20,9 @@ package org.apache.syncope.client.console.wizards;
 
 import java.io.Serializable;
 import org.apache.commons.lang3.SerializationUtils;
-import org.apache.syncope.client.console.panels.ModalPanel;
 import org.apache.wicket.PageReference;
 
-public abstract class AbstractModalPanelBuilder<T extends Serializable> implements Serializable {
+public abstract class AbstractModalPanelBuilder<T extends Serializable> implements ModalPanelBuilder<T> {
 
     private static final long serialVersionUID = 5241745929825564456L;
 
@@ -44,16 +43,6 @@ public abstract class AbstractModalPanelBuilder<T extends Serializable> implemen
         this.pageRef = pageRef;
     }
 
-    /**
-     * Build the wizard.
-     *
-     * @param id component id.
-     * @param index step index.
-     * @param mode mode.
-     * @return wizard.
-     */
-    public abstract ModalPanel<T> build(final String id, final int index, final AjaxWizard.Mode mode);
-
     protected void onCancelInternal(final T modelObject) {
     }
 
@@ -66,6 +55,7 @@ public abstract class AbstractModalPanelBuilder<T extends Serializable> implemen
         return item;
     }
 
+    @Override
     public T getDefaultItem() {
         return defaultItem;
     }
@@ -80,17 +70,13 @@ public abstract class AbstractModalPanelBuilder<T extends Serializable> implemen
         return SerializationUtils.clone(item);
     }
 
-    /**
-     * Replaces the default value provided with the constructor and nullify working item object.
-     *
-     * @param item new value.
-     * @return the current wizard factory instance.
-     */
+    @Override
     public AbstractModalPanelBuilder<T> setItem(final T item) {
         this.item = item;
         return this;
     }
 
+    @Override
     public PageReference getPageReference() {
         return pageRef;
     }

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/ModalPanelBuilder.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/ModalPanelBuilder.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/ModalPanelBuilder.java
new file mode 100644
index 0000000..62db09a
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/ModalPanelBuilder.java
@@ -0,0 +1,49 @@
+/*
+ * 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.wizards;
+
+import java.io.Serializable;
+import org.apache.syncope.client.console.panels.ModalPanel;
+import org.apache.wicket.PageReference;
+
+public interface ModalPanelBuilder<T extends Serializable> extends Serializable {
+
+    /**
+     * Build the wizard.
+     *
+     * @param id component id.
+     * @param index step index.
+     * @param mode mode.
+     * @return wizard.
+     */
+    ModalPanel<T> build(String id, int index, AjaxWizard.Mode mode);
+
+    T getDefaultItem();
+
+    PageReference getPageReference();
+
+    /**
+     * Replaces the default value provided with the constructor and nullify working item object.
+     *
+     * @param item new value.
+     * @return the current wizard factory instance.
+     */
+    ModalPanelBuilder<T> setItem(T item);
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/5b47ab23/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
index 2a61de7..144e2f4 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wizards/WizardMgtPanel.java
@@ -67,7 +67,7 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
 
     protected final AjaxLink<?> addAjaxLink;
 
-    protected AbstractModalPanelBuilder<T> newItemPanelBuilder;
+    protected ModalPanelBuilder<T> newItemPanelBuilder;
 
     protected NotificationPanel notificationPanel;
 
@@ -252,18 +252,19 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
         return this;
     }
 
-    public <B extends AbstractModalPanelBuilder<T>> WizardMgtPanel<T> setPageRef(final PageReference pageRef) {
+    public <B extends ModalPanelBuilder<T>> WizardMgtPanel<T> setPageRef(final PageReference pageRef) {
         this.pageRef = pageRef;
         return this;
     }
 
-    public <B extends AbstractModalPanelBuilder<T>> WizardMgtPanel<T> setShowResultPage(final boolean showResultPage) {
+    public <B extends ModalPanelBuilder<T>> WizardMgtPanel<T> setShowResultPage(final boolean showResultPage) {
         this.showResultPage = showResultPage;
         return this;
     }
 
-    protected <B extends AbstractModalPanelBuilder<T>> WizardMgtPanel<T> addNewItemPanelBuilder(
+    protected <B extends ModalPanelBuilder<T>> WizardMgtPanel<T> addNewItemPanelBuilder(
             final B panelBuilder, final boolean newItemDefaultButtonEnabled) {
+
         this.newItemPanelBuilder = panelBuilder;
 
         if (this.newItemPanelBuilder != null) {
@@ -321,7 +322,7 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
 
         protected final PageReference pageRef;
 
-        private AbstractModalPanelBuilder<T> newItemPanelBuilder;
+        private ModalPanelBuilder<T> newItemPanelBuilder;
 
         private boolean newItemDefaultButtonEnabled = true;
 
@@ -353,7 +354,7 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
             this.showResultPage = showResultPage;
         }
 
-        public Builder<T> addNewItemPanelBuilder(final AbstractModalPanelBuilder<T> panelBuilder) {
+        public Builder<T> addNewItemPanelBuilder(final ModalPanelBuilder<T> panelBuilder) {
             this.newItemPanelBuilder = panelBuilder;
             return this;
         }
@@ -366,7 +367,8 @@ public abstract class WizardMgtPanel<T extends Serializable> extends Panel imple
          * @return the current builder.
          */
         public Builder<T> addNewItemPanelBuilder(
-                final AbstractModalPanelBuilder<T> panelBuilder, final boolean newItemDefaultButtonEnabled) {
+                final ModalPanelBuilder<T> panelBuilder, final boolean newItemDefaultButtonEnabled) {
+
             this.newItemDefaultButtonEnabled = newItemDefaultButtonEnabled;
             return addNewItemPanelBuilder(panelBuilder);
         }