You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by fm...@apache.org on 2015/09/21 15:51:12 UTC

[26/30] syncope git commit: [SYNCOPE-156] fix sidebar management

[SYNCOPE-156] fix sidebar management


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

Branch: refs/heads/master
Commit: 10299f2c4e12376d1ca9ae700990576a8e15cf08
Parents: 54888f6
Author: fmartelli <fa...@gmail.com>
Authored: Thu Sep 17 12:07:15 2015 +0200
Committer: fmartelli <fa...@gmail.com>
Committed: Thu Sep 17 12:07:15 2015 +0200

----------------------------------------------------------------------
 .../syncope/client/console/pages/BasePage.java  |   4 +-
 .../syncope/client/console/pages/Realms.java    | 158 ++-----------
 .../console/panels/AbstractModalPanel.java      |   4 +-
 .../client/console/panels/GroupModalPanel.java  |   8 +-
 .../console/panels/GroupSearchResultPanel.java  |   6 +-
 .../client/console/panels/RealmModalPanel.java  |   2 +-
 .../console/panels/RealmSidebarPanel.java       | 235 +++++++++++++++++++
 .../syncope/client/console/themes/AdminLTE.java |   2 +-
 .../markup/html/bootstrap/dialog/BaseModal.java |   2 +-
 .../syncope/client/console/pages/Realms.html    |   9 +-
 .../console/panels/RealmSidebarPanel.html       |  53 +++++
 11 files changed, 318 insertions(+), 165 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/10299f2c/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 921888e..622d204 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
@@ -65,7 +65,7 @@ public class BasePage extends AbstractBasePage implements IAjaxIndicatorAware {
         add(new Label("version", SyncopeConsoleSession.get().getVersion()));
         add(new Label("username", SyncopeConsoleSession.get().getSelfTO().getUsername()));
 
-        WebMarkupContainer todosContainer = new WebMarkupContainer("todosContainer");
+        final WebMarkupContainer todosContainer = new WebMarkupContainer("todosContainer");
         add(todosContainer);
         Label todos = new Label("todos", "0");
         todosContainer.add(todos);
@@ -176,7 +176,7 @@ public class BasePage extends AbstractBasePage implements IAjaxIndicatorAware {
             }
         });
     }
