Change look & feel of base pages to use twitter bootstrap.
Fix tests, remove unecessary files.
Refactored header of page.
Clean up of stylesheets / resources.
Add bootstrap based feedback panel (many thanks to topriddy from #wicket)

git-svn-id: https://svn.apache.org/repos/asf/karaf/webconsole/trunk@1242780 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/BasePage.java b/core/src/main/java/org/apache/karaf/webconsole/core/BasePage.java
index ebf828c..8945495 100644
--- a/core/src/main/java/org/apache/karaf/webconsole/core/BasePage.java
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/BasePage.java
@@ -21,13 +21,11 @@
 import java.util.Locale;
 
 import org.apache.karaf.webconsole.core.brand.BrandProvider;
-import org.apache.karaf.webconsole.core.dashboard.DashboardPage;
-import org.apache.karaf.webconsole.core.internal.LanguagePanel;
+import org.apache.karaf.webconsole.core.navigation.markup.LanguageTopPanel;
 import org.apache.wicket.behavior.IBehavior;
 import org.apache.wicket.markup.html.WebPage;
 import org.apache.wicket.markup.html.basic.Label;
-import org.apache.wicket.markup.html.link.BookmarkablePageLink;
-import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.util.ListModel;
 import org.ops4j.pax.wicket.api.PaxWicketBean;
@@ -47,19 +45,19 @@
     private IModel<List<Locale>> supportedLocales = new ListModel<Locale>(Arrays.asList(Locale.FRENCH, Locale.ENGLISH));
 
     public BasePage() {
-        Link<DashboardPage> homeLink = new BookmarkablePageLink<DashboardPage>("homeLink", DashboardPage.class);
-        homeLink.add(brandProvider.getHeaderImage("logo"));
-        add(homeLink);
+        add(createTopPanel("topPanel"));
 
         add(new Label("footer", "Apache Karaf Console"));
 
-        add(new LanguagePanel("languagePanel", supportedLocales));
-
         for (IBehavior behavior : brandProvider.getBehaviors()) {
             add(behavior);
         }
     }
 
+    protected Panel createTopPanel(String id) {
+        return new LanguageTopPanel(id, getSupportedLocales());
+    }
+
     @Override
     protected void onConfigure() {
         brandProvider.modify(this);
@@ -67,4 +65,7 @@
         super.onConfigure();
     }
 
+    protected IModel<List<Locale>> getSupportedLocales() {
+        return supportedLocales;
+    }
 }
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/brand/DefaultBrandProvider.java b/core/src/main/java/org/apache/karaf/webconsole/core/brand/DefaultBrandProvider.java
index 5cd67bc..653a4f6 100644
--- a/core/src/main/java/org/apache/karaf/webconsole/core/brand/DefaultBrandProvider.java
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/brand/DefaultBrandProvider.java
@@ -54,7 +54,6 @@
 
     public void modify(Page page) {
         page.add(getHeaderContribution(BasePage.class, "style.css"));
-        page.add(getHeaderContribution(BasePage.class, "grid.css"));
     }
 
 }
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/internal/WebConsoleApplication.java b/core/src/main/java/org/apache/karaf/webconsole/core/internal/WebConsoleApplication.java
index a5a53cb..2ee9f51 100644
--- a/core/src/main/java/org/apache/karaf/webconsole/core/internal/WebConsoleApplication.java
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/internal/WebConsoleApplication.java
@@ -48,6 +48,7 @@
         getApplicationSettings().setPageExpiredErrorPage(PageExpiredErrorPage.class);
 
         getSecuritySettings().setAuthorizationStrategy(new RoleAuthorizationStrategy(new HierarchicalRoleCheckingStrategy()));
