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 <[email protected]> Authored: Fri Apr 18 14:41:47 2014 -0700 Committer: Yusaku Sako <[email protected]> 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('[email protected]'), - 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('[email protected]'), + + 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({
