http://git-wip-us.apache.org/repos/asf/syncope/blob/39f8a069/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupPanel.java
----------------------------------------------------------------------
diff --git 
a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupPanel.java
 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupPanel.java
new file mode 100644
index 0000000..7cbf47e
--- /dev/null
+++ 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupPanel.java
@@ -0,0 +1,187 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.apache.syncope.client.console.commons.Mode;
+import org.apache.syncope.client.console.commons.XMLRolesReader;
+import org.apache.syncope.client.console.commons.status.StatusBean;
+import org.apache.syncope.client.console.rest.AuthRestClient;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.wicket.PageReference;
+import 
org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.util.ListModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+
+public class GroupPanel extends Panel {
+
+    private static final long serialVersionUID = 4216376097320768369L;
+
+    @SpringBean
+    private AuthRestClient authRestClient;
+
+    @SpringBean
+    private XMLRolesReader xmlRolesReader;
+
+    private final AjaxPalettePanel<String> entitlements;
+
+    public static class Builder implements Serializable {
+
+        private static final long serialVersionUID = 8150440254654306070L;
+
+        private String id;
+
+        private Form form;
+
+        private GroupTO groupTO;
+
+        private Mode mode;
+
+        private PageReference pageReference;
+
+        public Builder(final String id) {
+            this.id = id;
+        }
+
+        public Builder form(final Form form) {
+            this.form = form;
+            return this;
+        }
+
+        public Builder groupTO(final GroupTO groupTO) {
+            this.groupTO = groupTO;
+            return this;
+        }
+
+        public Builder groupModalPageMode(final Mode mode) {
+            this.mode = mode;
+            return this;
+        }
+
+        public Builder pageRef(final PageReference pageReference) {
+            this.pageReference = pageReference;
+            return this;
+        }
+
+        public GroupPanel build() {
+            return new GroupPanel(this);
+        }
+    }
+
+    private GroupPanel(final Builder builder) {
+        super(builder.id);
+
+        this.add(new GroupDetailsPanel("details", builder.groupTO, 
builder.mode == Mode.TEMPLATE));
+
+        if (builder.pageReference == null || builder.groupTO.getKey() == 0) {
+            this.add(new Label("statuspanel", ""));
+        } else {
+            StatusPanel statusPanel = new StatusPanel(
+                    "statuspanel", builder.groupTO, new 
ArrayList<StatusBean>(), builder.pageReference);
+            statusPanel.setOutputMarkupId(true);
+            MetaDataRoleAuthorizationStrategy.authorize(
+                    statusPanel, RENDER, 
xmlRolesReader.getEntitlement("Resources", "getConnectorObject"));
+            this.add(statusPanel);
+        }
+
+        this.add(new AnnotatedBeanPanel("systeminformation", builder.groupTO));
+
+        //--------------------------------
+        // Attribute templates panel
+        //--------------------------------
+        AttrTemplatesPanel attrTemplates = new AttrTemplatesPanel("templates", 
builder.groupTO);
+        this.add(attrTemplates);
+
+        //--------------------------------
+        // Attributes panel
+        //--------------------------------
+        this.add(new PlainAttrsPanel(
+                "plainAttrs", builder.groupTO, builder.form, builder.mode, 
attrTemplates));
+
+        final AjaxCheckBoxPanel inhAttributes = new 
AjaxCheckBoxPanel("inheritPlainAttrs", "inheritPlainAttrs",
+                new PropertyModel<Boolean>(builder.groupTO, 
"inheritPlainAttrs"));
+        inhAttributes.setOutputMarkupId(true);
+        this.add(inhAttributes);
+        //--------------------------------
+
+        //--------------------------------
+        // Derived attributes panel
+        //--------------------------------
+        this.add(new DerAttrsPanel("derAttrs", builder.groupTO, 
attrTemplates));
+
+        final AjaxCheckBoxPanel inhDerivedAttributes = new 
AjaxCheckBoxPanel("inheritDerAttrs",
+                "inheritDerAttrs", new PropertyModel<Boolean>(builder.groupTO, 
"inheritDerAttrs"));
+        inhDerivedAttributes.setOutputMarkupId(true);
+        this.add(inhDerivedAttributes);
+        //--------------------------------
+
+        //--------------------------------
+        // Virtual attributes panel
+        //--------------------------------
+        this.add(new VirAttrsPanel(
+                "virAttrs", builder.groupTO, builder.mode == Mode.TEMPLATE, 
attrTemplates));
+
+        final AjaxCheckBoxPanel inhVirtualAttributes = new 
AjaxCheckBoxPanel("inheritVirAttrs",
+                "inheritVirAttrs", new PropertyModel<Boolean>(builder.groupTO, 
"inheritVirAttrs"));
+        inhVirtualAttributes.setOutputMarkupId(true);
+        this.add(inhVirtualAttributes);
+        //--------------------------------
+
+        //--------------------------------
+        // Resources panel
+        //--------------------------------
+        this.add(new 
ResourcesPanel.Builder("resources").attributableTO(builder.groupTO).build().
+                setOutputMarkupId(true));
+        //--------------------------------
+
+        //--------------------------------
+        // Entitlements
+        //--------------------------------
+        ListModel<String> selectedEntitlements = new 
ListModel<String>(builder.groupTO.getEntitlements());
+
+        List<String> allEntitlements = authRestClient.getAllEntitlements();
+        if (allEntitlements != null && !allEntitlements.isEmpty()) {
+            Collections.sort(allEntitlements);
+        }
+        ListModel<String> availableEntitlements = new 
ListModel<String>(allEntitlements);
+
+        entitlements = new AjaxPalettePanel<String>("entitlements", 
selectedEntitlements, availableEntitlements);
+        this.add(entitlements);
+
+        //--------------------------------
+        // Security panel
+        //--------------------------------
+        this.add(new GroupSecurityPanel("security", 
builder.groupTO).setOutputMarkupId(true));
+        //--------------------------------
+    }
+
+    public Collection<String> getSelectedEntitlements() {
+        return this.entitlements.getModelCollection();
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/39f8a069/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchPanel.java
----------------------------------------------------------------------
diff --git 
a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchPanel.java
 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchPanel.java
new file mode 100644
index 0000000..d13ab94
--- /dev/null
+++ 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchPanel.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.common.lib.search.AbstractFiqlSearchConditionBuilder;
+import org.apache.syncope.common.lib.types.AttributableType;
+import org.apache.wicket.model.LoadableDetachableModel;
+
+public class GroupSearchPanel extends AbstractSearchPanel {
+
+    private static final long serialVersionUID = 5757183539269316263L;
+
+    public static class Builder implements Serializable {
+
+        private static final long serialVersionUID = 6308997285778809579L;
+
+        private String id;
+
+        private String fiql = null;
+
+        private boolean required = true;
+
+        public Builder(final String id) {
+            this.id = id;
+        }
+
+        public Builder fiql(final String fiql) {
+            this.fiql = fiql;
+            return this;
+        }
+
+        public Builder required(final boolean required) {
+            this.required = required;
+            return this;
+        }
+
+        public GroupSearchPanel build() {
+            return new GroupSearchPanel(this);
+        }
+    }
+
+    private GroupSearchPanel(final Builder builder) {
+        super(builder.id, AttributableType.GROUP, builder.fiql, 
builder.required);
+    }
+
+    @Override
+    protected void populate() {
+        super.populate();
+
+        this.types = new LoadableDetachableModel<List<SearchClause.Type>>() {
+
+            private static final long serialVersionUID = 5275935387613157437L;
+
+            @Override
+            protected List<SearchClause.Type> load() {
+                final List<SearchClause.Type> result = new 
ArrayList<SearchClause.Type>();
+                result.add(SearchClause.Type.ATTRIBUTE);
+                result.add(SearchClause.Type.ENTITLEMENT);
+                result.add(SearchClause.Type.RESOURCE);
+                return result;
+            }
+        };
+
+        this.groupNames = new LoadableDetachableModel<List<String>>() {
+
+            private static final long serialVersionUID = 5275935387613157437L;
+
+            @Override
+            protected List<String> load() {
+                return Collections.<String>emptyList();
+            }
+        };
+    }
+
+    @Override
+    protected AbstractFiqlSearchConditionBuilder getSearchConditionBuilder() {
+        return SyncopeClient.getGroupSearchConditionBuilder();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/39f8a069/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java
----------------------------------------------------------------------
diff --git 
a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java
 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java
new file mode 100644
index 0000000..a7dac82
--- /dev/null
+++ 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.pages.ResultStatusModalPage;
+import org.apache.syncope.client.console.pages.GroupModalPage;
+import org.apache.syncope.client.console.pages.StatusModalPage;
+import org.apache.syncope.client.console.rest.AbstractSubjectRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.ActionLink.ActionType;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import 
org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
+import 
org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
+import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
+import 
org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
+import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.ResourceModel;
+
+public class GroupSearchResultPanel extends AbstractSearchResultPanel {
+
+    private static final long serialVersionUID = -1180593361914008764L;
+
+    private final static String PAGEID = "Groups";
+
+    public <T extends AbstractAttributableTO> GroupSearchResultPanel(final 
String id, final boolean filtered,
+            final String fiql, final PageReference callerRef, final 
AbstractSubjectRestClient restClient) {
+
+        super(id, filtered, fiql, callerRef, restClient);
+        initResultTable();
+    }
+
+    @Override
+    protected List<IColumn<AbstractAttributableTO, String>> getColumns() {
+        final List<IColumn<AbstractAttributableTO, String>> columns = new 
ArrayList<>();
+
+        for (String item : new String[] { "key", "name", "entitlements" }) {
+            columns.add(new PropertyColumn<AbstractAttributableTO, String>(new 
ResourceModel(item, item), item, item));
+        }
+
+        columns.add(new AbstractColumn<AbstractAttributableTO, String>(new 
ResourceModel("actions", "")) {
+
+            private static final long serialVersionUID = -3503023501954863131L;
+
+            @Override
+            public String getCssClass() {
+                return "action";
+            }
+
+            @Override
+            public void populateItem(final 
Item<ICellPopulator<AbstractAttributableTO>> cellItem,
+                    final String componentId, final 
IModel<AbstractAttributableTO> model) {
+
+                final ActionLinksPanel panel = new 
ActionLinksPanel(componentId, model, page.getPageReference());
+
+                panel.add(new ActionLink() {
+
+                    private static final long serialVersionUID = 
-3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+                        statusmodal.setPageCreator(new 
ModalWindow.PageCreator() {
+
+                            private static final long serialVersionUID = 
-7834632442532690940L;
+
+                            @Override
+                            public Page createPage() {
+                                return new StatusModalPage<GroupTO>(
+                                        page.getPageReference(), statusmodal, 
(GroupTO) model.getObject());
+                            }
+                        });
+
+                        statusmodal.show(target);
+                    }
+                }, ActionLink.ActionType.MANAGE_RESOURCES, PAGEID);
+
+                panel.add(new ActionLink() {
+
+                    private static final long serialVersionUID = 
-3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+                        editmodal.setPageCreator(new ModalWindow.PageCreator() 
{
+
+                            private static final long serialVersionUID = 
-7834632442532690940L;
+
+                            @Override
+                            public Page createPage() {
+                                return new GroupModalPage(
+                                        page.getPageReference(), editmodal, 
(GroupTO) model.getObject());
+                            }
+                        });
+
+                        editmodal.show(target);
+                    }
+                }, ActionLink.ActionType.EDIT, PAGEID);
+
+                panel.add(new ActionLink() {
+
+                    private static final long serialVersionUID = 
-3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+                        try {
+                            final GroupTO groupTO = (GroupTO) restClient.
+                                    delete(model.getObject().getETagValue(), 
model.getObject().getKey());
+
+                            page.setModalResult(true);
+
+                            editmodal.setPageCreator(new 
ModalWindow.PageCreator() {
+
+                                private static final long serialVersionUID = 
-7834632442532690940L;
+
+                                @Override
+                                public Page createPage() {
+                                    return new 
ResultStatusModalPage.Builder(editmodal, groupTO).build();
+                                }
+                            });
+
+                            editmodal.show(target);
+                        } catch (SyncopeClientException scce) {
+                            error(getString(Constants.OPERATION_ERROR) + ": " 
+ scce.getMessage());
+                            feedbackPanel.refresh(target);
+                        }
+                    }
+                }, ActionLink.ActionType.DELETE, PAGEID);
+
+                cellItem.add(panel);
+            }
+        });
+
+        return columns;
+    }
+
+    @Override
+    protected Collection<ActionType> getBulkActions() {
+        return 
Collections.<ActionLink.ActionType>singletonList(ActionLink.ActionType.DELETE);
+    }
+
+    @Override
+    protected String getPageId() {
+        return PAGEID;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/39f8a069/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupSecurityPanel.java
----------------------------------------------------------------------
diff --git 
a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupSecurityPanel.java
 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupSecurityPanel.java
new file mode 100644
index 0000000..4e0e1f9
--- /dev/null
+++ 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupSecurityPanel.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.rest.PolicyRestClient;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.AjaxCheckBoxPanel;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
+import org.apache.syncope.common.lib.to.AbstractAttributableTO;
+import org.apache.syncope.common.lib.to.AbstractPolicyTO;
+import org.apache.syncope.common.lib.types.PolicyType;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.form.ChoiceRenderer;
+import org.apache.wicket.markup.html.form.DropDownChoice;
+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.apache.wicket.spring.injection.annot.SpringBean;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GroupSecurityPanel extends Panel {
+
+    /**
+     * Logger.
+     */
+    protected static final Logger LOG = 
LoggerFactory.getLogger(GroupSecurityPanel.class);
+
+    private static final long serialVersionUID = -7982691107029848579L;
+
+    @SpringBean
+    private PolicyRestClient policyRestClient;
+
+    private IModel<Map<Long, String>> passwordPolicies = null;
+
+    private IModel<Map<Long, String>> accountPolicies = null;
+
+    public <T extends AbstractAttributableTO> GroupSecurityPanel(final String 
id, final T entityTO) {
+        super(id);
+
+        setOutputMarkupId(true);
+
+        passwordPolicies = new LoadableDetachableModel<Map<Long, String>>() {
+
+            private static final long serialVersionUID = 5275935387613157437L;
+
+            @Override
+            protected Map<Long, String> load() {
+                Map<Long, String> res = new HashMap<>();
+                for (AbstractPolicyTO policyTO : 
policyRestClient.getPolicies(PolicyType.PASSWORD, false)) {
+                    res.put(policyTO.getKey(), policyTO.getDescription());
+                }
+                return res;
+            }
+        };
+
+        accountPolicies = new LoadableDetachableModel<Map<Long, String>>() {
+
+            private static final long serialVersionUID = -2012833443695917883L;
+
+            @Override
+            protected Map<Long, String> load() {
+                Map<Long, String> res = new HashMap<>();
+                for (AbstractPolicyTO policyTO : 
policyRestClient.getPolicies(PolicyType.ACCOUNT, false)) {
+                    res.put(policyTO.getKey(), policyTO.getDescription());
+                }
+                return res;
+            }
+        };
+
+        final WebMarkupContainer securityContainer = new 
WebMarkupContainer("security");
+
+        securityContainer.setOutputMarkupId(true);
+        add(securityContainer);
+
+        // -------------------------------
+        // Password policy specification
+        // -------------------------------
+        final AjaxDropDownChoicePanel<Long> passwordPolicy = new 
AjaxDropDownChoicePanel<Long>("passwordPolicy",
+                "passwordPolicy", new PropertyModel<Long>(entityTO, 
"passwordPolicy"));
+
+        passwordPolicy.setChoiceRenderer(new 
PolicyRenderer(PolicyType.PASSWORD));
+
+        passwordPolicy.setChoices(new 
ArrayList<Long>(passwordPolicies.getObject().keySet()));
+
+        ((DropDownChoice<?>) passwordPolicy.getField()).setNullValid(true);
+
+        securityContainer.add(passwordPolicy);
+
+        final AjaxCheckBoxPanel inhPasswordPolicy = new 
AjaxCheckBoxPanel("inheritPasswordPolicy",
+                "inheritPasswordPolicy", new PropertyModel<Boolean>(entityTO, 
"inheritPasswordPolicy"));
+
+        passwordPolicy.setReadOnly(inhPasswordPolicy.getModelObject());
+
+        inhPasswordPolicy.getField().add(new 
AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                passwordPolicy.setReadOnly(inhPasswordPolicy.getModelObject());
+                target.add(passwordPolicy);
+            }
+        });
+
+        securityContainer.add(inhPasswordPolicy);
+        // -------------------------------
+
+        // -------------------------------
+        // Account policy specification
+        // -------------------------------
+        final AjaxDropDownChoicePanel<Long> accountPolicy = new 
AjaxDropDownChoicePanel<Long>("accountPolicy",
+                "accountPolicy", new PropertyModel<Long>(entityTO, 
"accountPolicy"));
+
+        accountPolicy.setChoiceRenderer(new 
PolicyRenderer(PolicyType.ACCOUNT));
+
+        accountPolicy.setChoices(new 
ArrayList<Long>(accountPolicies.getObject().keySet()));
+
+        ((DropDownChoice<?>) accountPolicy.getField()).setNullValid(true);
+
+        securityContainer.add(accountPolicy);
+
+        final AjaxCheckBoxPanel inhAccountPolicy = new 
AjaxCheckBoxPanel("inheritAccountPolicy",
+                "inheritAccountPolicy", new PropertyModel<Boolean>(entityTO, 
"inheritAccountPolicy"));
+        accountPolicy.setReadOnly(inhAccountPolicy.getModelObject());
+
+        inhAccountPolicy.getField().add(new 
AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                accountPolicy.setReadOnly(inhAccountPolicy.getModelObject());
+                target.add(accountPolicy);
+            }
+        });
+
+        securityContainer.add(inhAccountPolicy);
+        // -------------------------------
+    }
+
+    private class PolicyRenderer extends ChoiceRenderer<Long> {
+
+        private static final long serialVersionUID = 8060500161321947000L;
+
+        private PolicyType type;
+
+        public PolicyRenderer(final PolicyType type) {
+            super();
+            this.type = type;
+        }
+
+        @Override
+        public Object getDisplayValue(final Long object) {
+            Object displayValue;
+            switch (type) {
+                case ACCOUNT:
+                    displayValue = accountPolicies.getObject().get(object);
+                    break;
+                case PASSWORD:
+                    displayValue = passwordPolicies.getObject().get(object);
+                    break;
+                default:
+                    displayValue = "";
+            }
+            return displayValue;
+        }
+
+        @Override
+        public String getIdValue(Long object, int index) {
+            return String.valueOf(object != null
+                    ? object
+                    : 0L);
+        }
+    };
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/39f8a069/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupSummaryPanel.java
----------------------------------------------------------------------
diff --git 
a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupSummaryPanel.java
 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupSummaryPanel.java