+        getMarkupSettings().setStripWicketTags(true);
     }
 
     /**
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/AnonymousTopPanel.java b/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/AnonymousTopPanel.java
new file mode 100644
index 0000000..6190cd2
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/AnonymousTopPanel.java
@@ -0,0 +1,30 @@
+package org.apache.karaf.webconsole.core.navigation.markup;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.karaf.webconsole.core.brand.BrandProvider;
+import org.apache.karaf.webconsole.core.dashboard.DashboardPage;
+import org.apache.wicket.markup.html.link.BookmarkablePageLink;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.IModel;
+import org.ops4j.pax.wicket.api.PaxWicketBean;
+
+public class AnonymousTopPanel extends Panel {
+
+    private static final long serialVersionUID = 1L;
+
+    @PaxWicketBean(name = "brandProvider")
+    private BrandProvider brandProvider;
+
+    public AnonymousTopPanel(String id, IModel<List<Locale>> locales) {
+        super(id, locales);
+
+        Link<DashboardPage> homeLink = new BookmarkablePageLink<DashboardPage>("homeLink", DashboardPage.class);
+        //homeLink.add(brandProvider.getHeaderImage("logo"));
+        add(homeLink);
+        add(brandProvider.getHeaderImage("logo"));
+    }
+
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/LanguageChangeLink.java b/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/LanguageChangeLink.java
new file mode 100644
index 0000000..9d327c5
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/LanguageChangeLink.java
@@ -0,0 +1,41 @@
+/*
+ * 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.karaf.webconsole.core.navigation.markup;
+
+import java.util.Locale;
+
+import org.apache.wicket.markup.html.link.Link;
+
+/**
+ * Utility link to change session locale.
+ */
+public class LanguageChangeLink extends Link<Void> {
+
+    private static final long serialVersionUID = 1L;
+
+    private final Locale locale;
+
+    public LanguageChangeLink(String id, Locale locale) {
+        super(id);
+        this.locale = locale;
+    }
+
+    @Override
+    public void onClick() {
+        getSession().setLocale(locale);
+    }
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/LanguageTopPanel.java b/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/LanguageTopPanel.java
new file mode 100644
index 0000000..d7cc92d
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/LanguageTopPanel.java
@@ -0,0 +1,53 @@
+package org.apache.karaf.webconsole.core.navigation.markup;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.karaf.webconsole.core.BasePage;
+import org.apache.wicket.ResourceReference;
+import org.apache.wicket.behavior.SimpleAttributeModifier;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.image.Image;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.model.IModel;
+
+public class LanguageTopPanel extends AnonymousTopPanel {
+
+    private static final long serialVersionUID = 1L;
+
+    public LanguageTopPanel(String id, IModel<List<Locale>> locales) {
+        super(id, locales);
+
+        add(new ListView<Locale>("languages", locales) {
+
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void populateItem(final ListItem<Locale> item) {
+                final Locale model = item.getModelObject();
+
+                Link<Void> link = new LanguageChangeLink("languageLink", model);
+                link.add(getImage("flag", model));
+                link.add(getLabel("label", model));
+                item.add(link);
+            }
+        });
+    }
+
+    protected Label getLabel(String id, Locale locale) {
+        return new Label(id, locale.getDisplayName());
+    }
+
+    protected Image getImage(String id, Locale locale) {
+        String localeName = locale.getDisplayName(Locale.ENGLISH);
+        ResourceReference resource = new ResourceReference(BasePage.class, "images/" + localeName.toLowerCase() + "-flag.png");
+        Image image = new Image(id, resource);
+        image.add(new SimpleAttributeModifier("width", "20"));
+        image.add(new SimpleAttributeModifier("height", "14"));
+        image.add(new SimpleAttributeModifier("alt", localeName));
+        image.add(new SimpleAttributeModifier("title", localeName));
+        return image;
+    }
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/LogoutLink.java b/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/LogoutLink.java
new file mode 100644
index 0000000..bc8e9bb
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/LogoutLink.java
@@ -0,0 +1,41 @@
+/*
+ * 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.karaf.webconsole.core.navigation.markup;
+
+import org.apache.karaf.webconsole.core.page.LoginPage;
+import org.apache.karaf.webconsole.core.security.WebConsoleSession;
+import org.apache.wicket.markup.html.link.Link;
+
+/**
+ * Utility link to destroy session.
+ */
+public class LogoutLink extends Link<Void> {
+
+    public LogoutLink(String id) {
+        super(id);
+    }
+
+    private static final long serialVersionUID = 1L;
+
+    @Override
+    public void onClick() {
+        WebConsoleSession.get().invalidateNow();
+        getRequestCycle().setRedirect(true);
+        setResponsePage(LoginPage.class);
+    }
+
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/NavigationPanel.java b/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/NavigationPanel.java
deleted file mode 100644
index d6f5038..0000000
--- a/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/NavigationPanel.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.karaf.webconsole.core.navigation.markup;
-
-import java.util.List;
-
-import org.apache.karaf.webconsole.core.navigation.ConsoleTabProvider;
-import org.apache.wicket.Page;
-import org.apache.wicket.markup.html.link.Link;
-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;
-
-/**
- * Component responsible for rendering top navigation in webconsole.
- */
-public class NavigationPanel extends Panel {
-
-    private static final long serialVersionUID = 1L;
-
-    public NavigationPanel(String id, IModel<List<ConsoleTabProvider>> model) {
-        super(id);
-
-        add(new ListView<ConsoleTabProvider>("tabs", model) {
-
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            protected void populateItem(ListItem<ConsoleTabProvider> item) {
-                ConsoleTabProvider tab = item.getModelObject();
-
-                item.add(tab.getModuleLink("moduleLink", "moduleLabel"));
-
-                item.add(new ListView<Link<Page>>("moduleLinks", tab.getItems("link", "label")) {
-
-                    private static final long serialVersionUID = 1L;
-
-                    @Override
-                    protected void populateItem(ListItem<Link<Page>> item) {
-                        item.add(item.getModelObject());
-                    }
-                });
-            }
-        });
-
-    }
-
-}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/NavigationTopPanel.java b/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/NavigationTopPanel.java
new file mode 100644
index 0000000..fee4b63
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/navigation/markup/NavigationTopPanel.java
@@ -0,0 +1,126 @@
+/*
+ * 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.karaf.webconsole.core.navigation.markup;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.karaf.webconsole.core.navigation.ConsoleTabProvider;
+import org.apache.karaf.webconsole.core.page.AvatarImage;
+import org.apache.karaf.webconsole.core.preferences.PreferencesPage;
+import org.apache.karaf.webconsole.core.security.SecuredPageLink;
+import org.apache.karaf.webconsole.core.security.WebConsoleSession;
+import org.apache.karaf.webconsole.core.util.LinkUtils;
+import org.apache.wicket.Component;
+import org.apache.wicket.Page;
+import org.apache.wicket.behavior.AttributeAppender;
+import org.apache.wicket.behavior.SimpleAttributeModifier;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+import org.apache.wicket.markup.repeater.RepeatingView;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
+import org.apache.wicket.model.StringResourceModel;
+import org.ops4j.pax.wicket.api.PaxWicketBean;
+import org.osgi.service.prefs.PreferencesService;
+
+/**
+ * Component responsible for rendering top navigation in webconsole.
+ */
+public class NavigationTopPanel extends LanguageTopPanel {
+
+    private static final long serialVersionUID = 1L;
+
+    @PaxWicketBean(name = "preferencesService")
+    private PreferencesService preferences;
+
+    public NavigationTopPanel(String id, IModel<List<Locale>> locales, IModel<List<ConsoleTabProvider>> model) {
+        super(id, locales);
+
+        add(createTabList(model));
+
+        String username = WebConsoleSession.get().getUsername();
+        add(new AvatarImage("avatar", preferences.getUserPreferences(username)));
+
+        add(new Label("username", username));
+        add(new SecuredPageLink<PreferencesPage>("preferencesLink", PreferencesPage.class));
+
+        Link<Void> aLink = new LogoutLink("logoutLink");
+        aLink.add(new Label("label", new StringResourceModel("logout.link", this.getDefaultModel())));
+        add(aLink);
+
+    }
+
+    private Component createTabList(IModel<List<ConsoleTabProvider>> model) {
+        return new ListView<ConsoleTabProvider>("tabs", model) {
+
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void populateItem(ListItem<ConsoleTabProvider> item) {
+                ConsoleTabProvider tab = item.getModelObject();
+
+                List<Link<Page>> items = tab.getItems("link", "label");
+                if (!items.isEmpty()) {
+                    populateTabItem(item, tab);
+                    populateTabChildren(item, items);
+                } else {
+                    populateSingleTabItem(item, tab);
+                }
+            }
+        };
+    }
+
+    protected void populateTabItem(ListItem<ConsoleTabProvider> item, ConsoleTabProvider provider) {
+        Link<Page> link = provider.getModuleLink("moduleLink", "moduleLabel");
+        item.add(link);
+
+        if (LinkUtils.isActiveTrail(link, this)) {
+            item.add(new AttributeAppender("class", Model.of("active"), " "));
+        }
+    }
+
+    protected void populateSingleTabItem(ListItem<ConsoleTabProvider> item, ConsoleTabProvider provider) {
+        Link<Page> moduleLink = provider.getModuleLink("moduleLink", "moduleLabel");
+        
+        // remove dropdown stuff
+        item.add(new SimpleAttributeModifier("class", ""));
+        moduleLink.add(new SimpleAttributeModifier("data-toggle", ""));
+        moduleLink.add(new SimpleAttributeModifier("class", ""));
+
+        if (LinkUtils.isActiveTrail(moduleLink, this)) {
+            item.add(new AttributeAppender("class", Model.of("active"), " "));
+        }
+
+        item.add(moduleLink);
+        item.add(new RepeatingView("moduleLinks"));
+    }
+
+    protected void populateTabChildren(ListItem<ConsoleTabProvider> item, List<Link<Page>> listItems) {
+        item.add(new ListView<Link<Page>>("moduleLinks", listItems) {
+
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            protected void populateItem(ListItem<Link<Page>> item) {
+                item.add(item.getModelObject());
+            }
+        });
+    }
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/page/SecuredPage.java b/core/src/main/java/org/apache/karaf/webconsole/core/page/SecuredPage.java
index 56bf240..248f54d 100644
--- a/core/src/main/java/org/apache/karaf/webconsole/core/page/SecuredPage.java
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/page/SecuredPage.java
@@ -20,17 +20,11 @@
 
 import org.apache.karaf.webconsole.core.BasePage;
 import org.apache.karaf.webconsole.core.navigation.ConsoleTabProvider;
-import org.apache.karaf.webconsole.core.navigation.markup.NavigationPanel;
-import org.apache.karaf.webconsole.core.preferences.PreferencesPage;
-import org.apache.karaf.webconsole.core.security.SecuredPageLink;
-import org.apache.karaf.webconsole.core.security.WebConsoleSession;
+import org.apache.karaf.webconsole.core.navigation.markup.NavigationTopPanel;
 import org.apache.wicket.authorization.strategies.role.annotations.AuthorizeInstantiation;
-import org.apache.wicket.markup.html.basic.Label;
-import org.apache.wicket.markup.html.link.Link;
+import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.LoadableDetachableModel;
-import org.apache.wicket.model.StringResourceModel;
 import org.ops4j.pax.wicket.api.PaxWicketBean;
-import org.osgi.service.prefs.PreferencesService;
 
 /**
  * Page which requires admin role, in other words authorized user.
@@ -41,39 +35,15 @@
     @PaxWicketBean(name = "tabs")
     private List<ConsoleTabProvider> tabs;
 
-    @PaxWicketBean(name = "preferencesService")
-    private PreferencesService preferences;
-
-    public SecuredPage() {
-        add(new NavigationPanel("navigationPanel", new LoadableDetachableModel<List<ConsoleTabProvider>>() {
-
+    @Override
+    protected Panel createTopPanel(String id) {
+        return new NavigationTopPanel(id, getSupportedLocales(), new LoadableDetachableModel<List<ConsoleTabProvider>>() {
             private static final long serialVersionUID = 1L;
 
             @Override
             protected List<ConsoleTabProvider> load() {
                 return tabs;
             }
-        }));
-
-        String username = WebConsoleSession.get().getUsername();
-        add(new AvatarImage("avatar", preferences.getUserPreferences(username)));
-
-        add(new Label("username", username));
-        add(new SecuredPageLink<PreferencesPage>("preferencesLink", PreferencesPage.class));
-
-        Link<Void> aLink = new Link<Void>("logoutLink") {
-
-            private static final long serialVersionUID = 1L;
-
-            @Override
-            public void onClick() {
-                WebConsoleSession.get().invalidateNow();
-                getRequestCycle().setRedirect(true);
-                setResponsePage(LoginPage.class);
-            }
-        };
-
-        aLink.add(new Label("logoutTranslatedLink", new StringResourceModel("logout.link", this.getDefaultModel())));
-        add(aLink);
+        });
     }
 }
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/page/SidebarPage.java b/core/src/main/java/org/apache/karaf/webconsole/core/page/SidebarPage.java
index b9f8de4..ac0fc00 100644
--- a/core/src/main/java/org/apache/karaf/webconsole/core/page/SidebarPage.java
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/page/SidebarPage.java
@@ -18,7 +18,7 @@
 
 import org.apache.karaf.webconsole.core.internal.SidebarPanel;
 import org.apache.karaf.webconsole.core.navigation.SidebarProvider;
-import org.apache.wicket.markup.html.panel.FeedbackPanel;
+import org.apache.karaf.webconsole.core.panel.feedback.BootstrapFeedbackPanel;
 import org.apache.wicket.markup.html.panel.Panel;
 
 /**
@@ -30,7 +30,7 @@
     private Panel sidebar;
 
     public SidebarPage() {
-        add(new FeedbackPanel("feedback"));
+        add(new BootstrapFeedbackPanel("feedback"));
     }
 
     protected void setSidebarProvider(SidebarProvider provider) {
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/page/SinglePage.java b/core/src/main/java/org/apache/karaf/webconsole/core/page/SinglePage.java
index ea70233..b23ee4a 100644
--- a/core/src/main/java/org/apache/karaf/webconsole/core/page/SinglePage.java
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/page/SinglePage.java
@@ -16,7 +16,7 @@
  */
 package org.apache.karaf.webconsole.core.page;
 
-import org.apache.wicket.markup.html.panel.FeedbackPanel;
+import org.apache.karaf.webconsole.core.panel.feedback.BootstrapFeedbackPanel;
 
 /**
  * Page which body uses all available space - all screen width.
@@ -24,7 +24,7 @@
 public class SinglePage extends SecuredPage {
 
     public SinglePage() {
-        add(new FeedbackPanel("feedback"));
+        add(new BootstrapFeedbackPanel("feedback"));
     }
 
 }
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/panel/feedback/AlertPanel.java b/core/src/main/java/org/apache/karaf/webconsole/core/panel/feedback/AlertPanel.java
new file mode 100644
index 0000000..febe7da
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/panel/feedback/AlertPanel.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.webconsole.core.panel.feedback;
+
+import org.apache.wicket.behavior.AttributeAppender;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.model.Model;
+
+/**
+ * Bootstrap based alert panel.
+ */
+public final class AlertPanel extends Panel {
+
+    private static final long serialVersionUID = 1L;
+
+    private WebMarkupContainer wrapper;
+
+    public AlertPanel(String id, String message, AlertType type) {
+        super(id);
+
+        // make sure that wrapper is added before type of alert is set
+        add(wrapper = new WebMarkupContainer("wrapper"));
+
+        setType(type); // setter will modify css class
+
+        wrapper.add(new Label("message", message));
+    }
+
+    public void setType(AlertType type) {
+        wrapper.add(new AttributeAppender("class", Model.of(type.getCssClass()), " "));
+    }
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/panel/feedback/AlertType.java b/core/src/main/java/org/apache/karaf/webconsole/core/panel/feedback/AlertType.java
new file mode 100644
index 0000000..57f14ed
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/panel/feedback/AlertType.java
@@ -0,0 +1,54 @@
+/*
+ * 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.karaf.webconsole.core.panel.feedback;
+
+/**
+ * Enumeration which contains style names for alert panel. It points directly to
+ * bootstrap css classes.
+ */
+public enum AlertType {
+
+    /**
+     * By default alert is orange, we don't need any additional classes.
+     */
+    WARNING(""),
+
+    /**
+     * Red background.
+     */
+    ERROR("alert-error"),
+
+    /**
+     * Green background.
+     */
+    SUCCESS("alert-success"),
+
+    /**
+     * Blue background
+     */
+    INFO("alert-info");
+
+    private String cssClass;
+
+    AlertType(String css) {
+        this.cssClass = css;
+    }
+
+    public String getCssClass() {
+        return cssClass;
+    }
+}
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/panel/feedback/BootstrapFeedbackPanel.java b/core/src/main/java/org/apache/karaf/webconsole/core/panel/feedback/BootstrapFeedbackPanel.java
new file mode 100644
index 0000000..da53181
--- /dev/null
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/panel/feedback/BootstrapFeedbackPanel.java
@@ -0,0 +1,56 @@
+/*
+ * 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.karaf.webconsole.core.panel.feedback;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.feedback.FeedbackMessage;
+import org.apache.wicket.markup.html.panel.FeedbackPanel;
+
+/**
+ * Feedback panel which produces bootstrap-like message entries.
+ */
+public class BootstrapFeedbackPanel extends FeedbackPanel {
+
+    private static final long serialVersionUID = 1L;
+
+    public BootstrapFeedbackPanel(String id) {
+        super(id);
+    }
+
+    @Override
+    protected Component newMessageDisplayComponent(String id, FeedbackMessage message) {
+        // by default we'll assign alert-error class
+        AlertPanel alertPanel = new AlertPanel(id, message.getMessage().toString(), AlertType.ERROR);
+
+        // depends on message level change the css class
+        switch (message.getLevel()) {
+            case FeedbackMessage.INFO:
+                alertPanel.setType(AlertType.INFO);
+                break;
+            case FeedbackMessage.WARNING:
+                alertPanel.setType(AlertType.WARNING);
+                break;
+            // Not supported in Wicket 1.4
+//            case FeedbackMessage.SUCCESS:
+//                alertPanel.setType(AlertType.SUCCESS);
+//                break;
+        }
+
+        return alertPanel;
+    }
+
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/preferences/util/JdkPreferencesService.java b/core/src/main/java/org/apache/karaf/webconsole/core/preferences/util/JdkPreferencesService.java
index da35192..4c9f3c3 100644
--- a/core/src/main/java/org/apache/karaf/webconsole/core/preferences/util/JdkPreferencesService.java
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/preferences/util/JdkPreferencesService.java
@@ -16,13 +16,17 @@
  */
 package org.apache.karaf.webconsole.core.preferences.util;
 
+import java.io.Serializable;
+
 import org.osgi.service.prefs.Preferences;
 import org.osgi.service.prefs.PreferencesService;
 
 /**
  * Preferences service created on top of standard JDK implementation.
  */
-public class JdkPreferencesService implements PreferencesService {
+public class JdkPreferencesService implements PreferencesService, Serializable /* for tests*/ {
+
+    private static final long serialVersionUID = 1L;
 
     public Preferences getSystemPreferences() {
         return new JdkPreferences(java.util.prefs.Preferences.systemRoot());
diff --git a/core/src/main/java/org/apache/karaf/webconsole/core/util/LinkUtils.java b/core/src/main/java/org/apache/karaf/webconsole/core/util/LinkUtils.java
index 8753f42..e3a3b9c 100644
--- a/core/src/main/java/org/apache/karaf/webconsole/core/util/LinkUtils.java
+++ b/core/src/main/java/org/apache/karaf/webconsole/core/util/LinkUtils.java
@@ -16,7 +16,9 @@
  */
 package org.apache.karaf.webconsole.core.util;
 
+import org.apache.wicket.Component;
 import org.apache.wicket.Page;
+import org.apache.wicket.RequestCycle;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.link.BookmarkablePageLink;
 import org.apache.wicket.markup.html.link.Link;
@@ -44,4 +46,22 @@
         return link;
     }
 
+    /**
+     * Checks if given link is in active trail. It detects a path only from
+     * bookmarkable links.
+     * 
+     * @param link Link.
+     * @param component Component which should be asked for rendering url.
+     * @return True if link path is contained in request path.
+     */
+    public static boolean isActiveTrail(Link<?> link, Component component) {
+        if (link instanceof BookmarkablePageLink) {
+            Class<? extends Page> pageClass = ((BookmarkablePageLink<?>) link).getPageClass();
+
+            String requestPath = RequestCycle.get().getRequest().getPath();
+            String linkPath = (component.urlFor(pageClass, null) + "").replace("../", "");
+            return requestPath.contains(linkPath);
+        }
+        return false;
+    }
 }
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/BasePage.html b/core/src/main/resources/org/apache/karaf/webconsole/core/BasePage.html
index 39e3e56..0b5d6fc 100644
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/BasePage.html
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/BasePage.html
@@ -23,22 +23,13 @@
 </head>
 
 <body>
-    <div class="container container_12">
-        <div class="grid_3">
-            <a wicket:id="homeLink">
-                <img wicket:id="logo" />
-            </a>
-        </div>
-        <div class="grid_9">
-            <h3>Administration console</h3>
+    <div class="container-fluid">
 
-            <div wicket:id="languagePanel" id="languages">Languages go here</div>
-        </div>
-        <div class="clear"></div>
+        <div wicket:id="topPanel"></div>
 
         <wicket:child />
 
-        <div class="grid_12">
+        <div class="row-fluid">
             <div wicket:id="footer">Footer</div>
         </div>
     </div>
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/NavigationPanel.properties b/core/src/main/resources/org/apache/karaf/webconsole/core/NavigationPanel.properties
deleted file mode 100644
index 1c85219..0000000
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/NavigationPanel.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-# Features Console properties
-features.list = Features list
-features.repositories = Features repositories
-
-osgi = OSGi
-dashboard = Dashboard
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/NavigationPanel_de.properties b/core/src/main/resources/org/apache/karaf/webconsole/core/NavigationPanel_de.properties
deleted file mode 100644
index 1c8c5da..0000000
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/NavigationPanel_de.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-# Features Console properties
-features.list = Feature Liste
-features.repositories = Feature Repository
-
-osgi = OSGi
-dashboard = Dashboard
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/NavigationPanel_fr.properties b/core/src/main/resources/org/apache/karaf/webconsole/core/NavigationPanel_fr.properties
deleted file mode 100644
index 54d8495..0000000
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/NavigationPanel_fr.properties
+++ /dev/null
@@ -1,6 +0,0 @@
-# Features Console properties
-features.list = Liste de features
-features.repositories = R\u00E9pertoires de features
-
-osgi = OSGi
-dashboard = Dashboard
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/grid.css b/core/src/main/resources/org/apache/karaf/webconsole/core/grid.css
deleted file mode 100644
index 62f81c6..0000000
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/grid.css
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
-    Variable Grid System (Fluid Version).
-    Learn more ~ http://www.spry-soft.com/grids/
-    Based on 960 Grid System - http://960.gs/ & 960 Fluid - http://www.designinfluences.com/
-
-    Licensed under GPL and MIT.
-*/
-
-
-/* Containers
-----------------------------------------------------------------------------------------------------*/
-.container_12 {
-    width: 92%;
-    margin-left: 4%;
-    margin-right: 4%;
-}
-
-/* Grid >> Global
-----------------------------------------------------------------------------------------------------*/
-
-.grid_1,
-.grid_2,
-.grid_3,
-.grid_4,
-.grid_5,
-.grid_6,
-.grid_7,
-.grid_8,
-.grid_9,
-.grid_10,
-.grid_11,
-.grid_12 {
-    display:inline;
-    float: left;
-    position: relative;
-    margin-left: 1%;
-    margin-right: 1%;
-}
-
-/* Grid >> Children (Alpha ~ First, Omega ~ Last)
-----------------------------------------------------------------------------------------------------*/
-
-.alpha {
-    margin-left: 0;
-}
-
-.omega {
-    margin-right: 0;
-}
-
-/* Grid >> 12 Columns
-----------------------------------------------------------------------------------------------------*/
-
-
-.container_12 .grid_1 {
-    width:6.333%;
-}
-
-.container_12 .grid_2 {
-    width:14.667%;
-}
-
-.container_12 .grid_3 {
-    width:23.0%;
-}
-
-.container_12 .grid_4 {
-    width:31.333%;
-}
-
-.container_12 .grid_5 {
-    width:39.667%;
-}
-
-.container_12 .grid_6 {
-    width:48.0%;
-}
-
-.container_12 .grid_7 {
-    width:56.333%;
-}
-
-.container_12 .grid_8 {
-    width:64.667%;
-}
-
-.container_12 .grid_9 {
-    width:73.0%;
-}
-
-.container_12 .grid_10 {
-    width:81.333%;
-}
-
-.container_12 .grid_11 {
-    width:89.667%;
-}
-
-.container_12 .grid_12 {
-    width:98.0%;
-}
-
-
-
-/* Prefix Extra Space >> 12 Columns
-----------------------------------------------------------------------------------------------------*/
-
-
-.container_12 .prefix_1 {
-    padding-left:8.333%;
-}
-
-.container_12 .prefix_2 {
-    padding-left:16.667%;
-}
-
-.container_12 .prefix_3 {
-    padding-left:25.0%;
-}
-
-.container_12 .prefix_4 {
-    padding-left:33.333%;
-}
-
-.container_12 .prefix_5 {
-    padding-left:41.667%;
-}
-
-.container_12 .prefix_6 {
-    padding-left:50.0%;
-}
-
-.container_12 .prefix_7 {
-    padding-left:58.333%;
-}
-
-.container_12 .prefix_8 {
-    padding-left:66.667%;
-}
-
-.container_12 .prefix_9 {
-    padding-left:75.0%;
-}
-
-.container_12 .prefix_10 {
-    padding-left:83.333%;
-}
-
-.container_12 .prefix_11 {
-    padding-left:91.667%;
-}
-
-
-
-/* Suffix Extra Space >> 12 Columns
-----------------------------------------------------------------------------------------------------*/
-
-
-.container_12 .suffix_1 {
-    padding-right:8.333%;
-}
-
-.container_12 .suffix_2 {
-    padding-right:16.667%;
-}
-
-.container_12 .suffix_3 {
-    padding-right:25.0%;
-}
-
-.container_12 .suffix_4 {
-    padding-right:33.333%;
-}
-
-.container_12 .suffix_5 {
-    padding-right:41.667%;
-}
-
-.container_12 .suffix_6 {
-    padding-right:50.0%;
-}
-
-.container_12 .suffix_7 {
-    padding-right:58.333%;
-}
-
-.container_12 .suffix_8 {
-    padding-right:66.667%;
-}
-
-.container_12 .suffix_9 {
-    padding-right:75.0%;
-}
-
-.container_12 .suffix_10 {
-    padding-right:83.333%;
-}
-
-.container_12 .suffix_11 {
-    padding-right:91.667%;
-}
-
-
-
-/* Push Space >> 12 Columns
-----------------------------------------------------------------------------------------------------*/
-
-
-.container_12 .push_1 {
-    left:8.333%;
-}
-
-.container_12 .push_2 {
-    left:16.667%;
-}
-
-.container_12 .push_3 {
-    left:25.0%;
-}
-
-.container_12 .push_4 {
-    left:33.333%;
-}
-
-.container_12 .push_5 {
-    left:41.667%;
-}
-
-.container_12 .push_6 {
-    left:50.0%;
-}
-
-.container_12 .push_7 {
-    left:58.333%;
-}
-
-.container_12 .push_8 {
-    left:66.667%;
-}
-
-.container_12 .push_9 {
-    left:75.0%;
-}
-
-.container_12 .push_10 {
-    left:83.333%;
-}
-
-.container_12 .push_11 {
-    left:91.667%;
-}
-
-
-
-/* Pull Space >> 12 Columns
-----------------------------------------------------------------------------------------------------*/
-
-
-.container_12 .pull_1 {
-    left:-8.333%;
-}
-
-.container_12 .pull_2 {
-    left:-16.667%;
-}
-
-.container_12 .pull_3 {
-    left:-25.0%;
-}
-
-.container_12 .pull_4 {
-    left:-33.333%;
-}
-
-.container_12 .pull_5 {
-    left:-41.667%;
-}
-
-.container_12 .pull_6 {
-    left:-50.0%;
-}
-
-.container_12 .pull_7 {
-    left:-58.333%;
-}
-
-.container_12 .pull_8 {
-    left:-66.667%;
-}
-
-.container_12 .pull_9 {
-    left:-75.0%;
-}
-
-.container_12 .pull_10 {
-    left:-83.333%;
-}
-
-.container_12 .pull_11 {
-    left:-91.667%;
-}
-
-
-
-
-/* Clear Floated Elements
-----------------------------------------------------------------------------------------------------*/
-
-/* http://sonspring.com/journal/clearing-floats */
-
-.clear {
-    clear: both;
-    display: block;
-    overflow: hidden;
-    visibility: hidden;
-    width: 0;
-    height: 0;
-}
-
-/* http://perishablepress.com/press/2008/02/05/lessons-learned-concerning-the-clearfix-css-hack */
-
-.clearfix:after {
-    clear: both;
-    content: ' ';
-    display: block;
-    font-size: 0;
-    line-height: 0;
-    visibility: hidden;
-    width: 0;
-    height: 0;
-}
-
-.clearfix {
-    display: inline-block;
-}
-
-* html .clearfix {
-    height: 1%;
-}
-
-.clearfix {
-    display: block;
-}
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/navigation/markup/AnonymousTopPanel.html b/core/src/main/resources/org/apache/karaf/webconsole/core/navigation/markup/AnonymousTopPanel.html
new file mode 100644
index 0000000..e349429
--- /dev/null
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/navigation/markup/AnonymousTopPanel.html
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   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.
+-->
+<wicket:panel xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+
+    <div class="navbar navbar-fixed-top">
+        <div class="navbar-inner">
+            <div class="container-fluid">
+
+                <!-- This part is visible for mobile devices -->
+                <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
+                    <span class="icon-bar"></span>
+                    <span class="icon-bar"></span>
+                    <span class="icon-bar"></span>
+                </a>
+
+                <a class="brand" wicket:id="homeLink">
+                    WebConsole
+                </a>
+
+                <wicket:child />
+            </div>
+        </div>
+    </div>
+    <div class="pull-right">
+        <img wicket:id="logo" />
+    </div>
+
+</wicket:panel>
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/navigation/markup/LanguageTopPanel.html b/core/src/main/resources/org/apache/karaf/webconsole/core/navigation/markup/LanguageTopPanel.html
new file mode 100644
index 0000000..045d7d4
--- /dev/null
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/navigation/markup/LanguageTopPanel.html
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   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.
+-->
+<wicket:extend xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+    <div class="nav-collapse"><!-- Inner navigation -->
+        <wicket:child /><!-- make extensions be rendered first -->
+
+        <ul class="nav pull-right">
+            <li class="dropdown">
+                <a class="dropdown-toggle" data-toggle="dropdown">
+                    Language <b class="caret"></b>
+                </a>
+                <ul class="dropdown-menu">
+                    <li wicket:id="languages">
+                        <a wicket:id="languageLink">
+                            <img wicket:id="flag" />
+                            <span wicket:id="label">English</span>
+                        </a>
+                    </li>
+                </ul>
+            </li>
+
+        </ul>
+    </div>
+</wicket:extend>
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/navigation/markup/NavigationTopPanel.html b/core/src/main/resources/org/apache/karaf/webconsole/core/navigation/markup/NavigationTopPanel.html
new file mode 100644
index 0000000..a954ce4
--- /dev/null
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/navigation/markup/NavigationTopPanel.html
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   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.
+-->
+<wicket:extend xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
+
+    <ul class="nav">
+        <li wicket:id="tabs" class="dropdown">
+            <a wicket:id="moduleLink" class="dropdown-toggle" data-toggle="dropdown">
+                <span wicket:id="moduleLabel">Category</span>
+                <b class="caret"></b>
+            </a>
+            <ul class="dropdown-menu">
+                <li wicket:id="moduleLinks">
+                    <a wicket:id="link">
+                        <span wicket:id="label">Label</span>
+                    </a>
+                </li>
+            </ul>
+        </li>
+        <li class="divider-vertical"></li>
+    </ul>
+
+    <wicket:child />
+
+    <ul class="nav pull-right">
+        <li class="dropdown active">
+            <a href="#" data-toggle="dropdown" class="dropdown-toggle">
+                <span wicket:id="username">Admin</span>
+                <b class="caret"></b>
+            </a>
+            <ul class="dropdown-menu">
+                <li>
+                    <img wicket:id="avatar" />
+                    <a wicket:id="preferencesLink">Preferences</a>
+                </li>
+            </ul>
+        </li>
+        <li>
+            <a wicket:id="logoutLink">
+                <span wicket:id="label">Logout</span>
+            </a>
+        </li>
+        
+    </ul>
+
+</wicket:extend>
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/page/LoginPage.html b/core/src/main/resources/org/apache/karaf/webconsole/core/page/LoginPage.html
index a46ca85..ea7f793 100644
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/page/LoginPage.html
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/page/LoginPage.html
@@ -16,11 +16,13 @@
    limitations under the License.
 -->
 <wicket:extend xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
-    <br /><br /><br /><br /><br /><br />
-    <div class="grid_4 prefix_4 suffix_4">
-        <div wicket:id="signIn">
-            Here will be sign in form.
+    <div class="row-fluid" style="margin-top: 150px; margin-bottom: 150px">
+        <span class="span4">&nbsp;</span>
+        <div class="span4">
+            <div wicket:id="signIn">
+                Here will be sign in form.
+            </div>
         </div>
+        <span class="span4">&nbsp;</span>
     </div>
-    <br /><br /><br /><br /><br /><br />
 </wicket:extend>
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/page/SecuredPage.html b/core/src/main/resources/org/apache/karaf/webconsole/core/page/SecuredPage.html
index abbcc4b..1bc4139 100644
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/page/SecuredPage.html
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/page/SecuredPage.html
@@ -16,20 +16,6 @@
    limitations under the License.
 -->
 <wicket:extend xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
-    <div id="userbox" class="grid_2">
-        <img wicket:id="avatar" class="avatar" alt="User avatar" />
-        <span id="details">
-            Welcome <span wicket:id="username">admin</span>
-
-            <a href="#" wicket:id="logoutLink"><span wicket:id="logoutTranslatedLink"/></a>
-            <a href="#" wicket:id="preferencesLink">Preferences</a>
-        </span>
-    </div>
-
-    <div class="grid_12">
-        <div wicket:id="navigationPanel">Navigation goes here</div>
-    </div>
-    <div class="clear"></div>
 
     <wicket:child />
 
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/page/SidebarPage.html b/core/src/main/resources/org/apache/karaf/webconsole/core/page/SidebarPage.html
index e532812..b02b074 100644
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/page/SidebarPage.html
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/page/SidebarPage.html
@@ -16,12 +16,15 @@
    limitations under the License.
 -->
 <wicket:extend xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
-    <div class="grid_3 sidebar-wrapper">
-        <div class="sidebar" wicket:id="sidebar">Sidebar goes here</div>
+
+    <div class="row-fluid">
+        <div class="span4">
+            <div class="sidebar" wicket:id="sidebar">Sidebar goes here</div>
+        </div>
+        <div class="span8">
+            <span wicket:id="feedback">Feedback stuff</span>
+            <wicket:child />
+        </div>
     </div>
-    <div class="grid_9 sidebar-content content">
-        <span wicket:id="feedback">Feedback stuff</span>
-        <wicket:child />
-    </div>
-    <div class="clear"></div>
+
 </wicket:extend>
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/page/SinglePage.html b/core/src/main/resources/org/apache/karaf/webconsole/core/page/SinglePage.html
index efff411..519f16d 100644
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/page/SinglePage.html
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/page/SinglePage.html
@@ -16,9 +16,10 @@
    limitations under the License.
 -->
 <wicket:extend xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
-    <div class="grid_12 single-content content">
+
+    <div class="row-fluid">
         <span wicket:id="feedback">Feedback stuff</span>
         <wicket:child />
     </div>
-    <div class="clear"></div>
+
 </wicket:extend>
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/navigation/markup/NavigationPanel.html b/core/src/main/resources/org/apache/karaf/webconsole/core/panel/feedback/AlertPanel.html
similarity index 65%
copy from core/src/main/resources/org/apache/karaf/webconsole/core/navigation/markup/NavigationPanel.html
copy to core/src/main/resources/org/apache/karaf/webconsole/core/panel/feedback/AlertPanel.html
index a22af24..8437200 100644
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/navigation/markup/NavigationPanel.html
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/panel/feedback/AlertPanel.html
@@ -16,21 +16,10 @@
    limitations under the License.
 -->
 <wicket:panel xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
-    <div id="topmenu">
-        <ul>
-            <li wicket:id="tabs">
-                <a wicket:id="moduleLink">
-                    <span wicket:id="moduleLabel">Category</span>
-                </a>
-
-                <ul>
-                    <li wicket:id="moduleLinks">
-                        <a wicket:id="link">
-                            <span wicket:id="label">Label</span>
-                        </a>
-                    </li>
-                </ul>
-            </li>
-        </ul>
+    <div wicket:id="wrapper" class="alert">
+        <a class="close" href="#" data-dismiss="alert" >&times;</a>
+        <p>
+            <span wicket:id="message"></span>
+        </p>
     </div>
 </wicket:panel>
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/navigation/markup/NavigationPanel.html b/core/src/main/resources/org/apache/karaf/webconsole/core/panel/feedback/BootstrapFeedbackPanel.html
similarity index 65%
rename from core/src/main/resources/org/apache/karaf/webconsole/core/navigation/markup/NavigationPanel.html
rename to core/src/main/resources/org/apache/karaf/webconsole/core/panel/feedback/BootstrapFeedbackPanel.html
index a22af24..0d55b9a 100644
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/navigation/markup/NavigationPanel.html
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/panel/feedback/BootstrapFeedbackPanel.html
@@ -16,21 +16,9 @@
    limitations under the License.
 -->
 <wicket:panel xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd">
-    <div id="topmenu">
-        <ul>
-            <li wicket:id="tabs">
-                <a wicket:id="moduleLink">
-                    <span wicket:id="moduleLabel">Category</span>
-                </a>
-
-                <ul>
-                    <li wicket:id="moduleLinks">
-                        <a wicket:id="link">
-                            <span wicket:id="label">Label</span>
-                        </a>
-                    </li>
-                </ul>
-            </li>
-        </ul>
+    <div wicket:id="feedbackul">
+        <div wicket:id="messages">
+            <div wicket:id="message"></div>
+        </div>
     </div>
 </wicket:panel>
\ No newline at end of file
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/style.css b/core/src/main/resources/org/apache/karaf/webconsole/core/style.css
index 188d352..4ac91df 100644
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/style.css
+++ b/core/src/main/resources/org/apache/karaf/webconsole/core/style.css
@@ -1,14 +1,10 @@
 * {
-    font-family: Arial, Tahoma;
     font-size: 16px;
 }
 
 body {
-    background: #FFFFFF;
-}
-
-a {
-    color: #0F3B5F;
+    margin-top: 65px;
+    background: #fff;
 }
 
 li.current {
@@ -19,77 +15,6 @@
     border: 1px dotted black;
 }
 
-#container {
-    float: left;
-    width: 1500px;
-    margin: 0 auto;
-}
-
-#sidebar {
-    float: left;
-    width: 250px;
-}
-
-#userbox {
-    float: right;
-    width: 250px;
-}
-
-#userbox img.avatar {
-    padding: 3px;
-    float: left;
-}
-
-#details {
-    display: block;
-    float: left;
-}
-
-#details span {
-    font-weight: bold;
-}
-
-#details a span {
-    font-weight: normal;
-}
-
-#sidebar ul li, #languages ul li {
-    list-style-type: none;
-}
-
-#languages ul li a:link {
-    text-decoration: none;
-}
-
-#languages ul li {
-    display: inline;
-}
-
-#topmenu ul li, #top-panel ul li {
-    display: inline;
-}
-
-#topmenu {
-    background: #6f83ab;
-}
-
-#top-panel ul {
-    margin: 0px;
-}
-
-#top-panel {
-    background: #CCCC00;
-}
-
-table.dataview {
-	width: 100%;
-	margin-top: 20px;
-	margin-bottom: 10px;
-	border-bottom: 1px solid #0079d6;
-	font-size: 1em;
-	font-family: arial;
-}
-
 table.dataview caption { text-align: left; }
 table.dataview tr { padding-top: 2px; padding-bottom: 2px; }
 table.dataview tr.even { background-color: #ffebcd; }
@@ -109,51 +34,3 @@
 table.dataview #message { padding-left: 3px; }
 table.dataview caption { padding-bottom: 2px; }
 
-div.tabpanel div.tab-row{
-  float:left;
-  width:100%;
-  background:#DAE0D2 url("tabs/bg.gif") repeat-x bottom;
-  line-height:normal;
-  }
-
-div.tabpanel div.tab-row ul {
-  margin:0;
-  padding:10px 10px 0;
-  list-style:none;
-  }
-
-div.tabpanel div.tab-row li {
-  float:left;
-  background:url("tabs/left.gif") no-repeat left top;
-  margin:0;
-  padding:0 0 0 9px;
-  }
-
-div.tabpanel div.tab-row a {
-  display:block;
-  background:url("tabs/right.gif") no-repeat right top;
-  padding:5px 15px 4px 6px;
-  text-decoration:none;
-  font-weight:bold;
-  white-space:nowrap;
-  color:#eee;
-  }
-
-div.tab-panel {
-	clear: left;
-}
-
-div.tabpanel div.tab-row a:hover {
-  color:#fff;
-  }
-
-div.tabpanel div.tab-row li.selected {
-  background-image:url("tabs/left_on.gif");
-  }
-
-div.tabpanel div.tab-row li.selected a {
-  background-image:url("tabs/right_on.gif");
-  color:#333;
-  padding-bottom:5px;
-}
-
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/bg.gif b/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/bg.gif
deleted file mode 100644
index 3ae5c60..0000000
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/bg.gif
+++ /dev/null
Binary files differ
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/left.gif b/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/left.gif
deleted file mode 100644
index 473505a..0000000
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/left.gif
+++ /dev/null
Binary files differ
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/left_on.gif b/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/left_on.gif
deleted file mode 100644
index 58d8425..0000000
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/left_on.gif
+++ /dev/null
Binary files differ
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/right.gif b/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/right.gif
deleted file mode 100644
index e97e0e9..0000000
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/right.gif
+++ /dev/null
Binary files differ
diff --git a/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/right_on.gif b/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/right_on.gif
deleted file mode 100644
index 9b02b58..0000000
--- a/core/src/main/resources/org/apache/karaf/webconsole/core/tabs/right_on.gif
+++ /dev/null
Binary files differ
diff --git a/core/src/test/java/org/apache/karaf/webconsole/core/BasePageTest.java b/core/src/test/java/org/apache/karaf/webconsole/core/BasePageTest.java
index 41273e7..6f44ea9 100644
--- a/core/src/test/java/org/apache/karaf/webconsole/core/BasePageTest.java
+++ b/core/src/test/java/org/apache/karaf/webconsole/core/BasePageTest.java
@@ -68,7 +68,7 @@
         WicketTester tester = new WicketTester(application);
         tester.startPage(BasePage.class);
 
-        tester.assertVisible("homeLink:" + imageId);
+        tester.assertVisible("topPanel:" + imageId);
 
         verify(brandProvider);
     }
