ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From yus...@apache.org
Subject git commit: AMBARI-5504. Views: Ambari Web Layout Update. (xiwang via yusaku)
Date Fri, 18 Apr 2014 21:42:26 GMT
Repository: ambari
Updated Branches:
  refs/heads/trunk a32863d86 -> bbde993be


AMBARI-5504. Views: Ambari Web Layout Update. (xiwang via yusaku)


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

Branch: refs/heads/trunk
Commit: bbde993be9d0f377274d12dbcf15a15dc43c8d55
Parents: a32863d
Author: Yusaku Sako <yusaku@hortonworks.com>
Authored: Fri Apr 18 14:41:47 2014 -0700
Committer: Yusaku Sako <yusaku@hortonworks.com>
Committed: Fri Apr 18 14:41:47 2014 -0700

----------------------------------------------------------------------
 ambari-web/app/controllers.js                   |   1 +
 ambari-web/app/messages.js                      |   6 +-
 ambari-web/app/routes/main.js                   |  77 ++-
 ambari-web/app/styles/application.less          | 219 ++++++-
 ambari-web/app/templates/application.hbs        |  35 +-
 ambari-web/app/templates/main.hbs               |   7 -
 .../app/templates/main/charts/heatmap.hbs       |   4 +-
 ambari-web/app/templates/main/dashboard.hbs     |  67 +-
 ambari-web/app/templates/main/menu_item.hbs     |  49 +-
 ambari-web/app/views.js                         |   1 +
 ambari-web/app/views/main/dashboard.js          | 604 +------------------
 ambari-web/app/views/main/menu.js               |  75 ++-
 ambari-web/app/views/main/service/menu.js       |  89 ++-
 13 files changed, 515 insertions(+), 719 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/bbde993b/ambari-web/app/controllers.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers.js b/ambari-web/app/controllers.js
index 75348ae..e502296 100644
--- a/ambari-web/app/controllers.js
+++ b/ambari-web/app/controllers.js
@@ -25,6 +25,7 @@ require('controllers/wizard');
 require('controllers/installer');
 require('controllers/global/background_operations_controller');
 require('controllers/main');
+require('controllers/main/dashboard');
 require('controllers/main/admin');
 require('controllers/main/admin/highAvailability_controller');
 require('controllers/main/admin/highAvailability/wizard_controller');

http://git-wip-us.apache.org/repos/asf/ambari/blob/bbde993b/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index 4e32211..1185b69 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -1656,7 +1656,8 @@ Em.I18n.translations = {
   'dashboard.clusterMetrics.memory':'Memory Usage',
   'dashboard.clusterMetrics.network':'Network Usage',
 
-  'dashboard.widgets': 'Cluster Status and Metrics',
+  'dashboard.widgets.title': 'Cluster Status and Metrics',
+  'dashboard.heatmaps.title': 'Heatmaps',
   'dashboard.button.switch': 'Switch to classic dashboard',
   'dashboard.button.switchShort': 'Switch',
   'dashboard.button.reset': 'Reset all widgets to default ',