new file mode 100644
index 0000000..f9a56e6
--- /dev/null
+++ 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupSummaryPanel.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.io.Serializable;
+import org.apache.syncope.client.console.commons.XMLRolesReader;
+import org.apache.syncope.client.console.pages.GroupModalPage;
+import org.apache.syncope.client.console.rest.GroupRestClient;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GroupSummaryPanel extends Panel {
+
+    private static final long serialVersionUID = 643769814985593156L;
+
+    /**
+     * Logger.
+     */
+    private static final Logger LOG = 
LoggerFactory.getLogger(GroupSummaryPanel.class);
+
+    @SpringBean
+    private XMLRolesReader xmlRolesReader;
+
+    @SpringBean
+    private GroupRestClient restClient;
+
+    private GroupTO selectedNode;
+
+    public static class Builder implements Serializable {
+
+        private static final long serialVersionUID = 4164563358509351832L;
+
+        private String id;
+
+        private ModalWindow window;
+
+        private PageReference callerPageRef;
+
+        private Long selectedNodeId = null;
+
+        public Builder(final String id) {
+            this.id = id;
+        }
+
+        public GroupSummaryPanel.Builder window(final ModalWindow window) {
+            this.window = window;
+            return this;
+        }
+
+        public GroupSummaryPanel.Builder callerPageRef(final PageReference 
callerPageRef) {
+            this.callerPageRef = callerPageRef;
+            return this;
+        }
+
+        public GroupSummaryPanel.Builder selectedNodeId(final Long 
selectedNodeId) {
+            this.selectedNodeId = selectedNodeId;
+            return this;
+        }
+
+        public GroupSummaryPanel build() {
+            return new GroupSummaryPanel(this);
+        }
+    }
+
+    private GroupSummaryPanel(final Builder builder) {
+        super(builder.id);
+
+        if (builder.selectedNodeId == null || builder.selectedNodeId == 0) {
+            selectedNode = null;
+        } else {
+            try {
+                selectedNode = restClient.read(builder.selectedNodeId);
+            } catch (SyncopeClientException e) {
+                LOG.error("Could not read {}", builder.selectedNodeId, e);
+                selectedNode = null;
+                builder.selectedNodeId = null;
+            }
+        }
+
+        Fragment fragment = new Fragment("groupSummaryPanel",
+                builder.selectedNodeId == null
+                        ? "fakerootFrag"
+                        : (builder.selectedNodeId == 0 ? "rootPanel" : 
"groupViewPanel"),
+                this);
+
+        if (builder.selectedNodeId != null) {
+            if (builder.selectedNodeId == 0) {
+                @SuppressWarnings("rawtypes")
+                final ActionLinksPanel links = new 
ActionLinksPanel("actionLinks", new Model(), builder.callerPageRef);
+                links.setOutputMarkupId(true);
+                fragment.add(links);
+
+                links.addWithRoles(new ActionLink() {
+
+                    private static final long serialVersionUID = 
-3722207913631435501L;
+
+                    @Override
+                    public void onClick(final AjaxRequestTarget target) {
+                        builder.window.setPageCreator(new 
ModalWindow.PageCreator() {
+
+                            private static final long serialVersionUID = 
-7834632442532690940L;
+
+                            @Override
+                            public Page createPage() {
+                                return new 
GroupModalPage(builder.callerPageRef, builder.window, new GroupTO());
+                            }
+                        });
+
+                        builder.window.show(target);
+                    }
+                }, ActionLink.ActionType.CREATE, 
xmlRolesReader.getEntitlement("Groups", "create"));
+            } else {
+                GroupTabPanel groupTabPanel =
+                        new GroupTabPanel("nodeViewPanel", selectedNode, 
builder.window, builder.callerPageRef);
+                groupTabPanel.setOutputMarkupId(true);
+                fragment.add(groupTabPanel);
+            }
+        }
+        add(fragment);
+    }
+
+    public GroupTO getSelectedNode() {
+        return selectedNode;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/39f8a069/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupTabPanel.java
----------------------------------------------------------------------
diff --git 
a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupTabPanel.java
 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupTabPanel.java
new file mode 100644
index 0000000..9615554
--- /dev/null
+++ 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/GroupTabPanel.java
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.Mode;
+import org.apache.syncope.client.console.commons.XMLRolesReader;
+import org.apache.syncope.client.console.pages.ResultStatusModalPage;
+import org.apache.syncope.client.console.pages.GroupModalPage;
+import org.apache.syncope.client.console.pages.Groups;
+import org.apache.syncope.client.console.pages.StatusModalPage;
+import org.apache.syncope.client.console.rest.GroupRestClient;
+import org.apache.syncope.client.console.rest.UserRestClient;
+import 
org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxButton;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
+import org.apache.syncope.client.lib.SyncopeClient;
+import org.apache.syncope.common.lib.SyncopeClientException;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+
+public class GroupTabPanel extends Panel {
+
+    private static final long serialVersionUID = 859236186975983959L;
+
+    @SpringBean
+    private XMLRolesReader xmlRolesReader;
+
+    @SpringBean
+    private GroupRestClient groupRestClient;
+
+    @SpringBean
+    private UserRestClient userRestClient;
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    public GroupTabPanel(final String id, final GroupTO selectedNode, final 
ModalWindow window,
+            final PageReference pageRef) {
+
+        super(id);
+
+        this.add(new Label("displayName", selectedNode.getDisplayName()));
+
+        final ActionLinksPanel links = new ActionLinksPanel("actionLinks", new 
Model(), pageRef);
+        links.setOutputMarkupId(true);
+        this.add(links);
+        links.addWithRoles(new ActionLink() {
+
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                window.setPageCreator(new ModalWindow.PageCreator() {
+
+                    private static final long serialVersionUID = 
-7834632442532690940L;
+
+                    @Override
+                    public Page createPage() {
+                        GroupTO groupTO = new GroupTO();
+                        groupTO.setParent(selectedNode.getKey());
+                        return new GroupModalPage(pageRef, window, groupTO);
+                    }
+                });
+
+                window.show(target);
+            }
+        }, ActionLink.ActionType.CREATE, 
xmlRolesReader.getEntitlement("Groups", "create"));
+        links.addWithRoles(new ActionLink() {
+
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                window.setPageCreator(new ModalWindow.PageCreator() {
+
+                    private static final long serialVersionUID = 
-7834632442532690940L;
+
+                    @Override
+                    public Page createPage() {
+                        return new StatusModalPage<GroupTO>(pageRef, window, 
groupRestClient.read(selectedNode.getKey()));
+                    }
+                });
+
+                window.show(target);
+            }
+        }, ActionLink.ActionType.MANAGE_RESOURCES, 
xmlRolesReader.getEntitlement("Groups", "update"));
+        links.addWithRoles(new ActionLink() {
+
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                window.setPageCreator(new ModalWindow.PageCreator() {
+
+                    private static final long serialVersionUID = 
-7834632442532690940L;
+
+                    @Override
+                    public Page createPage() {
+                        GroupTO groupTO = 
groupRestClient.read(selectedNode.getKey());
+                        return new GroupModalPage(pageRef, window, groupTO);
+                    }
+                });
+
+                window.show(target);
+            }
+        }, ActionLink.ActionType.EDIT, xmlRolesReader.getEntitlement("Groups", 
"update"));
+        links.addWithRoles(new ActionLink() {
+
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                try {
+                    final GroupTO groupTO = 
groupRestClient.delete(selectedNode.getETagValue(), selectedNode.getKey());
+
+                    ((Groups) pageRef.getPage()).setModalResult(true);
+
+                    window.setPageCreator(new ModalWindow.PageCreator() {
+
+                        private static final long serialVersionUID = 
-7834632442532690940L;
+
+                        @Override
+                        public Page createPage() {
+                            return new ResultStatusModalPage.Builder(window, 
groupTO).build();
+                        }
+                    });
+
+                    window.show(target);
+                } catch (SyncopeClientException e) {
+                    error(getString(Constants.OPERATION_ERROR) + ": " + 
e.getMessage());
+                    ((Groups) 
pageRef.getPage()).getFeedbackPanel().refresh(target);
+                }
+            }
+        }, ActionLink.ActionType.DELETE, 
xmlRolesReader.getEntitlement("Groups", "delete"));
+
+        final Form form = new Form("groupForm");
+        form.setModel(new CompoundPropertyModel(selectedNode));
+        form.setOutputMarkupId(true);
+
+        final GroupPanel groupPanel = new GroupPanel.Builder("groupPanel").
+                
form(form).groupTO(selectedNode).groupModalPageMode(Mode.ADMIN).build();
+        groupPanel.setEnabled(false);
+        form.add(groupPanel);
+
+        final WebMarkupContainer userListContainer = new 
WebMarkupContainer("userListContainer");
+
+        userListContainer.setOutputMarkupId(true);
+        userListContainer.setEnabled(true);
+        userListContainer.add(new UserSearchResultPanel("userList", true, 
null, pageRef, userRestClient));
+        userListContainer.add(new ClearIndicatingAjaxButton("search", new 
ResourceModel("search"), pageRef) {
+
+            private static final long serialVersionUID = -958724007591692537L;
+
+            @Override
+            protected void onSubmitInternal(final AjaxRequestTarget target, 
final Form<?> form) {
+                userListContainer.replace(new UserSearchResultPanel("userList",
+                        true,
+                        
SyncopeClient.getUserSearchConditionBuilder().inGroups(selectedNode.getKey()).query(),
+                        pageRef,
+                        userRestClient));
+
+                target.add(userListContainer);
+            }
+        });
+
+        form.add(userListContainer);
+        add(form);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/39f8a069/client/old_console/src/main/java/org/apache/syncope/client/console/panels/ImagePanel.java
----------------------------------------------------------------------
diff --git 
a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/ImagePanel.java
 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/ImagePanel.java