-    
+
     /**
      * Set a WindowClosedCallback for a Modal instance.
      *

http://git-wip-us.apache.org/repos/asf/syncope/blob/10299f2c/client/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java b/client/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java
index 31b1081..fa480aa 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/pages/Realms.java
@@ -20,35 +20,25 @@ package org.apache.syncope.client.console.pages;
 
 import static org.apache.wicket.Component.ENABLE;
 
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
 import org.apache.syncope.client.console.SyncopeConsoleSession;
 import org.apache.syncope.client.console.commons.Constants;
 import org.apache.syncope.client.console.panels.Realm;
 import org.apache.syncope.client.console.panels.RealmModalPanel;
+import org.apache.syncope.client.console.panels.RealmSidebarPanel;
+import org.apache.syncope.client.console.panels.RealmSidebarPanel.ControlSidebarClick;
 import org.apache.syncope.client.console.rest.RealmRestClient;
 import org.apache.syncope.client.console.wicket.ajax.markup.html.ClearIndicatingAjaxLink;
 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
 import org.apache.syncope.common.lib.to.RealmTO;
 import org.apache.syncope.common.lib.types.Entitlement;
-import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.ajax.markup.html.AjaxLink;
 import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
-import org.apache.wicket.event.Broadcast;
 import org.apache.wicket.event.IEvent;
 import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow.WindowClosedCallback;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.basic.Label;
-import org.apache.wicket.markup.html.panel.Fragment;
-import org.apache.wicket.markup.repeater.RepeatingView;
 import org.apache.wicket.model.Model;
-import org.apache.wicket.model.PropertyModel;
 import org.apache.wicket.model.ResourceModel;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 import org.apache.wicket.spring.injection.annot.SpringBean;
@@ -60,26 +50,19 @@ public class Realms extends BasePage {
     @SpringBean
     private RealmRestClient realmRestClient;
 
-    private final WebMarkupContainer menu;
+    private final RealmSidebarPanel realmSidebarPanel;
 
     private final WebMarkupContainer content;
 
-    private RealmTO currentRealm;
-
     private final BaseModal<RealmTO> modal;
 
     public Realms(final PageParameters parameters) {
         super(parameters);
 
-        final List<RealmTO> realms = realmRestClient.list();
-        Collections.sort(realms, new RealmNameComparator());
-
-        menu = new WebMarkupContainer("menu");
-        menu.setOutputMarkupId(true);
-        add(menu);
-
-        addRealmTree(getParentMap(realms), 0L, menu);
-        setCurrentRealm(realms.get(0));
+        realmSidebarPanel = new RealmSidebarPanel("realmSidebarPanel", getPageReference());
+        realmSidebarPanel.setMarkupId("sidebar");
+        realmSidebarPanel.setOutputMarkupId(true);
+        add(realmSidebarPanel);
 
         content = new WebMarkupContainer("content");
         content.add(new Label("header", "Root realm"));
@@ -96,9 +79,7 @@ public class Realms extends BasePage {
 
             @Override
             public void onClose(final AjaxRequestTarget target) {
-                final List<RealmTO> realms = realmRestClient.list();
-                Collections.sort(realms, new RealmNameComparator());
-                target.add(addRealmTree(getParentMap(realms), 0L, menu));
+                target.add(realmSidebarPanel.reloadRealmTree());
 
                 modal.show(false);
 
@@ -110,83 +91,7 @@ public class Realms extends BasePage {
             }
         });
 
-        updateRealmContent(currentRealm);
-    }
-
-    private MarkupContainer addRealmTree(
-            final Map<Long, List<RealmTO>> parentMap, final Long key, final MarkupContainer container) {
-        final RepeatingView listItems = new RepeatingView("list");
-        listItems.setOutputMarkupId(true);
-        container.addOrReplace(listItems);
-
-        for (final RealmTO realm : parentMap.get(key)) {
-            final Fragment fragment;
-
-            final AjaxLink<Void> link = new AjaxLink<Void>("link") {
-
-                private static final long serialVersionUID = -7978723352517770644L;
-
-                @Override
-                public void onClick(final AjaxRequestTarget target) {
-                    Realms.this.setCurrentRealm(realm);
-                    send(Realms.this, Broadcast.EXACT, new ControlSidebarClick<>(realm, target));
-                }
-            };
-
-            link.addOrReplace(new Label("name", new PropertyModel<String>(realm, "name")));
-
-            if (parentMap.containsKey(realm.getKey()) && !parentMap.get(realm.getKey()).isEmpty()) {
-                fragment = new Fragment(String.valueOf(realm.getKey()), "withChildren", Realms.this);
-                addRealmTree(parentMap, realm.getKey(), fragment);
-            } else {
-                fragment = new Fragment(String.valueOf(realm.getKey()), "withoutChildren", Realms.this);
-            }
-
-            fragment.addOrReplace(link);
-            fragment.setOutputMarkupId(true);
-            listItems.addOrReplace(fragment);
-        }
-
-        return container;
-    }
-
-    private Map<Long, List<RealmTO>> getParentMap(final List<RealmTO> realms) {
-        final Map<Long, List<RealmTO>> res = new HashMap<>();
-        res.put(0L, new ArrayList<RealmTO>());
-
-        final Map<Long, List<RealmTO>> cache = new HashMap<>();
-
-        for (RealmTO realm : realms) {
-            if (res.containsKey(realm.getParent())) {
-                res.get(realm.getParent()).add(realm);
-
-                final List<RealmTO> children = new ArrayList<>();
-                res.put(realm.getKey(), children);
-
-                if (cache.containsKey(realm.getKey())) {
-                    children.addAll(cache.get(realm.getKey()));
-                    cache.remove(realm.getKey());
-                }
-            } else if (cache.containsKey(realm.getParent())) {
-                cache.get(realm.getParent()).add(realm);
-            } else {
-                final List<RealmTO> children = new ArrayList<>();
-                children.add(realm);
-                cache.put(realm.getParent(), children);
-            }
-        }
-
-        return res;
-    }
-
-    private static class RealmNameComparator implements Comparator<RealmTO>, Serializable {
-
-        private static final long serialVersionUID = 7085057398406518811L;
-
-        @Override
-        public int compare(final RealmTO r1, final RealmTO r2) {
-            return r1.getName().compareTo(r2.getName());
-        }
+        updateRealmContent(realmSidebarPanel.getCurrentRealm());
     }
 
     @Override
@@ -201,14 +106,6 @@ public class Realms extends BasePage {
         }
     }
 
-    private void setCurrentRealm(final RealmTO realmTO) {
-        this.currentRealm = realmTO;
-    }
-
-    public RealmTO getCurrentRealm() {
-        return this.currentRealm;
-    }
-
     private void updateRealmContent(final RealmTO realmTO) {
         content.addOrReplace(new Label("header", realmTO.getName()));
         content.addOrReplace(new Realm("body", realmTO, getPageReference()));
@@ -226,7 +123,7 @@ public class Realms extends BasePage {
             @Override
             protected void onClickInternal(final AjaxRequestTarget target) {
                 try {
-                    final RealmTO toBeDeleted = Realms.this.getCurrentRealm();
+                    final RealmTO toBeDeleted = realmSidebarPanel.getCurrentRealm();
 
                     if (toBeDeleted.getKey() == 0) {
                         throw new Exception("Root realm cannot be deleted");
@@ -234,12 +131,10 @@ public class Realms extends BasePage {
 
                     realmRestClient.delete(toBeDeleted.getFullPath());
 
-                    final List<RealmTO> realms = realmRestClient.list();
-                    Collections.sort(realms, new RealmNameComparator());
-                    target.add(addRealmTree(getParentMap(realms), 0L, menu));
+                    target.add(realmSidebarPanel.reloadRealmTree());
 
-//                    info(getString(Constants.OPERATION_SUCCEEDED));
-//                    feedbackPanel.refresh(target);
+                    info(getString(Constants.OPERATION_SUCCEEDED));
+                    feedbackPanel.refresh(target);
                 } catch (Exception e) {
                     LOG.error("While deleting realm", e);
                     error(getString(Constants.ERROR) + ": " + e.getMessage());
@@ -272,7 +167,7 @@ public class Realms extends BasePage {
                         modal,
                         Realms.this.getPageReference(),
                         realmTO,
-                        Realms.this.getCurrentRealm().getFullPath(),
+                        realmSidebarPanel.getCurrentRealm().getFullPath(),
                         Entitlement.REALM_CREATE,
                         true);
                 target.add(modal.setContent(panel));
@@ -296,9 +191,9 @@ public class Realms extends BasePage {
 
             @Override
             protected void onClickInternal(final AjaxRequestTarget target) {
-                modal.header(Model.of(Realms.this.getCurrentRealm().getName()));
+                modal.header(Model.of(realmSidebarPanel.getCurrentRealm().getName()));
 
-                final RealmTO realmTO = Realms.this.getCurrentRealm();
+                final RealmTO realmTO = realmSidebarPanel.getCurrentRealm();
                 modal.setFormModel(realmTO);
 
                 final RealmModalPanel panel = new RealmModalPanel(
@@ -321,25 +216,4 @@ public class Realms extends BasePage {
 
         content.addOrReplace(editLink);
     }
-
-    private static class ControlSidebarClick<T> {
-
-        private final AjaxRequestTarget target;
-
-        private final T obj;
-
-        public ControlSidebarClick(
-                final T obj, final AjaxRequestTarget target) {
-            this.obj = obj;
-            this.target = target;
-        }
-
-        public T getObj() {
-            return obj;
-        }
-
-        public AjaxRequestTarget getTarget() {
-            return target;
-        }
-    }
 }

http://git-wip-us.apache.org/repos/asf/syncope/blob/10299f2c/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractModalPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractModalPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractModalPanel.java
index 1ddffb7..139283f 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractModalPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/AbstractModalPanel.java
@@ -86,8 +86,8 @@ public class AbstractModalPanel extends Panel {
     @SpringBean
     protected MIMETypesLoader mimeTypesInitializer;
 
-    public AbstractModalPanel(final String id, final BaseModal<?> modal) {
-        super(id);
+    public AbstractModalPanel(final BaseModal<?> modal) {
+        super(BaseModal.getContentId());
         this.modal = modal;
     }
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/10299f2c/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupModalPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupModalPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupModalPanel.java
index 9c2f91b..5bfbe13 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupModalPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupModalPanel.java
@@ -48,14 +48,14 @@ public class GroupModalPanel extends AbstractModalPanel {
 
     protected GroupTO originalGroupTO;
 
-    public GroupModalPanel(final String id, final BaseModal<?> modal, final GroupTO groupTO) {
-        this(id, modal, groupTO, Mode.ADMIN);
+    public GroupModalPanel(final BaseModal<?> modal, final GroupTO groupTO) {
+        this(modal, groupTO, Mode.ADMIN);
     }
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
-    public GroupModalPanel(final String id, final BaseModal<?> modal, final GroupTO groupTO, final Mode mode) {
+    public GroupModalPanel(final BaseModal<?> modal, final GroupTO groupTO, final Mode mode) {
 
-        super(id, modal);
+        super(modal);
 
         this.mode = mode;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/10299f2c/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java
index 6a048b3..ffc232a 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/GroupSearchResultPanel.java
@@ -103,8 +103,7 @@ public class GroupSearchResultPanel extends AnySearchResultPanel {
         // Add defaults in case of no selection
         if (columns.isEmpty()) {
             for (String name : GroupDisplayAttributesModalPage.GROUP_DEFAULT_SELECTION) {
-                columns.add(
-                        new PropertyColumn<AnyTO, String>(new ResourceModel(name, name), name, name));
+                columns.add(new PropertyColumn<AnyTO, String>(new ResourceModel(name, name), name, name));
             }
 
             prefMan.setList(getRequest(), getResponse(), Constants.PREF_GROUP_DETAILS_VIEW,
@@ -126,8 +125,7 @@ public class GroupSearchResultPanel extends AnySearchResultPanel {
 
                     @Override
                     public void onClick(final AjaxRequestTarget target, final AnyTO anyTO) {
-                        editModal.addOrReplace(new GroupModalPanel(
-                                BaseModal.getContentId(), editModal, (GroupTO) model.getObject()));
+                        editModal.addOrReplace(new GroupModalPanel(editModal, (GroupTO) model.getObject()));
 
                         target.add(editModal);
                         editModal.show(target);

http://git-wip-us.apache.org/repos/asf/syncope/blob/10299f2c/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmModalPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmModalPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmModalPanel.java
index ed0c491..7e8f415 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmModalPanel.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmModalPanel.java
@@ -65,7 +65,7 @@ public class RealmModalPanel extends AbstractModalPanel {
             final String entitlement,
             final boolean newRealm) {
 
-        super(BaseModal.getContentId(), modal);
+        super(modal);
         this.newRealm = newRealm;
 
         this.pageRef = pageRef;

http://git-wip-us.apache.org/repos/asf/syncope/blob/10299f2c/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmSidebarPanel.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmSidebarPanel.java b/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmSidebarPanel.java
new file mode 100644
index 0000000..4084a53
--- /dev/null
+++ b/client/console/src/main/java/org/apache/syncope/client/console/panels/RealmSidebarPanel.java
@@ -0,0 +1,235 @@
+/*
+ * 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.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.syncope.client.console.rest.RealmRestClient;
+import org.apache.syncope.common.lib.to.RealmTO;
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.PageReference;
+import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.ajax.markup.html.AjaxLink;
+import org.apache.wicket.event.Broadcast;
+import org.apache.wicket.markup.ComponentTag;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.OnLoadHeaderItem;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.Fragment;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.markup.repeater.RepeatingView;
+import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+
+public class RealmSidebarPanel extends Panel {
+
+    private static final long serialVersionUID = -1100228004207271270L;
+
+    @SpringBean
+    private RealmRestClient realmRestClient;
+
+    private final WebMarkupContainer menu;
+
+    private RealmTO currentRealm;
+
+    private final PageReference pageRef;
+
+    private boolean reload = false;
+
+    public RealmSidebarPanel(final String id, final PageReference pageRef) {
+        super(id);
+        this.pageRef = pageRef;
+
+        final List<RealmTO> realms = realmRestClient.list();
+        Collections.sort(realms, new RealmNameComparator());
+
+        menu = new WebMarkupContainer("menu");
+
+        menu.setOutputMarkupId(true);
+        add(menu);
+
+        reloadRealmTree(reloadRealmParentMap(realms), 0L, menu);
+        setCurrentRealm(realms.get(0));
+    }
+
+    public final RealmSidebarPanel reloadRealmTree() {
+        reloadRealmTree(reloadRealmParentMap(), 0L, menu);
+        return this;
+    }
+
+    private MarkupContainer reloadRealmTree(
+            final Map<Long, List<RealmTO>> parentMap, final Long key, final MarkupContainer container) {
+        final RepeatingView listItems = new RepeatingView("list");
+        listItems.setOutputMarkupId(true);
+        container.addOrReplace(listItems);
+
+        for (final RealmTO realm : parentMap.get(key)) {
+            final Fragment fragment;
+
+            final AjaxLink<Void> link = new AjaxLink<Void>("link") {
+
+                private static final long serialVersionUID = -7978723352517770644L;
+
+                @Override
+                public void onClick(final AjaxRequestTarget target) {
+                    RealmSidebarPanel.this.setCurrentRealm(realm);
+                    send(pageRef.getPage(), Broadcast.EXACT, new ControlSidebarClick<>(realm, target));
+                }
+
+                @Override
+                protected void onComponentTag(final ComponentTag tag) {
+                    super.onComponentTag(tag);
+                    tag.put("href", "#");
+                }
+            };
+
+            link.setMarkupId("item-" + realm.getKey());
+            link.addOrReplace(new Label("name", new PropertyModel<String>(realm, "name")));
+
+            if (parentMap.containsKey(realm.getKey()) && !parentMap.get(realm.getKey()).isEmpty()) {
+                fragment = new Fragment(String.valueOf(realm.getKey()), "withChildren", RealmSidebarPanel.this);
+
+                final Link<Void> angle = new Link<Void>("angle") {
+
+                    private static final long serialVersionUID = -7978723352517770644L;
+
+                    @Override
+                    public void onClick() {
+                    }
+
+                    @Override
+                    protected void onComponentTag(final ComponentTag tag) {
+                        super.onComponentTag(tag);
+                        tag.put("href", "#");
+                    }
+                };
+
+                angle.setMarkupId("angle-" + realm.getKey());
+                fragment.addOrReplace(angle);
+
+                reloadRealmTree(parentMap, realm.getKey(), fragment);
+            } else {
+                fragment = new Fragment(String.valueOf(realm.getKey()), "withoutChildren", RealmSidebarPanel.this);
+            }
+
+            fragment.addOrReplace(link);
+            fragment.setOutputMarkupId(true);
+            listItems.addOrReplace(fragment);
+        }
+
+        return container;
+    }
+
+    private Map<Long, List<RealmTO>> reloadRealmParentMap() {
+        final List<RealmTO> realms = realmRestClient.list();
+        Collections.sort(realms, new RealmNameComparator());
+        return reloadRealmParentMap(realms);
+    }
+
+    private Map<Long, List<RealmTO>> reloadRealmParentMap(final List<RealmTO> realms) {
+        final Map<Long, List<RealmTO>> res = new HashMap<>();
+        res.put(0L, new ArrayList<RealmTO>());
+
+        final Map<Long, List<RealmTO>> cache = new HashMap<>();
+
+        for (RealmTO realm : realms) {
+            if (res.containsKey(realm.getParent())) {
+                res.get(realm.getParent()).add(realm);
+
+                final List<RealmTO> children = new ArrayList<>();
+                res.put(realm.getKey(), children);
+
+                if (cache.containsKey(realm.getKey())) {
+                    children.addAll(cache.get(realm.getKey()));
+                    cache.remove(realm.getKey());
+                }
+            } else if (cache.containsKey(realm.getParent())) {
+                cache.get(realm.getParent()).add(realm);
+            } else {
+                final List<RealmTO> children = new ArrayList<>();
+                children.add(realm);
+                cache.put(realm.getParent(), children);
+            }
+        }
+
+        return res;
+    }
+
+    private static class RealmNameComparator implements Comparator<RealmTO>, Serializable {
+
+        private static final long serialVersionUID = 7085057398406518811L;
+
+        @Override
+        public int compare(final RealmTO r1, final RealmTO r2) {
+            if (r1 == null && r2 == null) {
+                return 0;
+            } else if (r1 != null && r2 != null) {
+                return r1.getName().compareTo(r2.getName());
+            } else if (r1 == null && r2 != null) {
+                return -1;
+            } else {
+                return 1;
+            }
+        }
+    }
+
+    private void setCurrentRealm(final RealmTO realmTO) {
+        this.currentRealm = realmTO;
+    }
+
+    public RealmTO getCurrentRealm() {
+        return this.currentRealm;
+    }
+
+    public static class ControlSidebarClick<T> {
+
+        private final AjaxRequestTarget target;
+
+        private final T obj;
+
+        public ControlSidebarClick(final T obj, final AjaxRequestTarget target) {
+            this.obj = obj;
+            this.target = target;
+        }
+
+        public T getObj() {
+            return obj;
+        }
+
+        public AjaxRequestTarget getTarget() {
+            return target;
+        }
+    }
+
+    @Override
+    public void renderHead(final IHeaderResponse response) {
+        if (reload) {
+            response.render(OnLoadHeaderItem.forScript("$.AdminLTE.tree('.syncopeSidebar');"));
+        } else {
+            reload = true;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/syncope/blob/10299f2c/client/console/src/main/java/org/apache/syncope/client/console/themes/AdminLTE.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/themes/AdminLTE.java b/client/console/src/main/java/org/apache/syncope/client/console/themes/AdminLTE.java
index e78efd5..1381c00 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/themes/AdminLTE.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/themes/AdminLTE.java
@@ -42,7 +42,7 @@ public class AdminLTE extends Theme {
     public List<HeaderItem> getDependencies() {
         final List<HeaderItem> references = new ArrayList<>();
         references.add(JavaScriptHeaderItem.forReference(
-                new JQueryPluginResourceReference(AdminLTE.class, "js/AdminLTE-app.min.js")));
+                new JQueryPluginResourceReference(AdminLTE.class, "js/AdminLTE-app.min.js"), "adminltejs"));
 
         // Adds WebjarsJavaScriptResourceReference about JQuery
         references.add(JavaScriptHeaderItem.forReference(JQueryUIAllJavaScriptReference.instance()));

http://git-wip-us.apache.org/repos/asf/syncope/blob/10299f2c/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/bootstrap/dialog/BaseModal.java
----------------------------------------------------------------------
diff --git a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/bootstrap/dialog/BaseModal.java b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/bootstrap/dialog/BaseModal.java
index 234f728..e67daac 100644
--- a/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/bootstrap/dialog/BaseModal.java
+++ b/client/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/bootstrap/dialog/BaseModal.java
@@ -78,7 +78,7 @@ public class BaseModal<T extends Serializable> extends Modal<T> {
         form = new Form<T>(FORM);
         add(form);
 
-        content = new AbstractModalPanel(CONTENT_ID, this) {
+        content = new AbstractModalPanel(this) {
 
             private static final long serialVersionUID = 1L;
 

http://git-wip-us.apache.org/repos/asf/syncope/blob/10299f2c/client/console/src/main/resources/org/apache/syncope/client/console/pages/Realms.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/pages/Realms.html b/client/console/src/main/resources/org/apache/syncope/client/console/pages/Realms.html
index bf54dac..890db34 100644
--- a/client/console/src/main/resources/org/apache/syncope/client/console/pages/Realms.html
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/pages/Realms.html
@@ -55,14 +55,7 @@ under the License.
         <div wicket:id="modal"></div>
       </div>
 
-      <aside class="control-sidebar control-sidebar-dark control-sidebar-open block-sidebar">
-        <section class="sidebar">
-          <ul class="sidebar-menu" wicket:id="menu">
-            <wicket:container wicket:id="list"></wicket:container>
-          </ul>
-        </section>
-      </aside>
-      <div class="control-sidebar-bg inner-control-sidebar"></div>
+      <span wicket:id="realmSidebarPanel">[Realm Sidebar Panel]</span>
     </div>
 
     <wicket:fragment wicket:id="withChildren">

http://git-wip-us.apache.org/repos/asf/syncope/blob/10299f2c/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmSidebarPanel.html
----------------------------------------------------------------------
diff --git a/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmSidebarPanel.html b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmSidebarPanel.html
new file mode 100644
index 0000000..71ff092
--- /dev/null
+++ b/client/console/src/main/resources/org/apache/syncope/client/console/panels/RealmSidebarPanel.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://xmlns.jcp.org/jsf/composite">
+  <wicket:panel>
+    <aside id="aside" name="aside" class="control-sidebar control-sidebar-dark control-sidebar-open block-sidebar">
+      <section id="section" name="section" class="sidebar syncopeSidebar">
+        <ul id="tree" name="tree" class="sidebar-menu" wicket:id="menu">
+          <wicket:container wicket:id="list"></wicket:container>
+        </ul>
+      </section>
+    </aside>
+    <div  id="control" name="control" class="control-sidebar-bg inner-control-sidebar"></div>
+
+    <wicket:fragment wicket:id="withChildren">
+      <li id="treeview" name="treeview" class="treeview">
+        <a href="#" wicket:id="link"><i class="fa fa-folder-o">
+          </i><span wicket:id="name">[ITEM NAME]</span>
+        </a>
+        <a href="#" class="angle" wicket:id="angle">
+          <i class="fa fa-angle-left pull-right"></i>
+        </a>
+        <ul id="subtree" name="subtree" class="treeview-menu">
+          <wicket:container wicket:id="list"></wicket:container>
+        </ul>
+      </li>
+    </wicket:fragment>
+
+    <wicket:fragment wicket:id="withoutChildren">
+      <li>
+        <a name="label" href="#" wicket:id="link">
+          <i class="fa fa-leaf"></i><span wicket:id="name">[ITEM NAME]</span>
+        </a>
+      </li>
+    </wicket:fragment>
+  </wicket:panel>
+</html>
\ No newline at end of file