diff --git a/core/src/test/java/org/apache/karaf/webconsole/core/WebConsoleTest.java b/core/src/test/java/org/apache/karaf/webconsole/core/WebConsoleTest.java
index 884eb0d..6ae5667 100644
--- a/core/src/test/java/org/apache/karaf/webconsole/core/WebConsoleTest.java
+++ b/core/src/test/java/org/apache/karaf/webconsole/core/WebConsoleTest.java
@@ -32,8 +32,6 @@
 import org.apache.wicket.markup.html.link.Link;
 import org.apache.wicket.protocol.http.WebApplication;
 import org.junit.Before;
-import org.osgi.service.prefs.Preferences;
-import org.osgi.service.prefs.PreferencesService;
 
 /**
  * Base class for webconsole tests.
diff --git a/core/src/test/java/org/apache/karaf/webconsole/core/page/SecuredPageTest.java b/core/src/test/java/org/apache/karaf/webconsole/core/page/SecuredPageTest.java
index 864d0c6..b69f432 100644
--- a/core/src/test/java/org/apache/karaf/webconsole/core/page/SecuredPageTest.java
+++ b/core/src/test/java/org/apache/karaf/webconsole/core/page/SecuredPageTest.java
@@ -59,7 +59,7 @@
         WicketTester tester = new WicketTester(application);
 
         tester.startPage(SecuredPage.class);
-        tester.clickLink("logoutLink");
+        tester.clickLink("topPanel:logoutLink");
         tester.assertRenderedPage(LoginPage.class);
     }
 
@@ -76,8 +76,8 @@
         List<ConsoleTabProvider> tabs = new ArrayList<ConsoleTabProvider>();
 
         SerializableConsoleTabProvider mock = createStrictMock(SerializableConsoleTabProvider.class);
-        expect(mock.getModuleLink(anyString(), anyString())).andAnswer(new LinkAnswer("test", BasePage.class));
         expect(mock.getItems(anyString(), anyString())).andReturn(emptyLinkList());
+        expect(mock.getModuleLink(anyString(), anyString())).andAnswer(new LinkAnswer("test", BasePage.class));
 
         tabs.add(mock);
         values.put("tabs", tabs);
@@ -107,11 +107,11 @@
         List<ConsoleTabProvider> tabs = new ArrayList<ConsoleTabProvider>();
 
         SerializableConsoleTabProvider mock = createStrictMock(SerializableConsoleTabProvider.class);
-        expect(mock.getModuleLink(anyString(), anyString())).andAnswer(new LinkAnswer("test", BasePage.class));
         LinksAnswer answer = new LinksAnswer();
         answer.addLink("A1", SecuredPage.class);
         answer.addLink("B1", SidebarPage.class);
         expect(mock.getItems(anyString(), anyString())).andAnswer(answer);
+        expect(mock.getModuleLink(anyString(), anyString())).andAnswer(new LinkAnswer("test", BasePage.class));
 
         tabs.add(mock);
         values.put("tabs", tabs);
@@ -124,8 +124,9 @@
 
         assertTabs(tester, tabs);
         assertTabLink(tester, 0, "test", BasePage.class, answer.getPageLinks());
-        tester.assertLabel("navigationPanel:tabs:0:moduleLinks:0:link:label", "A1");
-        tester.assertLabel("navigationPanel:tabs:0:moduleLinks:1:link:label", "B1");
+
+        tester.assertLabel("topPanel:tabs:0:moduleLinks:0:link:label", "A1");
+        tester.assertLabel("topPanel:tabs:0:moduleLinks:1:link:label", "B1");
 
         verify(mock);
     }
@@ -143,27 +144,27 @@
         List<ConsoleTabProvider> tabs = new ArrayList<ConsoleTabProvider>();
 
         SerializableConsoleTabProvider mock = createStrictMock(SerializableConsoleTabProvider.class);
+        expect(mock.getItems(anyString(), anyString())).andReturn(emptyLinkList());
         expect(mock.getModuleLink(anyString(), anyString())).andAnswer(new LinkAnswer("test1", BasePage.class));
-        expect(mock.getItems(anyString(), anyString())).andReturn(emptyLinkList());
         replay(mock);
         tabs.add(mock);
 
         mock = createStrictMock(SerializableConsoleTabProvider.class);
+        expect(mock.getItems(anyString(), anyString())).andReturn(emptyLinkList());
         expect(mock.getModuleLink(anyString(), anyString())).andAnswer(new LinkAnswer("test2", SecuredPage.class));
-        expect(mock.getItems(anyString(), anyString())).andReturn(emptyLinkList());
         replay(mock);
         tabs.add(mock);
 
         mock = createStrictMock(SerializableConsoleTabProvider.class);
+        expect(mock.getItems(anyString(), anyString())).andReturn(emptyLinkList());
         expect(mock.getModuleLink(anyString(), anyString())).andAnswer(new LinkAnswer("test3", SinglePage.class));
-        expect(mock.getItems(anyString(), anyString())).andReturn(emptyLinkList());
         replay(mock);
         tabs.add(mock);
 
 
         mock = createStrictMock(SerializableConsoleTabProvider.class);
-        expect(mock.getModuleLink(anyString(), anyString())).andAnswer(new LinkAnswer("test4", SidebarPage.class));
         expect(mock.getItems(anyString(), anyString())).andReturn(emptyLinkList());
+        expect(mock.getModuleLink(anyString(), anyString())).andAnswer(new LinkAnswer("test4", SidebarPage.class));
         replay(mock);
         tabs.add(mock);
 
@@ -185,7 +186,7 @@
     // additional asserts
 
     private void assertTabs(WicketTester tester, List<ConsoleTabProvider> tabs) {
-        tester.assertListView("navigationPanel:tabs", tabs);
+        tester.assertListView("topPanel:tabs", tabs);
     }
 
     private void assertTabLink(WicketTester tester, int position, String label, Class<? extends WebPage> page) {
@@ -193,9 +194,11 @@
     }
 
     private void assertTabLink(WicketTester tester, int position, String label, Class<? extends WebPage> page, List<Link<Page>> children) {
-        tester.assertLabel("navigationPanel:tabs:" + position + ":moduleLink:moduleLabel", label);
-        tester.assertBookmarkablePageLink("navigationPanel:tabs:" + position + ":moduleLink", page, "");
-        tester.assertListView("navigationPanel:tabs:" + position + ":moduleLinks", children);
+        tester.assertLabel("topPanel:tabs:" + position + ":moduleLink:moduleLabel", label);
+        tester.assertBookmarkablePageLink("topPanel:tabs:" + position + ":moduleLink", page, "");
+        if (!children.isEmpty()) {
+            tester.assertListView("topPanel:tabs:" + position + ":moduleLinks", children);
+        }
     }
 
     @Override