new file mode 100644
index 0000000..7969c63
--- /dev/null
+++ 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/ImagePanel.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.behavior.Behavior;
+import org.apache.wicket.markup.html.image.Image;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.request.resource.ContextRelativeResource;
+
+public class ImagePanel extends Panel {
+
+    private static final long serialVersionUID = 5564818820574092960L;
+
+    final Image img;
+
+    public ImagePanel(final String id, final ContextRelativeResource img) {
+        super(id);
+        this.img = new Image("img", img);
+        add(this.img);
+    }
+
+    @Override
+    public Component add(final Behavior... behaviors) {
+        this.img.add(behaviors);
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/39f8a069/client/old_console/src/main/java/org/apache/syncope/client/console/panels/JQueryUITabbedPanel.java
----------------------------------------------------------------------
diff --git 
a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/JQueryUITabbedPanel.java
 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/JQueryUITabbedPanel.java
new file mode 100644
index 0000000..d898ba6
--- /dev/null
+++ 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/JQueryUITabbedPanel.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.util.List;
+import org.apache.wicket.extensions.ajax.markup.html.tabs.AjaxTabbedPanel;
+import org.apache.wicket.extensions.markup.html.tabs.ITab;
+
+/**
+ * AjaxTabbedPanel with JQueryUI styling.
+ */
+public class JQueryUITabbedPanel<T extends ITab> extends AjaxTabbedPanel<T> {
+
+    private static final long serialVersionUID = -5059184710433341333L;
+
+    public JQueryUITabbedPanel(final String id, final List<T> tabs) {
+        super(id, tabs);
+    }
+
+    @Override
+    protected String getTabContainerCssClass() {
+        return "";
+    }
+
+    @Override
+    protected String getSelectedTabCssClass() {
+        return "ui-state-active selected";
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/39f8a069/client/old_console/src/main/java/org/apache/syncope/client/console/panels/LayoutsPanel.java
----------------------------------------------------------------------
diff --git 
a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/LayoutsPanel.java
 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/LayoutsPanel.java
new file mode 100644
index 0000000..26f1894
--- /dev/null
+++ 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/LayoutsPanel.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.util.List;
+import org.apache.syncope.client.console.commons.AttrLayoutType;
+import org.apache.syncope.client.console.commons.Constants;
+import org.apache.syncope.client.console.commons.SelectChoiceRenderer;
+import org.apache.syncope.client.console.commons.XMLRolesReader;
+import org.apache.syncope.client.console.rest.ConfigurationRestClient;
+import org.apache.syncope.client.console.rest.SchemaRestClient;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.AjaxPalettePanel;
+import org.apache.syncope.common.lib.to.AttrTO;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.form.AjaxButton;
+import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.model.util.ListModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class LayoutsPanel extends Panel {
+
+    /**
+     * Logger.
+     */
+    private static final Logger LOG = 
LoggerFactory.getLogger(LayoutsPanel.class);
+
+    private static final long serialVersionUID = -6804066913177804275L;
+
+    private static final String CANCEL = "cancel";
+
+    private static final String APPLY = "apply";
+
+    @SpringBean
+    protected XMLRolesReader xmlRolesReader;
+
+    @SpringBean
+    private SchemaRestClient schemaRestClient;
+
+    @SpringBean
+    private ConfigurationRestClient confRestClient;
+
+    @SuppressWarnings("unchecked")
+    public LayoutsPanel(final String id, final AttrLayoutType attrLayoutType, 
final NotificationPanel feedbackPanel) {
+        super(id);
+
+        final WebMarkupContainer container = new 
WebMarkupContainer("container");
+        container.setOutputMarkupId(true);
+
+        final Form<String> form = new Form<String>("form");
+        form.setOutputMarkupId(true);
+
+        final AttrTO attrLayout = 
confRestClient.readAttrLayout(attrLayoutType);
+        form.setModel(new CompoundPropertyModel(attrLayout.getValues()));
+
+        final List<String> fields = 
schemaRestClient.getPlainSchemaNames(attrLayoutType.getAttrType());
+        final ListModel<String> selectedFields =
+                new ListModel<String>(attrLayout.getValues().isEmpty() ? 
fields : attrLayout.getValues());
+        final ListModel<String> availableFields = new 
ListModel<String>(fields);
+
+        form.add(new AjaxPalettePanel<String>("fields", selectedFields, 
availableFields,
+                new SelectChoiceRenderer<String>(), true, true));
+
+        final AjaxButton submit = new IndicatingAjaxButton(APPLY, new 
ResourceModel(APPLY)) {
+
+            private static final long serialVersionUID = -958724007591692537L;
+
+            @Override
+            protected void onSubmit(final AjaxRequestTarget target, final 
Form<?> form) {
+                try {
+                    confRestClient.set(attrLayout);
+                    info(getString(Constants.OPERATION_SUCCEEDED));
+                } catch (Exception e) {
+                    LOG.error("While saving layout configuration", e);
+                    error(getString(Constants.ERROR) + ": " + e.getMessage());
+                }
+                feedbackPanel.refresh(target);
+            }
+
+            @Override
+            protected void onError(final AjaxRequestTarget target, final 
Form<?> form) {
+                error(getString(Constants.ERROR) + ": While saving layout 
configuration");
+                feedbackPanel.refresh(target);
+            }
+        };
+
+        form.add(submit);
+
+        final IndicatingAjaxButton cancel = new IndicatingAjaxButton(CANCEL, 
new ResourceModel(CANCEL)) {
+
+            private static final long serialVersionUID = -958724007591692537L;
+
+            @Override
+            protected void onSubmit(final AjaxRequestTarget target, final 
Form<?> form) {
+                target.add(container);
+            }
+
+            @Override
+            protected void onError(final AjaxRequestTarget target, final 
Form<?> form) {
+            }
+        };
+
+        cancel.setDefaultFormProcessing(false);
+        form.add(cancel);
+        container.add(form);
+        add(container);
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/39f8a069/client/old_console/src/main/java/org/apache/syncope/client/console/panels/LoggerCategoryPanel.java
----------------------------------------------------------------------
diff --git 
a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/LoggerCategoryPanel.java
 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/LoggerCategoryPanel.java
new file mode 100644
index 0000000..70e0361
--- /dev/null
+++ 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/LoggerCategoryPanel.java
@@ -0,0 +1,461 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.Pair;
+import org.apache.syncope.client.console.commons.Constants;
+import 
org.apache.syncope.client.console.panels.SelectedEventsPanel.EventSelectionChanged;
+import 
org.apache.syncope.client.console.panels.SelectedEventsPanel.InspectSelectedEvent;
+import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.ActionLinksPanel;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.AjaxDropDownChoicePanel;
+import 
org.apache.syncope.client.console.wicket.markup.html.form.AjaxTextFieldPanel;
+import org.apache.syncope.common.lib.to.EventCategoryTO;
+import org.apache.syncope.common.lib.types.AuditElements;
+import org.apache.syncope.common.lib.types.AuditElements.EventCategoryType;
+import org.apache.syncope.common.lib.types.AuditLoggerName;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import 
org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.event.IEvent;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.form.IChoiceRenderer;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.ResourceModel;
+
+public abstract class LoggerCategoryPanel extends Panel {
+
+    private static final long serialVersionUID = 6429053774964787734L;
+
+    private final List<EventCategoryTO> eventCategoryTOs;
+
+    private final EventCategoryTO eventCategoryTO = new EventCategoryTO();
+
+    private final WebMarkupContainer categoryContainer;
+
+    private final WebMarkupContainer eventsContainer;
+
+    private final SelectedEventsPanel selectedEventsPanel;
+
+    private final AjaxDropDownChoicePanel<EventCategoryType> type;
+
+    private final AjaxDropDownChoicePanel<String> category;
+
+    private final AjaxDropDownChoicePanel<String> subcategory;
+
+    private final AjaxTextFieldPanel custom;
+
+    private final ActionLinksPanel actionPanel;
+
+    private final IModel<List<String>> model;
+
+    public LoggerCategoryPanel(
+            final String id,
+            final List<EventCategoryTO> eventCategoryTOs,
+            final IModel<List<String>> model,
+            final PageReference pageReference,
+            final String pageId) {
+        super(id);
+
+        this.model = model;
+        selectedEventsPanel = new SelectedEventsPanel("selectedEventsPanel", 
model);
+        add(selectedEventsPanel);
+
+        this.eventCategoryTOs = eventCategoryTOs;
+
+        categoryContainer = new WebMarkupContainer("categoryContainer");
+        categoryContainer.setOutputMarkupId(true);
+        add(categoryContainer);
+
+        eventsContainer = new WebMarkupContainer("eventsContainer");
+        eventsContainer.setOutputMarkupId(true);
+        add(eventsContainer);
+
+        authorizeList();
+        authorizeChanges();
+
+        categoryContainer.add(new Label("typeLabel", new ResourceModel("type", 
"type")));
+
+        type = new AjaxDropDownChoicePanel<EventCategoryType>(
+                "type",
+                "type",
+                new PropertyModel<EventCategoryType>(eventCategoryTO, "type"),
+                false);
+        type.setChoices(Arrays.asList(EventCategoryType.values()));
+        type.setStyleSheet("ui-widget-content ui-corner-all");
+        type.setChoiceRenderer(new IChoiceRenderer<EventCategoryType>() {
+
+            private static final long serialVersionUID = 2317134950949778735L;
+
+            @Override
+            public String getDisplayValue(final EventCategoryType 
eventCategoryType) {
+                return eventCategoryType.name();
+            }
+
+            @Override
+            public String getIdValue(final EventCategoryType 
eventCategoryType, final int i) {
+                return eventCategoryType.name();
+            }
+        });
+        categoryContainer.add(type);
+
+        type.getField().add(new 
AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306810L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                send(LoggerCategoryPanel.this, Broadcast.EXACT, new 
ChangeCategoryEvent(target, type));
+            }
+        });
+
+        categoryContainer.add(new Label("categoryLabel", new 
ResourceModel("category", "category")));
+
+        category = new AjaxDropDownChoicePanel<String>(
+                "category",
+                "category",
+                new PropertyModel<String>(eventCategoryTO, "category"),
+                false);
+        category.setChoices(filter(eventCategoryTOs, type.getModelObject()));
+        category.setStyleSheet("ui-widget-content ui-corner-all");
+        categoryContainer.add(category);
+
+        category.getField().add(new 
AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306811L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                send(LoggerCategoryPanel.this, Broadcast.EXACT, new 
ChangeCategoryEvent(target, category));
+            }
+        });
+
+        categoryContainer.add(new Label("subcategoryLabel", new 
ResourceModel("subcategory", "subcategory")));
+
+        subcategory = new AjaxDropDownChoicePanel<String>(
+                "subcategory",
+                "subcategory",
+                new PropertyModel<String>(eventCategoryTO, "subcategory"),
+                false);
+        subcategory.setChoices(filter(eventCategoryTOs, type.getModelObject(), 
category.getModelObject()));
+        subcategory.setStyleSheet("ui-widget-content ui-corner-all");
+        categoryContainer.add(subcategory);
+
+        subcategory.getField().add(new 
AjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
+
+            private static final long serialVersionUID = -1107858522700306812L;
+
+            @Override
+            protected void onUpdate(final AjaxRequestTarget target) {
+                send(LoggerCategoryPanel.this, Broadcast.EXACT, new 
ChangeCategoryEvent(target, subcategory));
+            }
+        });
+
+        categoryContainer.add(new Label("customLabel", new 
ResourceModel("custom", "custom")).setVisible(false));
+
+        custom = new AjaxTextFieldPanel("custom", "custom", new 
Model<String>(null));
+        custom.setStyleSheet("ui-widget-content ui-corner-all 
short_fixedsize");
+        custom.setVisible(false);
+        custom.setEnabled(false);
+
+        categoryContainer.add(custom);
+
+        actionPanel = new ActionLinksPanel("customActions", new Model(), 
pageReference);
+        categoryContainer.add(actionPanel);
+
+        actionPanel.add(new ActionLink() {
+
+            private static final long serialVersionUID = -3722207913631435501L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                if (StringUtils.isNotBlank(custom.getModelObject())) {
+                    final Pair<EventCategoryTO, AuditElements.Result> parsed =
+                            
AuditLoggerName.parseEventCategory(custom.getModelObject());
+
+                    final String eventString = AuditLoggerName.buildEvent(
+                            parsed.getKey().getType(),
+                            null,
+                            null,
+                            parsed.getKey().getEvents().isEmpty()
+                                    ? StringUtils.EMPTY : 
parsed.getKey().getEvents().iterator().next(),
+                            parsed.getValue());
+
+                    custom.setModelObject(StringUtils.EMPTY);
+                    send(LoggerCategoryPanel.this.getPage(), 
Broadcast.BREADTH, new EventSelectionChanged(
+                            target,
+                            Collections.<String>singleton(eventString),
+                            Collections.<String>emptySet()));
+                    target.add(categoryContainer);
+                }
+            }
+        }, ActionLink.ActionType.CREATE, pageId, true);
+
+        actionPanel.add(new ActionLink() {
+
+            private static final long serialVersionUID = -3722207913631435502L;
+
+            @Override
+            public void onClick(final AjaxRequestTarget target) {
+                if (StringUtils.isNotBlank(custom.getModelObject())) {
+                    Pair<EventCategoryTO, AuditElements.Result> parsed =
+                            
AuditLoggerName.parseEventCategory(custom.getModelObject());
+
+                    String eventString = AuditLoggerName.buildEvent(
+                            parsed.getKey().getType(),
+                            null,
+                            null,
+                            parsed.getKey().getEvents().isEmpty()
+                                    ? StringUtils.EMPTY : 
parsed.getKey().getEvents().iterator().next(),
+                            parsed.getValue());
+
+                    custom.setModelObject(StringUtils.EMPTY);
+                    send(LoggerCategoryPanel.this.getPage(), 
Broadcast.BREADTH, new EventSelectionChanged(
+                            target,
+                            Collections.<String>emptySet(),
+                            Collections.<String>singleton(eventString)));
+                    target.add(categoryContainer);
+                }
+            }
+        }, ActionLink.ActionType.DELETE, pageId, true);
+
+        actionPanel.setVisible(false);
+        actionPanel.setEnabled(false);
+
+        eventsContainer.add(new EventSelectionPanel("eventsPanel", 
eventCategoryTO, model) {
+
+            private static final long serialVersionUID = 3513194801190026082L;
+
+            @Override
+            protected void onEventAction(final IEvent<?> event) {
+                LoggerCategoryPanel.this.onEventAction(event);
+            }
+        });
+    }
+
+    private List<String> filter(
+            final List<EventCategoryTO> eventCategoryTOs, final 
EventCategoryType type) {
+        final Set<String> res = new HashSet<String>();
+
+        for (EventCategoryTO eventCategory : eventCategoryTOs) {
+            if (type == eventCategory.getType() && 
StringUtils.isNotEmpty(eventCategory.getCategory())) {
+                res.add(eventCategory.getCategory());
+            }
+        }
+
+        final List<String> filtered = new ArrayList<String>(res);
+        Collections.sort(filtered);
+        return filtered;
+    }
+
+    private List<String> filter(
+            final List<EventCategoryTO> eventCategoryTOs, final 
EventCategoryType type, final String category) {
+        final Set<String> res = new HashSet<String>();
+
+        for (EventCategoryTO eventCategory : eventCategoryTOs) {
+            if (type == eventCategory.getType() && 
StringUtils.equals(category, eventCategory.getCategory())
+                    && StringUtils.isNotEmpty(eventCategory.getSubcategory())) 
{
+                res.add(eventCategory.getSubcategory());
+            }
+        }
+
+        final List<String> filtered = new ArrayList<String>(res);
+        Collections.sort(filtered);
+        return filtered;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public void onEvent(final IEvent<?> event) {
+        if (event.getPayload() instanceof ChangeCategoryEvent) {
+            // update objects ....
+            eventCategoryTO.getEvents().clear();
+
+            final ChangeCategoryEvent change = (ChangeCategoryEvent) 
event.getPayload();
+
+            final Panel changedPanel = change.getChangedPanel();
+            if ("type".equals(changedPanel.getId())) {
+                eventCategoryTO.setType(type.getModelObject());
+                eventCategoryTO.setCategory(null);
+                eventCategoryTO.setSubcategory(null);
+
+                if (type.getModelObject() == EventCategoryType.CUSTOM) {
+                    category.setChoices(Collections.<String>emptyList());
+                    subcategory.setChoices(Collections.<String>emptyList());
+                    category.setEnabled(false);
+                    subcategory.setEnabled(false);
+                    custom.setVisible(true);
+                    custom.setEnabled(true);
+                    actionPanel.setVisible(true);
+                    actionPanel.setEnabled(true);
+
+                } else {
+                    category.setChoices(filter(eventCategoryTOs, 
type.getModelObject()));
+                    subcategory.setChoices(Collections.<String>emptyList());
+                    category.setEnabled(true);
+                    subcategory.setEnabled(true);
+                    custom.setVisible(false);
+                    custom.setEnabled(false);
+                    actionPanel.setVisible(false);
+                    actionPanel.setEnabled(false);
+                }
+                change.getTarget().add(categoryContainer);
+            } else if ("category".equals(changedPanel.getId())) {
+                subcategory.setChoices(filter(eventCategoryTOs, 
type.getModelObject(), category.getModelObject()));
+                eventCategoryTO.setCategory(category.getModelObject());
+                eventCategoryTO.setSubcategory(null);
+                change.getTarget().add(categoryContainer);
+            } else {
+                eventCategoryTO.setSubcategory(subcategory.getModelObject());
+            }
+
+            updateEventsContainer(change.getTarget());
+        } else if (event.getPayload() instanceof InspectSelectedEvent) {
+            // update objects ....
+            eventCategoryTO.getEvents().clear();
+
+            InspectSelectedEvent inspectSelectedEvent = (InspectSelectedEvent) 
event.getPayload();
+
+            Pair<EventCategoryTO, AuditElements.Result> categoryEvent =
+                    
AuditLoggerName.parseEventCategory(inspectSelectedEvent.getEvent());
+
+            eventCategoryTO.setType(categoryEvent.getKey().getType());
+            category.setChoices(filter(eventCategoryTOs, 
type.getModelObject()));
+
+            eventCategoryTO.setCategory(categoryEvent.getKey().getCategory());
+            subcategory.setChoices(filter(eventCategoryTOs, 
type.getModelObject(), category.getModelObject()));
+
+            
eventCategoryTO.setSubcategory(categoryEvent.getKey().getSubcategory());
+
+            if (categoryEvent.getKey().getType() == EventCategoryType.CUSTOM) {
+                custom.setModelObject(AuditLoggerName.buildEvent(
+                        categoryEvent.getKey().getType(),
+                        categoryEvent.getKey().getCategory(),
+                        categoryEvent.getKey().getSubcategory(),
+                        categoryEvent.getKey().getEvents().isEmpty()
+                                ? StringUtils.EMPTY : 
categoryEvent.getKey().getEvents().iterator().next(),
+                        categoryEvent.getValue()));
+
+                category.setEnabled(false);
+                subcategory.setEnabled(false);
+                custom.setVisible(true);
+                custom.setEnabled(true);
+                actionPanel.setVisible(true);
+                actionPanel.setEnabled(true);
+            } else {
+                category.setEnabled(true);
+                subcategory.setEnabled(true);
+                custom.setVisible(false);
+                custom.setEnabled(false);
+                actionPanel.setVisible(false);
+                actionPanel.setEnabled(false);
+            }
+
+            inspectSelectedEvent.getTarget().add(categoryContainer);
+            updateEventsContainer(inspectSelectedEvent.getTarget());
+        }
+    }
+
+    private void setEvents() {
+        final Iterator<EventCategoryTO> itor = eventCategoryTOs.iterator();
+        while (itor.hasNext() && eventCategoryTO.getEvents().isEmpty()) {
+            final EventCategoryTO eventCategory = itor.next();
+            if (eventCategory.getType() == eventCategoryTO.getType()
+                    && StringUtils.equals(eventCategory.getCategory(), 
eventCategoryTO.getCategory())
+                    && StringUtils.equals(eventCategory.getSubcategory(), 
eventCategoryTO.getSubcategory())) {
+                eventCategoryTO.getEvents().addAll(eventCategory.getEvents());
+            }
+        }
+    }
+
+    private class ChangeCategoryEvent {
+
+        private final AjaxRequestTarget target;
+
+        private final Panel changedPanel;
+
+        public ChangeCategoryEvent(final AjaxRequestTarget target, final Panel 
changedPanel) {
+            this.target = target;
+            this.changedPanel = changedPanel;
+        }
+
+        public AjaxRequestTarget getTarget() {
+            return target;
+        }
+
+        public Panel getChangedPanel() {
+            return changedPanel;
+        }
+    }
+
+    /**
+     * To be extended in order to add actions on events.
+     *
+     * @param event event.
+     */
+    protected void onEventAction(final IEvent<?> event) {
+        // nothing by default
+    }
+
+    private void authorizeList() {
+        for (String role : getListRoles()) {
+            MetaDataRoleAuthorizationStrategy.authorize(selectedEventsPanel, 
RENDER, role);
+        }
+    }
+
+    private void authorizeChanges() {
+        for (String role : getChangeRoles()) {
+            MetaDataRoleAuthorizationStrategy.authorize(categoryContainer, 
RENDER, role);
+            MetaDataRoleAuthorizationStrategy.authorize(eventsContainer, 
RENDER, role);
+        }
+    }
+
+    private void updateEventsContainer(final AjaxRequestTarget target) {
+        setEvents();
+
+        eventsContainer.addOrReplace(new EventSelectionPanel("eventsPanel", 
eventCategoryTO, model) {
+
+            private static final long serialVersionUID = 3513194801190026082L;
+
+            @Override
+            public void onEventAction(final IEvent<?> event) {
+                LoggerCategoryPanel.this.onEventAction(event);
+            }
+        });
+        target.add(eventsContainer);
+    }
+
+    protected abstract String[] getListRoles();
+
+    protected abstract String[] getChangeRoles();
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/39f8a069/client/old_console/src/main/java/org/apache/syncope/client/console/panels/MembershipsPanel.java
----------------------------------------------------------------------
diff --git 
a/client/old_console/src/main/java/org/apache/syncope/client/console/panels/MembershipsPanel.java
 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/MembershipsPanel.java
new file mode 100644
index 0000000..fa0a9bc
--- /dev/null
+++ 
b/client/old_console/src/main/java/org/apache/syncope/client/console/panels/MembershipsPanel.java
@@ -0,0 +1,255 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.client.console.panels;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.swing.tree.DefaultMutableTreeNode;
+import org.apache.syncope.client.console.commons.Mode;
+import org.apache.syncope.client.console.commons.GroupTreeBuilder;
+import org.apache.syncope.client.console.commons.status.StatusUtils;
+import org.apache.syncope.client.console.pages.MembershipModalPage;
+import org.apache.syncope.client.console.pages.UserModalPage;
+import 
org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink;
+import 
org.apache.syncope.client.console.wicket.ajax.markup.html.IndicatingOnConfirmAjaxLink;
+import 
org.apache.syncope.client.console.wicket.markup.html.tree.DefaultMutableTreeNodeExpansion;
+import 
org.apache.syncope.client.console.wicket.markup.html.tree.DefaultMutableTreeNodeExpansionModel;
+import 
org.apache.syncope.client.console.wicket.markup.html.tree.TreeGroupProvider;
+import org.apache.syncope.common.lib.to.MembershipTO;
+import org.apache.syncope.common.lib.to.GroupTO;
+import org.apache.syncope.common.lib.to.UserTO;
+import org.apache.wicket.Component;
+import org.apache.wicket.Page;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
+import 
org.apache.wicket.extensions.markup.html.repeater.tree.DefaultNestedTree;
+import org.apache.wicket.extensions.markup.html.repeater.tree.ITreeProvider;
+import org.apache.wicket.extensions.markup.html.repeater.tree.NestedTree;
+import org.apache.wicket.extensions.markup.html.repeater.tree.content.Folder;
+import 
org.apache.wicket.extensions.markup.html.repeater.tree.theme.WindowsTheme;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+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.Model;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+
+public class MembershipsPanel extends Panel {
+
+    private static final long serialVersionUID = -2559791301973107191L;
+
+    @SpringBean
+    private GroupTreeBuilder groupTreeBuilder;
+
+    private final ListView<MembershipTO> membView;
+
+    private final UserTO userTO;
+
+    private final StatusPanel statusPanel;
+
+    private final NestedTree<DefaultMutableTreeNode> tree;
+
+    public MembershipsPanel(final String id, final UserTO userTO, final Mode 
mode,
+            final StatusPanel statusPanel, final PageReference pageRef) {
+
+        super(id);
+        this.userTO = userTO;
+        this.statusPanel = statusPanel;
+
+        final WebMarkupContainer membershipsContainer = new 
WebMarkupContainer("membershipsContainer");
+        membershipsContainer.setOutputMarkupId(true);
+        add(membershipsContainer);
+
+        final ModalWindow membWin = new ModalWindow("membershipWin");
+        membWin.setCssClassName(ModalWindow.CSS_CLASS_GRAY);
+        membWin.setCookieName("create-membership-modal");
+        add(membWin);
+
+        final ITreeProvider<DefaultMutableTreeNode> treeProvider = new 
TreeGroupProvider(groupTreeBuilder, true);
+        final DefaultMutableTreeNodeExpansionModel treeModel = new 
DefaultMutableTreeNodeExpansionModel();
+
+        tree = new DefaultNestedTree<DefaultMutableTreeNode>("treeTable", 
treeProvider, treeModel) {
+
+            private static final long serialVersionUID = 7137658050662575546L;
+
+            @Override
+            protected Component newContentComponent(final String id, final 
IModel<DefaultMutableTreeNode> node) {
+                final DefaultMutableTreeNode treeNode = node.getObject();
+                final GroupTO groupTO = (GroupTO) treeNode.getUserObject();
+
+                return new Folder<DefaultMutableTreeNode>(id, 
MembershipsPanel.this.tree, node) {
+
+                    private static final long serialVersionUID = 
9046323319920426493L;
+
+                    @Override
+                    protected boolean isClickable() {
+                        return true;
+                    }
+
+                    @Override
+                    protected IModel<?> newLabelModel(final 
IModel<DefaultMutableTreeNode> model) {
+                        return new Model<String>(groupTO.getDisplayName());
+                    }
+
+                    @Override
+                    protected void onClick(final AjaxRequestTarget target) {
+                        if (groupTO.getKey() > 0) {
+                            membWin.setPageCreator(new 
ModalWindow.PageCreator() {
+
+                                private static final long serialVersionUID = 
7661763358801821185L;
+
+                                @Override
+                                public Page createPage() {
+                                    PageReference pageRef = 
getPage().getPageReference();
+
+                                    for (MembershipTO membTO : 
membView.getList()) {
+                                        if (membTO.getGroupKey() == 
groupTO.getKey()) {
+                                            return new 
MembershipModalPage(pageRef, membWin, membTO, mode);
+                                        }
+                                    }
+                                    MembershipTO membTO = new MembershipTO();
+                                    membTO.setGroupKey(groupTO.getKey());
+                                    membTO.setGroupName(groupTO.getName());
+
+                                    return new MembershipModalPage(pageRef, 
membWin, membTO, mode);
+                                }
+                            });
+                            membWin.show(target);
+                        }
+                    }
+                };
+            }
+        };
+        tree.add(new WindowsTheme());
+        tree.setOutputMarkupId(true);
+
+        DefaultMutableTreeNodeExpansion.get().expandAll();
+
+        this.add(tree);
+
+        membView = new ListView<MembershipTO>("memberships",
+                new PropertyModel<List<? extends MembershipTO>>(userTO, 
"memberships")) {
+
+                    private static final long serialVersionUID = 
9101744072914090143L;
+
+                    @Override
+                    protected void populateItem(final ListItem<MembershipTO> 
item) {
+                        final MembershipTO membershipTO = (MembershipTO) 
item.getDefaultModelObject();
+
+                        item.add(new Label("groupId", new 
Model<Long>(membershipTO.getGroupKey())));
+                        item.add(new Label("groupName", new 
Model<String>(membershipTO.getGroupName())));
+
+                        AjaxLink editLink = new 
ClearIndicatingAjaxLink("editLink", pageRef) {
+
+                            private static final long serialVersionUID = 
-7978723352517770644L;
+
+                            @Override
+                            protected void onClickInternal(final 
AjaxRequestTarget target) {
+                                membWin.setPageCreator(new 
ModalWindow.PageCreator() {
+
+                                    private static final long serialVersionUID 
= -7834632442532690940L;
+
+                                    @Override
+                                    public Page createPage() {
+                                        return new 
MembershipModalPage(getPage().getPageReference(), membWin,
+                                                membershipTO, mode);
+
+                                    }
+                                });
+                                membWin.show(target);
+                            }
+                        };
+                        item.add(editLink);
+
+                        AjaxLink deleteLink = new 
IndicatingOnConfirmAjaxLink("deleteLink", pageRef) {
+
+                            private static final long serialVersionUID = 
-7978723352517770644L;
+
+                            @Override
+                            protected void onClickInternal(final 
AjaxRequestTarget target) {
+                                userTO.getMemberships().remove(membershipTO);
+                                ((UserModalPage) 
getPage()).getUserTO().getMemberships().remove(membershipTO);
+                                target.add(membershipsContainer);
+
+                                GroupTO groupTO = 
groupTreeBuilder.findGroup(membershipTO.getGroupKey());
+                                Set<String> resourcesToRemove = groupTO == null
+                                        ? Collections.<String>emptySet() : 
groupTO.getResources();
+                                if (!resourcesToRemove.isEmpty()) {
+                                    Set<String> resourcesAssignedViaMembership 
= new HashSet<>();
+                                    for (MembershipTO membTO : 
userTO.getMemberships()) {
+                                        groupTO = 
groupTreeBuilder.findGroup(membTO.getGroupKey());
+                                        if (groupTO != null) {
+                                            
resourcesAssignedViaMembership.addAll(groupTO.getResources());
+                                        }
+                                    }
+                                    
resourcesToRemove.removeAll(resourcesAssignedViaMembership);
+                                    
resourcesToRemove.removeAll(userTO.getResources());
+                                }
+
+                                StatusUtils.update(
+                                        userTO, statusPanel, target, 
Collections.<String>emptySet(), resourcesToRemove);
+                            }
+                        };
+                        item.add(deleteLink);
+                    }
+                };
+
+        membershipsContainer.add(membView);
+
+        setWindowClosedCallback(membWin, membershipsContainer);
+    }
+
+    private void setWindowClosedCallback(final ModalWindow window, final 
WebMarkupContainer container) {
+        window.setWindowClosedCallback(new ModalWindow.WindowClosedCallback() {
+
+            private static final long serialVersionUID = 8804221891699487139L;
+
+            @Override
+            public void onClose(final AjaxRequestTarget target) {
+                final UserTO updatedUserTO = ((UserModalPage) 
getPage()).getUserTO();
+                if (!userTO.equals(updatedUserTO)) {
+                    if (updatedUserTO.getMemberships().size() > 
userTO.getMemberships().size()) {
+                        Set<Long> diff = new 
HashSet<Long>(updatedUserTO.getMembershipMap().keySet());
+                        diff.removeAll(userTO.getMembershipMap().keySet());
+
+                        Set<String> resourcesToAdd = new HashSet<>();
+                        for (Long diffMembId : diff) {
+                            long groupId = 
updatedUserTO.getMembershipMap().get(diffMembId).getGroupKey();
+                            GroupTO groupTO = 
groupTreeBuilder.findGroup(groupId);
+                            resourcesToAdd.addAll(groupTO.getResources());
+                            StatusUtils.update(
+                                    userTO, statusPanel, target, 
resourcesToAdd, Collections.<String>emptySet());
+                        }
+                    }
+
+                    MembershipsPanel.this.userTO.getMemberships().clear();
+                    
MembershipsPanel.this.userTO.getMemberships().addAll(updatedUserTO.getMemberships());
+                    target.add(container);
+                }
+            }
+        });
+    }
+}

Reply via email to