@@ -1984,13 +1985,12 @@ Em.I18n.translations = {
   'restart.service.rest.context': 'Restart {0}s',
 
   'menu.item.dashboard':'Dashboard',
-  'menu.item.heatmaps':'Heatmaps',
   'menu.item.services':'Services',
   'menu.item.hosts':'Hosts',
   'menu.item.mirroring':'Mirroring',
   'menu.item.jobs':'Jobs',
   'menu.item.admin':'Admin',
-  'menu.item.views':'Views',
+  'menu.item.views':'<i class="icon-th"></i>',
 
   'jobs.nothingToShow': 'No jobs to display',
   'jobs.loadingTasks': 'Loading...',

http://git-wip-us.apache.org/repos/asf/ambari/blob/bbde993b/ambari-web/app/routes/main.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/main.js b/ambari-web/app/routes/main.js
index 4c81c16..17d8bfd 100644
--- a/ambari-web/app/routes/main.js
+++ b/ambari-web/app/routes/main.js
@@ -59,7 +59,7 @@ module.exports = Em.Route.extend({
 
   index: Ember.Route.extend({
     route: '/',
-    redirectsTo: 'dashboard'
+    redirectsTo: 'dashboard.index'
   }),
 
 
@@ -68,7 +68,6 @@ module.exports = Em.Route.extend({
     connectOutlets: function (router, context) {
       router.get('mainController').connectOutlet('mainViews');
     }
-
   }),
   test: Em.Route.extend({
     route: '/test',
@@ -81,38 +80,65 @@ module.exports = Em.Route.extend({
     router.get('applicationController').connectOutlet('main');
   },
 
-  charts: Em.Route.extend({
-    route: '/charts',
+  dashboard: Em.Route.extend({
+    route: '/dashboard',
     connectOutlets: function (router, context) {
-      router.get('mainController').connectOutlet('mainCharts');
+      router.get('mainController').connectOutlet('mainDashboard');
     },
     enter: function (router) {
       Em.run.next(function () {
-        router.transitionTo('heatmap');
+        router.transitionTo('widgets');
       });
     },
-    index: Ember.Route.extend({
+    index: Em.Route.extend({
       route: '/',
-      redirectsTo: 'heatmap'
+      redirectsTo: 'widgets'
     }),
-    heatmap: Em.Route.extend({
-      route: '/heatmap',
+    //on click nav tabs events, go to widgets view or heatmap view
+    goToDashboardView: function (router, event) {
+      router.transitionTo(event.context);
+    },
+    widgets: Em.Route.extend({
+      route: '/clusterWidgets',
       connectOutlets: function (router, context) {
-        router.get('mainChartsController').connectOutlet('mainChartsHeatmap');
+        router.set('mainDashboardController.selectedCategory', 'widgets');
+        router.get('mainDashboardController').connectOutlet('mainDashboardWidgets');
       }
     }),
-    horizon_chart: Em.Route.extend({
-      route: '/horizon_chart',
+    charts: Em.Route.extend({
+      route: '/charts',
       connectOutlets: function (router, context) {
-        router.get('mainChartsController').connectOutlet('mainChartsHorizon');
+        router.set('mainDashboardController.selectedCategory', 'charts');
+        router.get('mainDashboardController').connectOutlet('mainCharts');
+      },
+      enter: function (router) {
+        Em.run.next(function () {
+          router.transitionTo('heatmap');
+        });
+      },
+      index: Ember.Route.extend({
+        route: '/',
+        redirectsTo: 'heatmap'
+      }),
+      heatmap: Em.Route.extend({
+        route: '/heatmap',
+        connectOutlets: function (router, context) {
+          router.get('mainChartsController').connectOutlet('mainChartsHeatmap');
+        }
+      }),
+      horizon_chart: Em.Route.extend({
+        route: '/horizon_chart',
+        connectOutlets: function (router, context) {
+          router.get('mainChartsController').connectOutlet('mainChartsHorizon');
+        }
+      }),
+      showChart: function (router, event) {
+        var parent = event.view._parentView;
+        parent.deactivateChildViews();
+        event.view.set('active', "active");
+        router.transitionTo(event.context);
       }
-    }),
-    showChart: function (router, event) {
-      var parent = event.view._parentView;
-      parent.deactivateChildViews();
-      event.view.set('active', "active");
-      router.transitionTo(event.context);
-    }
+    })
   }),
 
   apps: Em.Route.extend({
@@ -585,7 +611,7 @@ module.exports = Em.Route.extend({
       router.transitionTo('admin' + object.context.capitalize());
     },
 
-//events
+    //events
     goToAdmin: function (router, event) {
       router.transitionTo(event.context);
     }
@@ -593,13 +619,6 @@ module.exports = Em.Route.extend({
   }),
   stackUpgrade: require('routes/stack_upgrade'),
 
-  dashboard: Em.Route.extend({
-    route: '/dashboard',
-    connectOutlets: function (router, context) {
-      router.get('mainController').connectOutlet('mainDashboard');
-    }
-  }),
-
   services: Em.Route.extend({
     route: '/services',
     index: Em.Route.extend({

http://git-wip-us.apache.org/repos/asf/ambari/blob/bbde993b/ambari-web/app/styles/application.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/application.less b/ambari-web/app/styles/application.less
index 54cf714..43ef9a0 100644
--- a/ambari-web/app/styles/application.less
+++ b/ambari-web/app/styles/application.less
@@ -39,6 +39,25 @@
   100% { background-color: #118fff; }
 }
 
+@-webkit-keyframes greenPulseInner {
+  from { color: #118fff; }
+  50% { color: #006DCC; }
+  to { color: #118fff; }
+}
+
+@-moz-keyframes greenPulseInner {
+  from { color: #118fff; }
+  50% { color: #006DCC; }
+  to { color: #118fff; }
+}
+
+@keyframes greenPulseInner
+{
+  0% { color: #118fff; }
+  50% { color: #006DCC; }
+  100% { color: #118fff; }
+}
+
 .gradient(@color: #FAFAFA, @start: #FFFFFF, @stop: #F2F2F2) {
   background: @color;
   background: -webkit-gradient(linear, left top, left bottom, color-stop(0, @start), color-stop(1, @stop));
@@ -87,12 +106,38 @@ footer {
   padding: 15px 0;
 }
 
+@top-nav-bg-color-from: #555555;
+@top-nav-bg-color-to: #333333;
+@top-nav-brand-color: #ffffff;
+@top-nav-ops-count-color: #ffffff;
+@top-nav-ops-count-bg-color: #c3c3c3;
+@top-nav-menu-active-text-color: #333333;
+@top-nav-menu-active-bg-color: #ffffff;
+@top-nav-menu-text-color: #c3c3c3;
+@top-nav-menu-text-hover-color: #ffffff;
+@top-nav-menu-dropdown-border-color: #c3c3c3;
+@top-nav-menu-dropdown-bg-color: #ffffff;
+@top-nav-menu-dropdown-text-color: #333333;
+
 #top-nav {
-  .navbar {
+
+  .navbar.navbar-static-top {
     font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-  }
+    -moz-box-shadow: 0 1 5px #888;
+    -webkit-box-shadow: 0 1px 5px #888;
+    box-shadow: 0 1px 5px #888;
+    .navbar-inner {
+      background-image: -moz-linear-gradient(top, @top-nav-bg-color-from, @top-nav-bg-color-to);
+      background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@top-nav-bg-color-from), to(@top-nav-bg-color-to));
+      background-image: -webkit-linear-gradient(top, @top-nav-bg-color-from, @top-nav-bg-color-to);
+      background-image: -o-linear-gradient(top, @top-nav-bg-color-from, @top-nav-bg-color-to);
+      background-image: linear-gradient(to bottom, @top-nav-bg-color-from, @top-nav-bg-color-to);
+      -webkit-box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);
+      -moz-box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);
+      box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);
+      max-height: 40px;
+    }
 
-  .navbar {
     .logo {
       float: left;
       padding-top: 2px;
@@ -102,12 +147,13 @@ footer {
     }
 
     .brand {
-      color: #666666;
+      color: @top-nav-brand-color;
       font-size: 16px;
       font-weight: normal;
       line-height: 32px;
       margin-left: 0;
       padding: 2px 5px 0 10px;
+      text-shadow: 0 1px 0 #555555;
     }
 
     .brand.cluster-name {
@@ -124,10 +170,144 @@ footer {
         animation-name: greenPulse;
         animation-duration: 1s;
         animation-iteration-count: infinite;
-        margin: 2px;
+        //margin: 2px;
       }
+      .label  {
+         padding: 3px 5px 3px;
+         color: @top-nav-ops-count-color;
+         text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+         background-color: @top-nav-ops-count-bg-color;
+       }
+      .icon-caret-left {
+        color: @top-nav-ops-count-bg-color;
+        margin-right: -1px;
+        text-shadow: none;
+      }
+      .ops-count {
+        margin-right: -1px;
+        color: #006DCC;
+        text-shadow: none;
+        -webkit-animation-name: greenPulseInner;
+        -webkit-animation-duration: 1s;
+        -webkit-animation-iteration-count: infinite;
+        -moz-animation-name: greenPulseInner;
+        -moz-animation-duration: 1s;
+        -moz-animation-iteration-count: infinite;
+        animation-name: greenPulseInner;
+        animation-duration: 1s;
+        animation-iteration-count: infinite;
+      }
+
     }
+    .top-nav-menu.nav {
+      display: block;
+      float: right;
+      padding-left: 20px;
+      overflow: visible;
+
+      li > a {
+        text-shadow: none;
+        color: @top-nav-menu-text-color;
+        text-align: center;
+        white-space: nowrap;
+      }
+      .active > a, .active > a:hover, .active > a:focus {
+        color: @top-nav-menu-active-text-color;
+        background-color: @top-nav-menu-active-bg-color;
+        -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
+        -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
+        box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125);
+      }
+      li > a:focus, li > a:hover {
+        color: @top-nav-menu-text-hover-color;
+        text-decoration: none;
+        background-color: transparent;
+      }
+      .alerts-count {
+        margin: 1px;
+      }
+      .icon-th {
+        font-size: 1.3em;
+      }
+      //top-nav bar dropdown menu on hover
+      li.top-nav-dropdown {
+        position: relative;
+      }
+      .top-nav-dropdown:hover .top-nav-dropdown-menu {
+        display: block;
 
+      }
+      .top-nav-dropdown-menu {
+        display: none;
+        position: absolute;
+        top: 95%;
+        left: 0;
+        z-index: 1000;
+        float: left;
+        min-width: 160px;
+        padding: 5px 0;
+        margin: 2px 0 0;
+        list-style: none;
+        background-color: @top-nav-menu-dropdown-bg-color;
+        border: 3px solid @top-nav-menu-dropdown-border-color;
+        -webkit-border-radius: 6px;
+        -moz-border-radius: 6px;
+        border-radius: 6px;
+        -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+        -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+        box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
+        -webkit-background-clip: padding-box;
+        -moz-background-clip: padding;
+        background-clip: padding-box;
+        .health-status-LIVE, .health-status-STARTING {
+          color: @health-status-green;
+        }
+        .health-status-DEAD-RED, .health-status-STOPPING {
+          color: @health-status-red;
+        }
+        .health-status-DEAD-YELLOW {
+          color: @health-status-yellow;
+        }
+        .icon-refresh {
+          color: #fdb82f;
+          margin-left: 4px;
+        }
+        .label {
+          padding: 0 0 0 3px;
+        }
+        .operations-count {
+          background: #953B39;
+        }
+      }
+      .top-nav-dropdown-menu > li{
+        position: relative;
+      }
+      .top-nav-dropdown-menu > li.active > a{
+        background-color: @top-nav-menu-dropdown-border-color;
+      }
+      .top-nav-dropdown-menu > li > a {
+        text-decoration: none;
+        text-align: left;
+        padding: 5px;
+        display: block;
+        padding: 3px 20px;
+        clear: both;
+        font-weight: normal;
+        line-height: 20px;
+        color: @top-nav-menu-dropdown-text-color;
+        white-space: nowrap;
+      }
+      .top-nav-dropdown-menu > li.active > a{
+        background-color: #e5e5e5;
+      }
+      .top-nav-dropdown-menu > li > a:hover {
+        color: #ffffff;
+        background-color: #666666;
+        background-image: linear-gradient(to bottom, #666666, #555555);
+        background-repeat: repeat-x;
+      }
+
+    }
   }
 
   .navbar .nav {
@@ -137,14 +317,19 @@ footer {
 
   .navbar-inner {
     min-height: 40px;
+    border: none;
   }
 
-  .navbar .nav .active > a, .navbar .nav .active > a:hover {
+  .top-nav-user {
+    float: right;
+  }
+  .navbar .nav .top-nav-user .active > a,
+  .navbar .nav .top-nav-user .active > a:hover {
     color: #FFFFFF;
     text-decoration: none;
   }
 
-  .navbar .nav > li > a {
+  .navbar .nav .top-nav-user > li > a {
     border-radius: 8px;
     -webkit-border-radius: 8px;
     -moz-border-radius: 8px;
@@ -157,13 +342,13 @@ footer {
     text-shadow: none;
   }
 
-  .navbar .nav > li > a:hover {
+  .navbar .nav .top-nav-user > li > a:hover {
     background-color: transparent;
     color: #999999;
     text-decoration: none;
   }
 
-  .navbar .nav > li.right {
+  .navbar .nav .top-nav-user > li.right {
     float: right;
   }
 }
@@ -2457,12 +2642,14 @@ table.graphs {
 
 /*Dashboard Widgets Start*/
 #dashboard-widgets-container{
+  > ul.nav.nav-tabs {
+    margin-bottom: 10px;
+  }
   h4{
     line-height: 30px;
     margin-bottom: 0px;
     margin-top: 0px;
   }
-
   .add-widget-button{
     margin-top: 0px;
     margin-left: -22px;
@@ -2526,8 +2713,6 @@ table.graphs {
     margin-right: 4px;
   }
 
-
-
   #dashboard-widgets{
     .caption {
       height: 25px;
@@ -4025,6 +4210,7 @@ ul.filter {
 
 /*Start Heatmap*/
 .heatmap {
+  padding: 5px;
   #heatmap-metric-title {
     margin-left: 23px;
   }
@@ -4054,7 +4240,11 @@ ul.filter {
     }
   }
   .legend-column {
-    min-width: 160px;
+    min-width: 150px;
+  }
+  .heatmap-content {
+    float: right;
+    width: 80%;
   }
   .heatmap_host_details {
     font-size: 12px;
@@ -4075,8 +4265,9 @@ ul.filter {
   .legend {
     margin-top: 20px;
     margin-bottom: 20px;
+    font-size: 12px;
     .tile {
-      width: 50px;
+      width: 30px;
       height: 1em;
       padding: 4px;
       border: 1px solid #D4D4D4;

http://git-wip-us.apache.org/repos/asf/ambari/blob/bbde993b/ambari-web/app/templates/application.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/application.hbs b/ambari-web/app/templates/application.hbs
index 8c21c72..02f4607 100644
--- a/ambari-web/app/templates/application.hbs
+++ b/ambari-web/app/templates/application.hbs
@@ -21,40 +21,43 @@
     <div class="navbar navbar-static-top">
       <div class="navbar-inner">
         <div class="container main-container">
-          <a {{translateAttr href="topnav.logo.href"}} class="logo" target="_blank"><img src="/img/logo.png" alt="Apache Ambari" title="Apache Ambari"></a>
+          <a {{translateAttr href="topnav.logo.href"}} class="logo" target="_blank"><img src="/img/logo-white.png" alt="Apache Ambari" title="Apache Ambari"></a>
           <a class="brand" {{translateAttr href="topnav.logo.href"}} target="_blank" title="Apache Ambari">{{t app.name}}</a>
 
           {{#if isClusterDataLoaded}}
             <a class="brand cluster-name" href="javascript:void(null);" {{bindAttr title="clusterName"}}>
               <span {{action "showPopup" target="App.router.backgroundOperationsController"}} >{{clusterDisplayName}} </span>
-
-              {{#with App.router.backgroundOperationsController}}
-                {{#if allOperationsCount}}
-                  <span class="label operations-count" {{action "showPopup" target="App.router.backgroundOperationsController"}}>{{allOperationsCount}} {{t ops}}</span>
-                {{else}}
-                  <span class="label" {{action "showPopup" target="App.router.backgroundOperationsController"}}>{{allOperationsCount}} {{t ops}}</span>
-                {{/if}}
-              {{/with}}
+                {{#with App.router.backgroundOperationsController}}
+                  {{#if allOperationsCount}}
+                      <i class="icon-caret-left ops-count"></i><span class="label operations-count" {{action "showPopup" target="App.router.backgroundOperationsController"}}> {{allOperationsCount}} {{t ops}}</span>
+                  {{else}}
+                      <i class="icon-caret-left"></i><span class="label" {{action "showPopup" target="App.router.backgroundOperationsController"}}>{{allOperationsCount}} {{t ops}}</span>
+                  {{/if}}
+                {{/with}}
             </a>
           {{/if}}
 
           {{#if App.router.loggedIn}}
-            <div class="btn-group pull-right usermenu-wrapper">
-              <button class="btn btn-group dropdown-toggle"  data-toggle="dropdown">
-                {{App.router.loginName}}&nbsp;<span class="caret"></span>
+            <div class="top-nav-user btn-group">
+              <button class="btn dropdown-toggle"  data-toggle="dropdown">
+                  <i class="icon-user"></i>&nbsp;{{App.router.loginName}}&nbsp;<span class="caret"></span>
               </button>
               <ul class="dropdown-menu">
-                <li><a href="" {{action showAboutPopup target="controller"}}>{{t app.aboutAmbari}}</a></li>
+                  <li><a href="" {{action showAboutPopup target="controller"}}>{{t app.aboutAmbari}}</a></li>
                 {{#if isClusterDataLoaded}}
                   {{#if App.isAdmin}}
-                    <li><a href="" {{action showSettingsPopup target="controller"}}>{{t app.settings}}</a></li>
+                      <li><a href="" {{action showSettingsPopup target="controller"}}>{{t app.settings}}</a></li>
                   {{/if}}
                 {{/if}}
-                <li class="break"></li>
-                <li><a href="" {{action logoff}}>{{t app.signout}}</a></li>
+                  <li class="break"></li>
+                  <li><a href="" {{action logoff}}>{{t app.signout}}</a></li>
               </ul>
             </div>
           {{/if}}
+
+          {{#if isClusterDataLoaded}}
+            {{view App.MainMenuView}}
+          {{/if}}
         </div>
       </div>
     </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/bbde993b/ambari-web/app/templates/main.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main.hbs b/ambari-web/app/templates/main.hbs
index 0a6ebcf..612fdcd 100644
--- a/ambari-web/app/templates/main.hbs
+++ b/ambari-web/app/templates/main.hbs
@@ -22,13 +22,6 @@
   </div>
 {{else}}
   {{#if isClusterDataLoaded}}
-    <div id="main-nav">
-      <div class="navbar">
-        <div class="navbar-inner">
-          {{view App.MainMenuView}}
-        </div>
-      </div>
-    </div>
     {{outlet}}
   {{/if}}
   {{#unless isClusterDataLoaded}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/bbde993b/ambari-web/app/templates/main/charts/heatmap.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/charts/heatmap.hbs b/ambari-web/app/templates/main/charts/heatmap.hbs
index 3b5a750..f08ffc8 100644
--- a/ambari-web/app/templates/main/charts/heatmap.hbs
+++ b/ambari-web/app/templates/main/charts/heatmap.hbs
@@ -16,7 +16,7 @@
 * limitations under the License.
 }}
 
-<div class="heatmap">
+<div class="heatmap box">
 
   <div class="container-fluid">
 	  <div class="row-fluid">
@@ -59,7 +59,7 @@
 	        </div>
         {{/if}}
 	    </div>
-	    <div class="span10">
+	    <div class="span10 heatmap-content">
 	      <h4 id="heatmap-metric-loading">
 	        <span id="heatmap-metric-title">{{controller.selectedMetric.name}}</span>
 	      </h4>

http://git-wip-us.apache.org/repos/asf/ambari/blob/bbde993b/ambari-web/app/templates/main/dashboard.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/dashboard.hbs b/ambari-web/app/templates/main/dashboard.hbs
index b10a3c6..f0bceb0 100644
--- a/ambari-web/app/templates/main/dashboard.hbs
+++ b/ambari-web/app/templates/main/dashboard.hbs
@@ -15,56 +15,21 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 }}
-{{#if view.isDataLoaded}}
-    <div class="row-fluid">
-      <div class="services-menu well span2" style="padding: 8px 0">
-        {{view App.MainServiceMenuView}}
-        {{view App.AllServicesActionView}}
-      </div>
 
-      <div class="span10" id="dashboard-widgets-container">
-        <div class="box">
-          <div class="box-header">
-            <div class="row-fluid">
-              <h4 class="span10">{{t dashboard.widgets}}</h4>
-                <a class="add-widget-button span1">{{view view.plusButtonFilterView}}</a>
-                <div class="btn-group">
-                  <button class="btn dropdown-toggle span1 more-options-button"  data-toggle="dropdown">
-                    <i class="icon-cog"></i> &nbsp;
-                    <span class= "caret"></span>
-                  </button>
-                  <ul class="dropdown-menu right-align-dropdown">
-                    <li>
-                      <a href="#" {{action "resetAllWidgets" target="view"}}>
-                        <i class="icon-refresh"></i>
-                        {{t dashboard.button.reset}}
-                      </a>
-                    </li>
-                    <li>
-                      <a target="_blank" {{bindAttr href="view.gangliaUrl"}}>
-                        <i class="icon-share"></i>
-                        {{t dashboard.button.gangliaLink}}
-                      </a>
-                    </li>
-                  </ul>
-                </div>
-            </div>
-          </div>
-
-          <div id="dashboard-widgets"  class="widgets-container">
-            <div class="thumbnails row-fluid" id="sortable">
-              {{#if view.visibleWidgets.length}}
-                {{#each widgetClass in view.visibleWidgets}}
-                  <div {{bindAttr class="widgetClass.class"}}>
-                    {{view widgetClass }}
-                  </div>
-                {{/each}}
-              {{/if}}
-            </div>
-          </div>
-
-        </div>
-      </div>
+<div class="row-fluid">
+  <div class="services-menu well span2" style="padding: 8px 0">
+    {{view App.MainServiceMenuView}}
+    {{view App.AllServicesActionView}}
+  </div>
+    <div class="span10" id="dashboard-widgets-container">
+      <ul class="nav nav-tabs">
+        {{#each category in view.categories}}
+          {{#view view.NavItemView itemBinding="category.name" }}
+              <a href="#" {{action "goToDashboardView" category.url}} >{{category.label}}</a>
+          {{/view}}
+        {{/each}}
+      </ul>
+      <!--show widgets or heapmaps in the content-->
+      {{outlet}}
     </div>
-{{/if}}
-
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/bbde993b/ambari-web/app/templates/main/menu_item.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/menu_item.hbs b/ambari-web/app/templates/main/menu_item.hbs
index 5031e76..894e491 100644
--- a/ambari-web/app/templates/main/menu_item.hbs
+++ b/ambari-web/app/templates/main/menu_item.hbs
@@ -15,25 +15,32 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 }}
-{{#if view.content.isView}}
-    <a href="#" class="dropdown-toggle" data-toggle="dropdown">{{view.content.label}}<b class="caret pull-right"></b></a>
-    <ul class="dropdown-menu pull-right">
-      {{#each v in view.content.views}}
-          <li><a href="#" class="align-right" {{action "setView" v target="App.router.mainViewsController"}}>{{v.label}}</a></li>
-      {{/each}}
-    </ul>
-{{else}}
-    <a href="#/main/{{unbound view.content.routing}}">
-      {{unbound view.content.label}}
-      {{#if view.alertsCount}}
-          <span class="label label-important alerts-count">
-            {{view.alertsCount}}
-          </span>
-      {{/if}}
-        <!--{{#if view.hostDetailsOperationsCount}}-->
-        <!--<span class="label operations-count" {{action "showBackgroundOperationsPopup" target="App.router.mainHostDetailsController"}}>-->
-        <!--{{view.hostDetailsOperationsCount}}-->
-        <!--</span>-->
-        <!--{{/if}}-->
-    </a>
+<a href="#/main/{{unbound view.content.routing}}">
+  {{{unbound view.content.label}}}
+  {{#if view.alertsCount}}
+      <span class="label label-important alerts-count">
+        {{view.alertsCount}}
+      </span>
+  {{/if}}
+</a>
+<!--dropdown menu for the items had dropdowns-->
+{{#if view.isServicesItem}}
+  {{view App.TopNavServiceMenuView}}
 {{/if}}
+{{#if view.isAdminItem}}
+  <ul class="top-nav-dropdown-menu">
+    {{#each category in view.dropdownCategories}}
+        <li><a href="#" {{action "goToCategory" category.url target="view"}}>{{category.label}}</a></li>
+    {{/each}}
+  </ul>
+{{/if}}
+{{#if view.isViewsItem}}
+  <ul class="top-nav-dropdown-menu">
+    {{#each category in view.content.views}}
+        <li><a href="#" {{action "setView" category target="App.router.mainViewsController"}}>{{category.label}}</a></li>
+    {{/each}}
+  </ul>
+{{/if}}
+
+
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/bbde993b/ambari-web/app/views.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js
index 4af6051..adc6720 100644
--- a/ambari-web/app/views.js
+++ b/ambari-web/app/views.js
@@ -107,6 +107,7 @@ require('views/main/dashboard/cluster_metrics/memory');
 require('views/main/dashboard/cluster_metrics/network');
 
 require('views/main/dashboard/widget');
+require('views/main/dashboard/widgets');
 require('views/main/dashboard/widgets/text_widget');
 require('views/main/dashboard/widgets/uptime_text_widget');
 require('views/main/dashboard/widgets/links_widget');

http://git-wip-us.apache.org/repos/asf/ambari/blob/bbde993b/ambari-web/app/views/main/dashboard.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/dashboard.js b/ambari-web/app/views/main/dashboard.js
index 5004b3b..a8c2b5b 100644
--- a/ambari-web/app/views/main/dashboard.js
+++ b/ambari-web/app/views/main/dashboard.js
@@ -17,577 +17,39 @@
  */
 
 var App = require('app');
-var filters = require('views/common/filter_view');
 
-App.MainDashboardView = Em.View.extend(App.UserPref, App.LocalStorage, {
+App.MainDashboardView = Em.View.extend({
 
   name: 'mainDashboardView',
-
-  templateName:require('templates/main/dashboard'),
-
-  didInsertElement:function () {
-    this.setWidgetsDataModel();
-    this.setInitPrefObject();
-    this.setOnLoadVisibleWidgets();
-    this.set('isDataLoaded',true);
-    Em.run.next(this, 'makeSortable');
-  },
-
-  /**
-   * List of services
-   * @type {Ember.Enumerable}
-   */
-  content:[],
-
-  /**
-   * @type {bool}
-   */
-  isDataLoaded: false,
-
-  /**
-   * Make widgets' list sortable on New Dashboard style
-   */
-  makeSortable: function () {
-    var self = this;
-    $( "#sortable" ).sortable({
-      items: "> div",
-      //placeholder: "sortable-placeholder",
-      cursor: "move",
-      update: function (event, ui) {
-        if (!App.testMode) {
-          // update persist then translate to real
-          var widgetsArray = $('div[viewid]'); // get all in DOM
-          self.getUserPref(self.get('persistKey'));
-          var oldValue = self.get('currentPrefObject') || self.getDBProperty(self.get('persistKey'));
-          var newValue = Em.Object.create({
-            dashboardVersion: oldValue.dashboardVersion,
-            visible: [],
-            hidden: oldValue.hidden,
-            threshold: oldValue.threshold
-          });
-          var size = oldValue.visible.length;
-          for(var j = 0; j <= size -1; j++){
-            var viewID = widgetsArray.get(j).getAttribute('viewid');
-            var id = viewID.split("-").get(1);
-            newValue.visible.push(id);
-          }
-          self.postUserPref(self.get('persistKey'), newValue);
-          self.setDBProperty(self.get('persistKey'), newValue);
-          //self.translateToReal(newValue);
-        }
-      }
-    }).disableSelection();
-  },
-
-  /**
-   * Set Service model values
-   */
-  setWidgetsDataModel: function () {
-    var services = App.Service.find();
-    var self = this;
-    services.forEach(function (item) {
-      switch (item.get('serviceName')) {
-        case "HDFS":
-          self.set('hdfs_model',  App.HDFSService.find(item.get('id')) || item);
-          break;
-        case "YARN":
-          self.set('yarn_model', App.YARNService.find(item.get('id')) || item);
-          break;
-        case "MAPREDUCE":
-          self.set('mapreduce_model', App.MapReduceService.find(item.get('id')) || item);
-          break;
-        case "HBASE":
-          self.set('hbase_model', App.HBaseService.find(item.get('id')) || item);
-          break;
-        case "STORM":
-          self.set('storm_model', item);
-          break;
-        case "FLUME":
-          self.set('flume_model', item);
-          break;
-      }
-    }, this);
-  },
-
-  /**
-   * Load widget statuses to <code>initPrefObject</code>
-   */
-  setInitPrefObject: function() {
-    //in case of some service not installed
-    var visibleFull = [
-      '2', '4', '8', '10',
-      '17', '11', '12', '13', '14',
-      '18', '1', '6', '5', '9',
-      '3', '7', '15', '16', '20',
-      '19', '21', '23',
-      '24', '25', '26', '27',// all yarn
-      '28', // storm
-      '29' // flume
-    ]; // all in order
-    var hiddenFull = [['22','Region In Transition']];
-    if (this.get('hdfs_model') == null) {
-      var hdfs= ['1', '2', '3', '4', '5', '15', '17'];
-      hdfs.forEach ( function (item) {
-        visibleFull = visibleFull.without(item);
-      }, this);
-    }
-    if (this.get('mapreduce_model') == null) {
-      var map = ['6', '7', '8', '9', '10', '16', '18'];
-      map.forEach ( function (item) {
-        visibleFull = visibleFull.without(item);
-      }, this);
-    }
-    if (this.get('hbase_model') == null) {
-      var hbase = ['19', '20', '21', '23'];
-      hbase.forEach ( function (item) {
-        visibleFull = visibleFull.without(item);
-      }, this);
-      hiddenFull = [];
-    }
-    if (this.get('yarn_model') == null) {
-      var yarn = ['24', '25', '26', '27'];
-      yarn.forEach ( function (item) {
-        visibleFull = visibleFull.without(item);
-      }, this);
-    }
-    if (this.get('storm_model') == null) {
-      var storm = ['28'];
-      storm.forEach(function(item) {
-        visibleFull = visibleFull.without(item);
-      }, this);
-    }
-    if (this.get('flume_model') == null) {
-      var flume = ['29'];
-      flume.forEach(function(item) {
-        visibleFull = visibleFull.without(item);
-      }, this);
-    }
-    var obj = this.get('initPrefObject');
-    obj.set('visible', visibleFull);
-    obj.set('hidden', hiddenFull);
-  },
-
-  hdfs_model: null,
-
-  mapreduce_model: null,
-
-  mapreduce2_model: null,
-
-  yarn_model: null,
-
-  hbase_model: null,
-
-  storm_model: null,
-
-  flume_model: null,
-
-  /**
-   * List of visible widgets
-   * @type {Ember.Enumerable}
-   */
-  visibleWidgets: [],
-
-  /**
-   * List of hidden widgets
-   * @type {Ember.Enumerable}
-   */
-  hiddenWidgets: [], // widget child view will push object in this array if deleted
-
-  /**
-   * Submenu view for New Dashboard style
-   * @type {Ember.View}
-   */
-  plusButtonFilterView: filters.createComponentView({
-    /**
-     * Base methods was implemented in <code>filters.componentFieldView</code>
-     */
-    hiddenWidgetsBinding: 'parentView.hiddenWidgets',
-    visibleWidgetsBinding: 'parentView.visibleWidgets',
-    layout: null,
-
-    filterView: filters.componentFieldView.extend({
-      templateName:require('templates/main/dashboard/plus_button_filter'),
-      hiddenWidgetsBinding: 'parentView.hiddenWidgets',
-      visibleWidgetsBinding: 'parentView.visibleWidgets',
-      valueBinding: '',
-      applyFilter:function() {
-        this._super();
-        var parent = this.get('parentView').get('parentView');
-        var hiddenWidgets = this.get('hiddenWidgets');
-        var checkedWidgets = hiddenWidgets.filterProperty('checked', true);
-
-        if (App.testMode) {
-          var visibleWidgets = this.get('visibleWidgets');
-          checkedWidgets.forEach(function(item){
-            var newObj = parent.widgetsMapper(item.id);
-            visibleWidgets.pushObject(newObj);
-            hiddenWidgets.removeObject(item);
-          }, this);
-        } else {
-          //save in persist
-          parent.getUserPref(parent.get('persistKey'));
-          var oldValue = parent.get('currentPrefObject') || parent.getDbProperty(parent.get('persistKey'));
-          var newValue = Em.Object.create({
-            dashboardVersion: oldValue.dashboardVersion,
-            visible: oldValue.visible,
-            hidden: [],
-            threshold: oldValue.threshold
-          });
-          checkedWidgets.forEach(function(item){
-            newValue.visible.push(item.id);
-            hiddenWidgets.removeObject(item);
-          }, this);
-          hiddenWidgets.forEach(function(item){
-            newValue.hidden.push([item.id, item.displayName]);
-          }, this);
-          parent.postUserPref(parent.get('persistKey'), newValue);
-          parent.setDBProperty(parent.get('persistKey'), newValue);
-          parent.translateToReal(newValue);
-        }
-      }
-    })
-  }),
-
-  /**
-   * Translate from Json value got from persist to real widgets view
-   */
-  translateToReal: function (value) {
-    var version = value.dashboardVersion;
-    var visible = value.visible;
-    var hidden = value.hidden;
-    var threshold = value.threshold;
-
-    if (version == 'classic') {
-      this.set('isClassicDashboard', true);
-    } else if (version == 'new') {
-      this.set('isClassicDashboard', false);
-      var visibleWidgets = [];
-      var hiddenWidgets = [];
-      // re-construct visibleWidgets and hiddenWidgets
-      for (var j = 0; j <= visible.length -1; j++) {
-        var id = visible[j];
-        var widgetClass = this.widgetsMapper(id);
-        //override with new threshold
-        if (threshold[id].length > 0) {
-          widgetClass.reopen({
-            thresh1: threshold[id][0],
-            thresh2: threshold[id][1]
-          });
-        }
-        visibleWidgets.pushObject(widgetClass);
-      }
-      for (var j = 0; j <= hidden.length -1; j++) {
-        var id = hidden[j][0];
-        var title = hidden[j][1];
-        hiddenWidgets.pushObject(Em.Object.create({displayName:title , id: id, checked: false}));
-      }
-      this.set('visibleWidgets', visibleWidgets);
-      this.set('hiddenWidgets', hiddenWidgets);
-    }
-  },
-
-  /**
-   * Set visibility-status for widgets
-   */
-  setOnLoadVisibleWidgets: function () {
-    if (App.testMode) {
-      this.translateToReal(this.get('initPrefObject'));
-    } else {
-      // called when first load/refresh/jump back page
-      this.getUserPref(this.get('persistKey'));
-      var currentPrefObject = this.get('currentPrefObject') || this.getDBProperty(this.get('persistKey'));
-      if (currentPrefObject) { // fit for no dashboard version
-        if (!currentPrefObject.dashboardVersion) {
-          currentPrefObject.dashboardVersion = 'new';
-          this.postUserPref(this.get('persistKey'), currentPrefObject);
-          this.setDBProperty(this.get('persistKey'), currentPrefObject);
-        }
-        this.set('currentPrefObject', this.checkServicesChange(currentPrefObject));
-        this.translateToReal(this.get('currentPrefObject'));
-      }
-      else {
-        // post persist then translate init object
-        this.postUserPref(this.get('persistKey'), this.get('initPrefObject'));
-        this.setDBProperty(this.get('persistKey'), this.get('initPrefObject'));
-        this.translateToReal(this.get('initPrefObject'));
-      }
-    }
-  },
-
-  /**
-   * Remove widget from visible and hidden lists
-   * @param {Object} value
-   * @param {Object} widget
-   * @returns {*}
-   */
-  removeWidget: function (value, widget) {
-    value.visible = value.visible.without(widget);
-    for (var j = 0; j <= value.hidden.length -1; j++) {
-      if (value.hidden[j][0] == widget) {
-        value.hidden.splice(j, 1);
-      }
-    }
-    return value;
-  },
-
-  /**
-   * Check if widget is in visible or hidden list
-   * @param {Object} value
-   * @param {Object} widget
-   * @returns {bool}
-   */
-  containsWidget: function (value, widget) {
-    var flag = value.visible.contains (widget);
-    for (var j = 0; j <= value.hidden.length -1; j++) {
-      if ( !flag && value.hidden[j][0] == widget) {
-        flag = true;
-        break;
-      }
-    }
-    return flag;
-  },
-
-  /**
-   * check if stack has upgraded from HDP 1.0 to 2.0 OR add/delete services.
-   * Update the value on server if true.
-   * @param {Object} currentPrefObject
-   * @return {Object}
-   */
-  checkServicesChange: function (currentPrefObject) {
-    var toDelete = $.extend(true, {}, currentPrefObject);
-    var toAdd = [];
-    var self = this;
-
-    // check each service, find out the newly added service and already deleted service
-    if (this.get('hdfs_model') != null) {
-      var hdfsAndMetrics= ['1', '2', '3', '4', '5', '15', '17', '11', '12', '13', '14'];
-      hdfsAndMetrics.forEach ( function (item) {
-        toDelete = self.removeWidget(toDelete, item);
-      }, this);
-    }
-    if (this.get('mapreduce_model') != null) {
-      var map = ['6', '7', '8', '9', '10', '16', '18'];
-      var flag = self.containsWidget(toDelete, map[0]);
-      if (flag) {
-        map.forEach ( function (item) {
-          toDelete = self.removeWidget(toDelete, item);
-        }, this);
-      } else {
-        toAdd = toAdd.concat(map);
-      }
-    }
-    if (this.get('hbase_model') != null) {
-      var hbase = ['19', '20', '21', '22', '23'];
-      var flag = self.containsWidget(toDelete, hbase[0]);
-      if (flag) {
-        hbase.forEach ( function (item) {
-          toDelete = self.removeWidget(toDelete, item);
-        }, this);
-      } else {
-        toAdd = toAdd.concat(hbase);
-      }
-    }
-    if (this.get('yarn_model') != null) {
-      var yarn = ['24', '25', '26', '27'];
-      var flag = self.containsWidget(toDelete, yarn[0]);
-      if (flag) {
-        yarn.forEach ( function (item) {
-          toDelete = self.removeWidget(toDelete, item);
-        }, this);
-      } else {
-        toAdd = toAdd.concat(yarn);
-      }
-    }
-    if (this.get('storm_model') != null) {
-      var storm = ['28'];
-      var flag = self.containsWidget(toDelete, storm[0]);
-      if (flag) {
-        storm.forEach ( function (item) {
-          toDelete = self.removeWidget(toDelete, item);
-        }, this);
-      } else {
-        toAdd = toAdd.concat(storm);
-      }
-    }
-    if (this.get('flume_model') != null) {
-      var flume = ['29'];
-      var flag = self.containsWidget(toDelete, flume[0]);
-      if (flag) {
-        flume.forEach ( function (item) {
-          toDelete = self.removeWidget(toDelete, item);
-        }, this);
-      } else {
-        toAdd = toAdd.concat(flume);
-      }
-    }
-    var value = currentPrefObject;
-    if (toDelete.visible.length || toDelete.hidden.length) {
-      toDelete.visible.forEach ( function (item) {
-        value = self.removeWidget(value, item);
-      }, this);
-      toDelete.hidden.forEach ( function (item) {
-        value = self.removeWidget(value, item[0]);
-      }, this);
-    }
-    if (toAdd.length) {
-      value.visible = value.visible.concat(toAdd);
-      var allThreshold = this.get('initPrefObject').threshold;
-      // add new threshold OR override with default value
-      toAdd.forEach ( function (item) {
-        value.threshold[item] = allThreshold[item];
-      }, this);
-    }
-    return value;
-  },
-
-  /**
-   * Get view for widget by widget's id
-   * @param {string} id
-   * @returns {Ember.View}
-   */
-  widgetsMapper: function (id) {
-    return Em.get({
-     '1': App.NameNodeHeapPieChartView,
-     '2': App.NameNodeCapacityPieChartView,
-     '3': App.NameNodeCpuPieChartView,
-     '4': App.DataNodeUpView,
-     '5': App.NameNodeRpcView,
-     '6': App.JobTrackerHeapPieChartView,
-     '7': App.JobTrackerCpuPieChartView,
-     '8': App.TaskTrackerUpView,
-     '9': App.JobTrackerRpcView,
-     '10': App.MapReduceSlotsView,
-     '11': App.ChartClusterMetricsMemoryWidgetView,
-     '12': App.ChartClusterMetricsNetworkWidgetView,
-     '13': App.ChartClusterMetricsCPUWidgetView,
-     '14': App.ChartClusterMetricsLoadWidgetView,
-     '15': App.NameNodeUptimeView,
-     '16': App.JobTrackerUptimeView,
-     '17': App.HDFSLinksView,
-     '18': App.MapReduceLinksView,
-     '19': App.HBaseLinksView,
-     '20': App.HBaseMasterHeapPieChartView,
-     '21': App.HBaseAverageLoadView,
-     '22': App.HBaseRegionsInTransitionView,
-     '23': App.HBaseMasterUptimeView,
-     '24': App.ResourceManagerHeapPieChartView,
-     '25': App.ResourceManagerUptimeView,
-     '26': App.NodeManagersLiveView,
-     '27': App.YARNMemoryPieChartView,
-     '28': App.SuperVisorUpView,
-     '29': App.FlumeAgentUpView
-    }, id);
-  },
-
-  /**
-   * @type {Object|null}
-   */
-  currentPrefObject: null,
-
-  /**
-   * @type {Ember.Object}
-   */
-  initPrefObject: Em.Object.create({
-    dashboardVersion: 'new',
-    visible: [],
-    hidden: [],
-    threshold: {1: [80, 90], 2: [85, 95], 3: [90, 95], 4: [80, 90], 5: [1000, 3000], 6: [70, 90], 7: [90, 95], 8: [50, 75], 9: [30000, 120000],
-      10: [], 11: [], 12: [], 13: [], 14: [], 15: [], 16: [], 17: [], 18: [], 19: [], 20: [70, 90], 21: [10, 19.2], 22: [3, 10], 23: [],
-      24: [70, 90], 25: [], 26: [50, 75], 27: [50, 75], 28: [85, 95], 29: [85, 95]} // id:[thresh1, thresh2]
-  }),
-
-  /**
-   * Key-name to store data in Local Storage and Persist
-   * @type {string}
-   */
-  persistKey: function () {
-    return 'user-pref-' + App.router.get('loginName') + '-dashboard';
-  }.property(),
-
-  makeRequestAsync: false,
-
-  getUserPrefSuccessCallback: function (response, request, data) {
-    if (response) {
-      console.log('Got persist value from server with key ' + data.key + '. Value is: ' + response);
-      this.set('currentPrefObject', response);
-    }
-  },
-
-  getUserPrefErrorCallback: function (request) {
-    // this user is first time login
-    if (request.status == 404) {
-      console.log('Persist did NOT find the key');
-    }
-  },
-
-  /**
-   * Reset widgets visibility-status
-   */
-  resetAllWidgets: function() {
-    var self = this;
-    App.showConfirmationPopup(function() {
-      if(!App.testMode) {
-        self.postUserPref(self.get('persistKey'), self.get('initPrefObject'));
-        self.setDBProperty(self.get('persistKey'), self.get('initPrefObject'));
-      }
-      self.translateToReal(self.get('initPrefObject'));
-    });
-  },
-
-  /**
-   * @type {string}
-   */
-  gangliaUrl: function () {
-    return App.router.get('clusterController.gangliaUrl') + "/?r=hour&cs=&ce=&m=&s=by+name&c=HDPSlaves&tab=m&vn=";
-  }.property('App.router.clusterController.gangliaUrl'),
-
-  showAlertsPopup: function (event) {
-    var service = event.context;
-    App.router.get('mainAlertsController').loadAlerts(service.get('serviceName'), "SERVICE");
-    App.ModalPopup.show({
-      header: this.t('services.alerts.headingOfList'),
-      bodyClass: Ember.View.extend({
-        templateName: require('templates/main/dashboard/alert_notification_popup'),
-        service: service,
-        controllerBinding: 'App.router.mainAlertsController',
-        warnAlerts: function () {
-          return this.get('controller.alerts').filterProperty('isOk', false).filterProperty('ignoredForServices', false);
-        }.property('controller.alerts'),
-
-        warnAlertsCount: function () {
-          return this.get('warnAlerts').length;
-        }.property('warnAlerts'),
-
-        warnAlertsMessage: function() {
-          return Em.I18n.t('services.alerts.head').format(this.get('warnAlertsCount'));
-        }.property('warnAlertsCount'),
-
-        nagiosUrl: function () {
-          return App.router.get('clusterController.nagiosUrl');
-        }.property('App.router.clusterController.nagiosUrl'),
-
-        closePopup: function () {
-          this.get('parentView').hide();
-        },
-
-        viewNagiosUrl: function () {
-          window.open(this.get('nagiosUrl'), "_blank");
-          this.closePopup();
-        },
-
-        selectService: function () {
-          App.router.transitionTo('services.service.summary', service);
-          this.closePopup();
-        }
-      }),
-      primary: Em.I18n.t('common.close'),
-      secondary : null,
-      didInsertElement: function () {
-        this.$().find('.modal-footer').addClass('align-center');
-        this.$().children('.modal').css({'margin-top': '-350px'});
-      }
-    });
-    event.stopPropagation();
-  }
-
-});
+  templateName: require('templates/main/dashboard'),
+
+  selectedBinding: 'controller.selectedCategory',
+  categories: function() {
+    var items = [{
+      name: 'widgets',
+      url: 'dashboard.index',
+      label: Em.I18n.t('dashboard.widgets.title'),
+      isActive: function () {
+        debugger;
+        return 'widgets' === this.get('selected');
+      }.property('selected')
+    },
+    {
+      name: 'charts',
+      url: 'dashboard.charts',
+      label: Em.I18n.t('dashboard.heatmaps.title'),
+      isActive: function () {
+        debugger;
+        return 'charts' === this.get('selected');
+      }.property('selected')
+    }];
+    return items;
+  }.property(''),
+  NavItemView: Ember.View.extend({
+    tagName: 'li',
+    classNameBindings: 'isActive:active'.w(),
+    isActive: function () {
+      return this.get('item') === this.get('parentView.selected');
+    }.property('item', 'parentView.selected')
+  })
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/bbde993b/ambari-web/app/views/main/menu.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/menu.js b/ambari-web/app/views/main/menu.js
index c2a4e21..ef27e2a 100644
--- a/ambari-web/app/views/main/menu.js
+++ b/ambari-web/app/views/main/menu.js
@@ -24,7 +24,7 @@ var App = require('app');
  */
 App.MainMenuView = Em.CollectionView.extend({
   tagName:'ul',
-  classNames:['nav'],
+  classNames:['nav', 'top-nav-menu'],
 
   views: function() {
     return App.router.get('clusterController.ambariViews');
@@ -33,7 +33,6 @@ App.MainMenuView = Em.CollectionView.extend({
   content:function(){
     var result = [
       { label:Em.I18n.t('menu.item.dashboard'), routing:'dashboard', active:'active'},
-      { label:Em.I18n.t('menu.item.heatmaps'), routing:'charts'},
       { label:Em.I18n.t('menu.item.services'), routing:'services'},
       { label:Em.I18n.t('menu.item.hosts'), routing:'hosts'}
     ];
@@ -84,7 +83,7 @@ App.MainMenuView = Em.CollectionView.extend({
 
   itemViewClass:Em.View.extend({
 
-    classNameBindings:['active', ':span2'],
+    classNameBindings:['active', ':top-nav-dropdown'],
     active:'',
 
     alertsCount:function () {
@@ -94,6 +93,74 @@ App.MainMenuView = Em.CollectionView.extend({
       }
     }.property('App.router.mainHostController.content.@each.criticalAlertsCount'),
 
-    templateName: require('templates/main/menu_item')
+    templateName: require('templates/main/menu_item'),
+
+    dropdownMenu: function () {
+      var item = this.get('content').routing;
+      var itemsWithDropdown = ['services', 'admin', 'views'];
+      return itemsWithDropdown.contains(item);
+    }.property(''),
+    isAdminItem: function () {
+      return this.get('content').routing == 'admin';
+    }.property(''),
+    isServicesItem: function () {
+      return this.get('content').routing == 'services';
+    }.property(''),
+    isViewsItem: function () {
+      return this.get('content').routing == 'views';
+    }.property(''),
+    goToCategory: function (event) {
+      //App.router.transitionTo('admin.service.summary', service);
+      var itemName = this.get('content').routing;
+      // route to correct category of current menu item
+      if (itemName == 'admin') {
+        App.router.transitionTo('admin.' + event.context);
+      }
+    },
+    dropdownCategories: function () {
+      var itemName = this.get('content').routing;
+      var categories = [];
+      // create dropdown categories for each menu item
+      if (itemName == 'admin') {
+        categories = [{
+          name: 'user',
+          url: 'adminUser',
+          label: Em.I18n.t('common.users')
+        }];
+        if (App.get('isHadoop2Stack') && App.supports.highAvailability) {
+          categories.push({
+            name: 'highAvailability',
+            url: 'adminHighAvailability',
+            label: Em.I18n.t('admin.highAvailability')
+          });
+        }
+        if (App.supports.secureCluster) {
+          categories.push({
+            name: 'security',
+            url: 'adminSecurity.index',
+            label: Em.I18n.t('common.security')
+          });
+        }
+        categories.push({
+          name: 'cluster',
+          url: 'adminCluster',
+          label: Em.I18n.t('common.cluster')
+        });
+        categories.push({
+          name: 'misc',
+          url: 'adminMisc',
+          label: Em.I18n.t('common.misc')
+        });
+        if (App.router.get('mainAdminController.isAccessAvailable')) {
+          categories.push({
+            name: 'access',
+            url: 'adminAccess',
+            label: Em.I18n.t('common.access')
+          });
+        }
+      }
+      return categories;
+
+    }.property('')
   })
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/bbde993b/ambari-web/app/views/main/service/menu.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/menu.js b/ambari-web/app/views/main/service/menu.js
index 6247c44..de81134 100644
--- a/ambari-web/app/views/main/service/menu.js
+++ b/ambari-web/app/views/main/service/menu.js
@@ -53,7 +53,94 @@ App.MainServiceMenuView = Em.CollectionView.extend({
   },
 
   tagName:'ul',
-  classNames:["nav", "nav-list", "nav-services"],
+  classNames:[ "nav", "nav-list", "nav-services"],
+
+  itemViewClass:Em.View.extend({
+
+    classNameBindings:["active", "clients"],
+    templateName:require('templates/main/service/menu_item'),
+    restartRequiredMessage: null,
+
+    shouldBeRestarted: function() {
+      return this.get('content.hostComponents').someProperty('staleConfigs', true);
+    }.property('content.hostComponents.@each.staleConfigs'),
+
+    active:function () {
+      return this.get('content.id') == this.get('parentView.activeServiceId') ? 'active' : '';
+    }.property('parentView.activeServiceId'),
+
+    alertsCount: function () {
+      return this.get('content.criticalAlertsCount');
+    }.property('content.criticalAlertsCount'),
+
+    link: function() {
+      var stateName = (['summary','configs'].contains(App.router.get('currentState.name')))
+        ? this.get('content.isConfigurable') ?  App.router.get('currentState.name') : 'summary'
+        : 'summary';
+      return "#/main/services/" + this.get('content.id') + "/" + stateName;
+    }.property('App.router.currentState.name', 'parentView.activeServiceId'),
+
+    refreshRestartRequiredMessage: function() {
+      var restarted, componentsCount, hostsCount, message, tHosts, tComponents;
+      restarted = this.get('content.restartRequiredHostsAndComponents');
+      componentsCount = 0;
+      hostsCount = 0;
+      message = "";
+      for (var host in restarted) {
+        hostsCount++;
+        componentsCount += restarted[host].length;
+      }
+      if (hostsCount > 1) {
+        tHosts = Em.I18n.t('common.hosts');
+      } else {
+        tHosts = Em.I18n.t('common.host');
+      }
+      if (componentsCount > 1) {
+        tComponents = Em.I18n.t('common.components');
+      } else {
+        tComponents = Em.I18n.t('common.component');
+      }
+      message += componentsCount + ' ' + tComponents + ' ' + Em.I18n.t('on') + ' ' +
+        hostsCount + ' ' + tHosts + ' ' + Em.I18n.t('services.service.config.restartService.needToRestartEnd');
+      this.set('restartRequiredMessage', message);
+    }.observes('content.restartRequiredHostsAndComponents')
+  })
+
+});
+
+App.TopNavServiceMenuView = Em.CollectionView.extend({
+  disabledServices: ['HCATALOG'],
+
+  content:function () {
+    var items = App.router.get('mainServiceController.content').filter(function(item){
+      return !this.get('disabledServices').contains(item.get('id'));
+    }, this);
+    return misc.sortByOrder(App.Service.servicesSortOrder, items);
+  }.property('App.router.mainServiceController.content', 'App.router.mainServiceController.content.length'),
+
+  didInsertElement:function () {
+    App.router.location.addObserver('lastSetURL', this, 'renderOnRoute');
+    this.renderOnRoute();
+    App.tooltip($(".restart-required-service"), {html:true, placement:"right"});
+  },
+
+  activeServiceId:null,
+  /**
+   *    Syncs navigation menu with requested URL
+   */
+  renderOnRoute:function () {
+    var last_url = App.router.location.lastSetURL || location.href.replace(/^[^#]*#/, '');
+    if (last_url.substr(1, 4) !== 'main' || !this._childViews) {
+      return;
+    }
+    var reg = /^\/main\/services\/(\S+)\//g;
+    var sub_url = reg.exec(last_url);
+    var service_id = (null != sub_url) ? sub_url[1] : 1;
+    this.set('activeServiceId', service_id);
+  },
+
+  tagName:'ul',
+  classNames:[ "top-nav-dropdown-menu"],
 
   itemViewClass:Em.View.extend({
 


Mime
View raw message