AMBARI-20316. Move breadcrumbs to the separated view (onechiporenko)

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

Branch: refs/heads/branch-feature-AMBARI-12556
Commit: f7e7c8bb331d92997d547e6717ee1f3fdbefc6a8
Parents: 3d95dd6
Author: Oleg Nechiporenko <onechipore...@apache.org>
Authored: Mon Mar 6 14:58:54 2017 +0200
Committer: Oleg Nechiporenko <onechipore...@apache.org>
Committed: Mon Mar 6 16:30:14 2017 +0200

----------------------------------------------------------------------
 ambari-web/app/assets/test/tests.js             |   1 +
 ambari-web/app/routes/main.js                   |  78 ++++++++
 ambari-web/app/routes/view.js                   |   5 +
 ambari-web/app/routes/views.js                  |   7 +
 ambari-web/app/templates/application.hbs        |   8 +-
 ambari-web/app/templates/common/breadcrumbs.hbs |  24 +++
 ambari-web/app/views.js                         |   1 +
 ambari-web/app/views/application.js             | 106 +----------
 ambari-web/app/views/common/breadcrumbs_view.js | 190 +++++++++++++++++++
 .../test/controllers/main/service/item_test.js  |  19 +-
 .../test/views/common/breadcrumbs_view_test.js  |  37 ++++
 11 files changed, 359 insertions(+), 117 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/f7e7c8bb/ambari-web/app/assets/test/tests.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/assets/test/tests.js 
