You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by yu...@apache.org on 2014/04/18 23:42:26 UTC
git commit: AMBARI-5504. Views: Ambari Web Layout Update. (xiwang via
yusaku)
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 <yu...@hortonworks.com>
Authored: Fri Apr 18 14:41:47 2014 -0700
Committer: Yusaku Sako <yu...@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}} <span class="caret"></span>
+ <div class="top-nav-user btn-group">
+ <button class="btn dropdown-toggle" data-toggle="dropdown">
+ <i class="icon-user"></i> {{App.router.loginName}} <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>
- <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({