b/ambari-web/app/assets/test/tests.js
index 308edcd..ab007f0 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -236,6 +236,7 @@ var files = [
   'test/utils/configs/modification_handlers/misc_test',
   'test/utils/load_timer_test',
   'test/utils/configs/theme/theme_test',
+  'test/views/common/breadcrumbs_view_test',
   'test/views/common/chart/linear_time_test',
   'test/views/common/configs/widgets/combo_config_widget_view_test',
   'test/views/common/configs/widgets/config_widget_view_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/f7e7c8bb/ambari-web/app/routes/main.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/main.js b/ambari-web/app/routes/main.js
index 4460442..4607033 100644
--- a/ambari-web/app/routes/main.js
+++ b/ambari-web/app/routes/main.js
@@ -18,7 +18,19 @@
 
 var App = require('app');
 
+function getPostFormatLabel(parent) {
+  return function (label) {
+    return `${parent} - ${label}`;
+  }
+}
+
 module.exports = Em.Route.extend(App.RouterRedirections, {
+
+  breadcrumbs: {
+    label: '<span class="glyphicon glyphicon-home"></span>',
+    route: 'dashboard'
+  },
+
   route: '/main',
   enter: function (router) {
     App.db.updateStorage();
@@ -111,6 +123,12 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
   }),
 
   dashboard: Em.Route.extend({
+
+    breadcrumbs: {
+      label: Em.I18n.t('menu.item.dashboard'),
+      route: 'dashboard'
+    },
+
     route: '/dashboard',
     connectOutlets: function (router, context) {
       router.get('mainController').connectOutlet('mainDashboard');
@@ -191,6 +209,15 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
 
 
   hosts: Em.Route.extend({
+
+    breadcrumbs: {
+      label: Em.I18n.t('menu.item.hosts'),
+      route: 'hosts',
+      beforeTransition() {
+        App.router.set('mainHostController.showFilterConditionsFirstLoad', 
false);
+      }
+    },
+
     route: '/hosts',
     index: Ember.Route.extend({
       route: '/',
@@ -202,6 +229,12 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
     }),
 
     hostDetails: Em.Route.extend({
+
+      breadcrumbs: {
+        labelBindingPath: 
'App.router.mainHostDetailsController.content.hostName',
+        disabled: true
+      },
+
       route: '/:host_id',
       connectOutlets: function (router, host) {
         router.get('mainHostController').set('showFilterConditionsFirstLoad', 
true);
@@ -325,6 +358,15 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
   hostAdd: require('routes/add_host_routes'),
 
   alerts: Em.Route.extend({
+
+    breadcrumbs: {
+      label: Em.I18n.t('menu.item.alerts'),
+      route: 'alerts',
+      beforeTransition() {
+        
App.router.set('mainAlertDefinitionsController.showFilterConditionsFirstLoad', 
false);
+      }
+    },
+
     route: '/alerts',
     index: Em.Route.extend({
       route: '/',
@@ -335,6 +377,11 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
 
     alertDetails: Em.Route.extend({
 
+      breadcrumbs: {
+        labelBindingPath: 
'App.router.mainAlertDefinitionDetailsController.content.label',
+        disabled: true
+      },
+
       route: '/:alert_definition_id',
 
       connectOutlets: function (router, alertDefinition) {
@@ -401,6 +448,12 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
     }),
 
     adminKerberos: Em.Route.extend({
+
+      breadcrumbs: {
+        label: Em.I18n.t('common.kerberos'),
+        labelPostFormat: getPostFormatLabel('Admin')
+      },
+
       route: '/kerberos',
       enter: function (router, transition) {
         if (router.get('loggedIn') && 
!App.isAuthorized('CLUSTER.TOGGLE_KERBEROS')) {
@@ -519,6 +572,12 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
       }),
 
       services: Em.Route.extend({
+
+        breadcrumbs: {
+          label: Em.I18n.t('admin.stackUpgrade.title'),
+          labelPostFormat: getPostFormatLabel('Admin')
+        },
+
         route: '/services',
         connectOutlets: function (router, context) {
           
router.get('mainAdminStackAndUpgradeController').connectOutlet('mainAdminStackServices');
@@ -556,6 +615,12 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
       }
     }),
     adminServiceAccounts: Em.Route.extend({
+
+      breadcrumbs: {
+        label: Em.I18n.t('common.serviceAccounts'),
+        labelPostFormat: getPostFormatLabel('Admin')
+      },
+
       route: '/serviceAccounts',
       enter: function (router, transition) {
         if (router.get('loggedIn') && 
!App.isAuthorized('SERVICE.SET_SERVICE_USERS_GROUPS')) {
@@ -570,6 +635,12 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
     }),
 
     adminServiceAutoStart: Em.Route.extend({
+
+      breadcrumbs: {
+        label: Em.I18n.t('admin.serviceAutoStart.title'),
+        labelPostFormat: getPostFormatLabel('Admin')
+      },
+
       route: '/serviceAutoStart',
       enter: function(router, transition) {
         if (router.get('loggedIn') && 
!App.isAuthorized('CLUSTER.MANAGE_AUTO_START') && 
!App.isAuthorized('CLUSTER.MANAGE_AUTO_START')) {
@@ -653,6 +724,13 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
   editWidget: require('routes/edit_widget'),
 
   services: Em.Route.extend({
+
+    breadcrumbs: {
+      labelBindingPath: 
'App.router.mainServiceItemController.content.displayName',
+      labelPostFormat: getPostFormatLabel('Service'),
+      disabled: true
+    },
+
     route: '/services',
     index: Em.Route.extend({
       route: '/',

http://git-wip-us.apache.org/repos/asf/ambari/blob/f7e7c8bb/ambari-web/app/routes/view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/view.js b/ambari-web/app/routes/view.js
index 50d8f4b..22a4057 100644
--- a/ambari-web/app/routes/view.js
+++ b/ambari-web/app/routes/view.js
@@ -19,6 +19,11 @@
 var App = require('app');
 
 module.exports = Em.Route.extend({
+
+  breadcrumbs: {
+    labelBindingPath: 'App.router.mainViewsDetailsController.content.label'
+  },
+
   route: '/view',
   enter: function (router) {
     Em.$('body').addClass('contribview');

http://git-wip-us.apache.org/repos/asf/ambari/blob/f7e7c8bb/ambari-web/app/routes/views.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/views.js b/ambari-web/app/routes/views.js
index 88b1251..073507c 100644
--- a/ambari-web/app/routes/views.js
+++ b/ambari-web/app/routes/views.js
@@ -19,6 +19,13 @@
 var App = require('app');
 
 module.exports = Em.Route.extend({
+
+  breadcrumbs: {
+    transition() {
+      App.router.route('views');
+    }
+  },
+
   route: '/views',
   enter: function (router) {
     router.get('mainViewsController').loadAmbariViews();

http://git-wip-us.apache.org/repos/asf/ambari/blob/f7e7c8bb/ambari-web/app/templates/application.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/application.hbs 
b/ambari-web/app/templates/application.hbs
index 9d6db78..9eab287 100644
--- a/ambari-web/app/templates/application.hbs
+++ b/ambari-web/app/templates/application.hbs
@@ -68,13 +68,7 @@
     <nav class="navbar navbar-default navbar-static-top">
       <div class="container main-container">
         <div class="navbar-header navbar-nav">
-          {{#if view.breadcrumbs.length}}
-            {{#each item in view.breadcrumbs}}
-              <span><a {{bindAttr class="item.disabled:disabled"}} {{action 
goToSection item.route target="view"}}>
-                {{{item.label}}}</a></span>
-              {{#unless item.lastItem}}&nbsp;/&nbsp;{{/unless}}
-            {{/each}}
-          {{/if}}
+          {{view App.BreadcrumbsView}}
         </div>
 
         {{! right offset. don't delete me! }}

http://git-wip-us.apache.org/repos/asf/ambari/blob/f7e7c8bb/ambari-web/app/templates/common/breadcrumbs.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/common/breadcrumbs.hbs 
b/ambari-web/app/templates/common/breadcrumbs.hbs
new file mode 100644
index 0000000..89353d9
--- /dev/null
+++ b/ambari-web/app/templates/common/breadcrumbs.hbs
@@ -0,0 +1,24 @@
+{{!
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+}}
+
+{{#each item in view.items}}
+  <a {{bindAttr class="item.disabled:disabled"}} {{action moveTo item 
target="view"}}>
+    {{{item.formattedLabel}}}
+  </a>
+  {{#unless item.isLast}}&nbsp;/&nbsp;{{/unless}}
+{{/each}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f7e7c8bb/ambari-web/app/views.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js
index 7ec59f7..3ed1a37 100644
--- a/ambari-web/app/views.js
+++ b/ambari-web/app/views.js
@@ -20,6 +20,7 @@
 // load all views here
 
 require('views/application');
+require('views/common/breadcrumbs_view');
 require('views/common/clock_view');
 require('views/common/checkbox_view');
 require('views/common/log_search_ui_link_view');

http://git-wip-us.apache.org/repos/asf/ambari/blob/f7e7c8bb/ambari-web/app/views/application.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/application.js 
b/ambari-web/app/views/application.js
index ef9df6a..7a64584 100644
--- a/ambari-web/app/views/application.js
+++ b/ambari-web/app/views/application.js
@@ -22,111 +22,9 @@ var App = require('app');
 App.ApplicationView = Em.View.extend({
   templateName: require('templates/application'),
 
-  views: function () {

+  views: function () {
     return App.router.get('loggedIn') ? 
App.router.get('mainViewsController.visibleAmbariViews') : [];
-  
}.property('App.router.mainViewsController.visibleAmbariViews.[]', 
'App.router.loggedIn'),
-
-  /**
-   * Create the breadcrums showing on ambari top bar
-   * Eg, Home / Alerts / Metrics Monitor Status
-   * @returns {array}
-   */
-  breadcrumbs: function () {
-    var breadcrumbs = [];
-    if (App.router.get('loggedIn')) {
-      var home = {
-        label: '<span class="glyphicon glyphicon-home"></span>',
-        route: 'dashboard',
-        disabled: false
-      };
-      if (App.router.get('currentState.parentState.name') == 'dashboard') {
-        breadcrumbs.pushObject({
-          label: '<span class="glyphicon glyphicon-home"></span>&nbsp;&nbsp;' 
+  Em.I18n.t('menu.item.dashboard'),
-          disabled: true,
-          lastItem: true
-        });
-      } else if (App.router.get('currentState.parentState.name') == 'hosts') {
-        breadcrumbs.pushObject(home);
-        breadcrumbs.pushObject({
-          label: Em.I18n.t('menu.item.hosts'),
-          disabled: true,
-          lastItem: true
-        });
-      } else if (App.router.get('currentState.parentState.name') == 
'hostDetails') {
-        var hostName = 
App.router.get('mainHostDetailsController.content.hostName');
-        breadcrumbs.pushObject(home);
-        breadcrumbs.pushObject({
-          label: Em.I18n.t('menu.item.hosts'),
-          route: 'hosts',
-          disabled: false
-        });
-        breadcrumbs.pushObject({
-          label: hostName,
-          disabled: true,
-          lastItem: true
-        });
-      } else if (App.router.get('currentState.parentState.name') == 'alerts') {
-        breadcrumbs.pushObject(home);
-        if (App.router.get('currentState.name') == 'alertDetails') {
-          breadcrumbs.pushObject({
-            label: Em.I18n.t('menu.item.alerts'),
-            route: 'alerts',
-            disabled: false
-          });
-          breadcrumbs.pushObject({
-            label: 
App.router.get('mainAlertDefinitionDetailsController.content.label'),
-            disabled: true,
-            lastItem: true
-          });
-        } else {
-          breadcrumbs.pushObject({
-            label: Em.I18n.t('menu.item.alerts'),
-            disabled: true,
-            lastItem: true
-          });
-        }
-      } else if (App.router.get('currentState.parentState.name') == 'service') 
{
-        breadcrumbs.pushObject(home);
-        var serviceName = 
App.router.get('mainServiceItemController.content.displayName');
-        breadcrumbs.pushObject({
-          label: 'Service - ' + serviceName,
-          disabled: true,
-          lastItem: true
-        });
-      } else if (App.router.get('currentState.parentState.name') == 'admin'|| 
App.router.get('currentState.parentState.parentState.name') == 'admin') {
-        breadcrumbs.pushObject(home);
-        breadcrumbs.pushObject({
-          label: 'Admin - ' + 
App.router.get('mainAdminController.categoryLabel'),
-          disabled: true,
-          lastItem: true
-        });
-      } else if (App.router.get('currentState.parentState.name') == 'views') {
-        breadcrumbs.pushObject(home);
-        breadcrumbs.pushObject({
-          label: App.router.get('mainViewsDetailsController.content.label'),
-          disabled: true,
-          lastItem: true
-        });
-      }
-    }
-    return breadcrumbs;
-
-  }.property('App.router.loggedIn', 'App.router.currentState.parentState.name',
-      'App.router.mainHostDetailsController.content.hostName', 
'App.router.mainAlertDefinitionDetailsController.content.label',
-      'App.router.mainServiceItemController.content.displayName', 
'App.router.mainAdminController.categoryLabel', 
'App.router.mainViewsDetailsController.content.label'),
-
-  goToSection: function (event) {
-    if (!event.context) return;
-    if (event.context === 'hosts') {
-      App.router.set('mainHostController.showFilterConditionsFirstLoad', 
false);
-    } else if (event.context === 'views') {
-      App.router.route('views');
-      return;
-    } else if (event.context === 'alerts') {
-      
App.router.set('mainAlertDefinitionsController.showFilterConditionsFirstLoad', 
false);
-    }
-    App.router.route('main/' + event.context);
-  },
+  }.property('App.router.mainViewsController.visibleAmbariViews.[]', 
'App.router.loggedIn'),
 
   didInsertElement: function () {
     // on 'Enter' pressed, trigger modal window primary button if primary 
button is enabled(green)

http://git-wip-us.apache.org/repos/asf/ambari/blob/f7e7c8bb/ambari-web/app/views/common/breadcrumbs_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/common/breadcrumbs_view.js 
b/ambari-web/app/views/common/breadcrumbs_view.js
new file mode 100644
index 0000000..f9073ba
--- /dev/null
+++ b/ambari-web/app/views/common/breadcrumbs_view.js
@@ -0,0 +1,190 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+
+function _getLabelPathWithoutApp(labelBindingPath) {
+  return labelBindingPath.startsWith('App.') ? 
labelBindingPath.replace('App.', '') : labelBindingPath;
+}
+
+/**
+ * Don't create instances directly
+ * Only <code>App.BreadcrumbsView</code>-instance will create them
+ *
+ * @type {Em.Object}
+ */
+App.BreadcrumbItem = Em.Object.extend({
+
+  /**
+   * String shown as breadcrumb
+   *
+   * @type {string}
+   */
+  label: '',
+
+  /**
+   * Path to variable that will be used as breadcrumb
+   * If <code>labelBindingPath</code> is <code>'App.router.somePath'</code>, 
its value will be used
+   *
+   * @type {string}
+   */
+  labelBindingPath: '',
+
+  /**
+   * Determines if breadcrumb is disabled
+   *
+   * @type {boolean}
+   */
+  disabled: false,
+
+  /**
+   * Check if current breadcrumb is last
+   *
+   * @type {boolean}
+   */
+  isLast: false,
+
+  /**
+   * Move user to this route when click on breadcrumb item (don't add prefix 
<code>main</code>)
+   *
+   * @type {string}
+   */
+  route: '',
+
+  /**
+   * Hook executed before transition
+   * may be overridden when needed
+   *
+   * @type {Function}
+   */
+  beforeTransition: Em.K,
+
+  /**
+   * Hook executed after transition
+   * may be overridden when needed
+   *
+   * @type {Function}
+   */
+  afterTransition: Em.K,
+
+  /**
+   * Label shown on the page
+   * Result of <code>createLabel</code> execution
+   *
+   * @type {string}
+   */
+  formattedLabel: '',
+
+  /**
+   * Hook for label formatting
+   * It's executed after <code>label</code> or <code>labelBindingPath</code> 
is processed
+   *
+   * @param {string} label
+   * @returns {string}
+   */
+  labelPostFormat: function (label) {
+    return label;
+  },
+
+  transition: function () {
+    return App.router.route('main/' + this.get('route'));
+  },
+
+  /**
+   * Generate <code>formattedLabel</code> shown on the page
+   *
+   * @method createLabel
+   */
+  createLabel() {
+    let label = this.get('label');
+    let labelBindingPath = this.get('labelBindingPath');
+
+    let formattedLabel = labelBindingPath ? 
App.get(_getLabelPathWithoutApp(labelBindingPath)) : label;
+    this.set('formattedLabel', this.labelPostFormat(formattedLabel));
+  },
+
+  /**
+   * If <code>labelBindingPath</code> is provided, <code>createLabel</code> 
should observe value in path <code>${labelBindingPath}</code>
+   *
+   * @returns {*}
+   */
+  init() {
+    let labelBindingPath = this.get('labelBindingPath');
+    if (labelBindingPath) {
+      labelBindingPath = `App.${_getLabelPathWithoutApp(labelBindingPath)}`;
+      this.addObserver(labelBindingPath, this, 'createLabel');
+    }
+    this.createLabel();
+    return this._super(...arguments);
+  }
+
+});
+
+/**
+ * Usage:
+ * <code>{{view App.BreadcrumbsView}}</code>
+ *
+ * @type {Em.View}
+ */
+App.BreadcrumbsView = Em.View.extend({
+
+  templateName: require('templates/common/breadcrumbs'),
+
+  /**
+   * List of the breadcrumbs
+   * It's updated if <code>App.router.currentState</code> is changed. This 
happens when user is moved from one page to another
+   *
+   * @type {BreadcrumbItem[]}
+   */
+  items: function () {
+    let currentState = App.get('router.currentState');
+    let items = [];
+    while (currentState) {
+      if (currentState.breadcrumbs) {
+        items.pushObject(currentState.breadcrumbs);
+      }
+      currentState = currentState.get('parentState');
+    }
+    items = items.reverse().map(item => 
App.BreadcrumbItem.extend(item).create());
+    if (items.length) {
+      items.get('lastObject').setProperties({
+        disabled: true,
+        isLast: true
+      });
+    }
+    return items;
+  }.property('App.router.currentState'),
+
+  /**
+   * Move user to the route described in the breadcrumb item
+   * <code>beforeTransition</code> hook is executed
+   *
+   * @param {{context: App.BreadcrumbItem}} event
+   * @returns {*}
+   */
+  moveTo(event) {
+    let item = event.context;
+    if (!item || item.get('disabled')) {
+      return;
+    }
+    Em.tryInvoke(item, 'beforeTransition');
+    Em.tryInvoke(item, 'transition');
+    Em.tryInvoke(item, 'afterTransition');
+  }
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/f7e7c8bb/ambari-web/test/controllers/main/service/item_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/service/item_test.js 
b/ambari-web/test/controllers/main/service/item_test.js
index e33ecaa..c4a50ea 100644
--- a/ambari-web/test/controllers/main/service/item_test.js
+++ b/ambari-web/test/controllers/main/service/item_test.js
@@ -1926,8 +1926,10 @@ describe('App.MainServiceItemController', function () {
   describe('#applyRecommendedValues', function () {
 
     var controller;
+    var configsS1;
+    var configsS2;
 
-    beforeEach(function () {
+      beforeEach(function () {
       controller = App.MainServiceItemController.create({
         stepConfigs: [
           Em.Object.create({
@@ -1983,12 +1985,17 @@ describe('App.MainServiceItemController', function () {
       });
     });
 
-    it('should update properties with saveRecommended flag set to true', 
function () {
+    beforeEach(function () {
       controller.applyRecommendedValues(controller.get('stepConfigs'));
-      expect(controller.get('stepConfigs').findProperty('serviceName', 
's1').get('configs').findProperty('name', 'p1').get('value')).to.equal('i1');
-      expect(controller.get('stepConfigs').findProperty('serviceName', 
's1').get('configs').findProperty('name', 'p2').get('value')).to.equal('r2');
-      expect(controller.get('stepConfigs').findProperty('serviceName', 
's2').get('configs').findProperty('name', 'p3').get('value')).to.equal('r3');
-      expect(controller.get('stepConfigs').findProperty('serviceName', 
's2').get('configs').findProperty('name', 'p4').get('value')).to.equal('v4');
+      configsS1 = controller.get('stepConfigs').findProperty('serviceName', 
's1').get('configs');
+      configsS2 = controller.get('stepConfigs').findProperty('serviceName', 
's2').get('configs');
+    });
+
+    it('should update properties with saveRecommended flag set to true', 
function () {
+      expect(configsS1.findProperty('name', 'p1').get('value')).to.equal('i1');
+      expect(configsS1.findProperty('name', 'p2').get('value')).to.equal('r2');
+      expect(configsS2.findProperty('name', 'p3').get('value')).to.equal('r3');
+      expect(configsS2.findProperty('name', 'p4').get('value')).to.equal('v4');
     });
 
   });

http://git-wip-us.apache.org/repos/asf/ambari/blob/f7e7c8bb/ambari-web/test/views/common/breadcrumbs_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/common/breadcrumbs_view_test.js 
b/ambari-web/test/views/common/breadcrumbs_view_test.js
new file mode 100644
index 0000000..751811c
--- /dev/null
+++ b/ambari-web/test/views/common/breadcrumbs_view_test.js
@@ -0,0 +1,37 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+describe('App.BreadcrumbItem', function () {
+
+  describe('#createLabel', function () {
+
+    describe('#labelBindingPath', function () {
+
+      beforeEach(function () {
+        this.breadcrumb = App.BreadcrumbItem.create({labelBindingPath: 
'App.router.somePath'});
+      });
+
+      it('Observer is added', function () {
+        
expect(Em.meta(this.breadcrumb).listeners).to.have.property('App.router.somePath:change');
+      });
+
+    });
+
+  });
+
+});
\ No newline at end of file

Reply via email to