ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From onechipore...@apache.org
Subject ambari git commit: AMBARI-9871. Need to adjust UI for HDP 2.0/2.1 Stacks with versions (onechiporenko)
Date Mon, 02 Mar 2015 17:23:47 GMT
Repository: ambari
Updated Branches:
  refs/heads/trunk a42b6894e -> 70b912c6a


AMBARI-9871. Need to adjust UI for HDP 2.0/2.1 Stacks with versions (onechiporenko)


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

Branch: refs/heads/trunk
Commit: 70b912c6a441ad3dff091554d8b2872290d2bb28
Parents: a42b689
Author: Oleg Nechiporenko <onechiporenko@apache.org>
Authored: Mon Mar 2 18:44:49 2015 +0200
Committer: Oleg Nechiporenko <onechiporenko@apache.org>
Committed: Mon Mar 2 18:44:49 2015 +0200

----------------------------------------------------------------------
 .../app/scripts/controllers/NavbarCtrl.js       |  10 +-
 .../ui/admin-web/app/views/leftNavbar.html      |   2 +-
 ambari-web/app/assets/test/tests.js             |   2 +
 ambari-web/app/config.js                        |   2 +
 .../controllers/global/cluster_controller.js    |   3 +
 .../main/admin/stack_and_upgrade_controller.js  |  57 ++++-
 ambari-web/app/routes/main.js                   |   7 +-
 ambari-web/app/styles/stack_versions.less       | 113 ++++++++++
 .../main/admin/stack_upgrade/services.hbs       |  78 ++++++-
 ambari-web/app/templates/main/host.hbs          |   6 +-
 .../views/main/admin/stack_upgrade/menu_view.js |  29 +--
 .../main/admin/stack_upgrade/services_view.js   | 218 +++++++++++++++++++
 ambari-web/app/views/main/host/menu.js          |  64 +++---
 .../main/admin/stack_upgrade/menu_view_test.js  |  56 +++++
 ambari-web/test/views/main/host/menu_test.js    |  71 ++++++
 15 files changed, 665 insertions(+), 53 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/70b912c6/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/NavbarCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/NavbarCtrl.js
b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/NavbarCtrl.js
index f44a10f..2f33ae4 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/NavbarCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/NavbarCtrl.js
@@ -18,8 +18,9 @@
 'use strict';
 
 angular.module('ambariAdminConsole')
-.controller('NavbarCtrl',['$scope', 'Cluster', '$location', 'Alert', 'ROUTES', 'ConfirmationModal',
'$rootScope', function($scope, Cluster, $location, Alert, ROUTES, ConfirmationModal, $rootScope)
{
+.controller('NavbarCtrl',['$scope', 'Cluster', '$location', 'Alert', 'ROUTES', 'ConfirmationModal',
'$rootScope', 'Stack', function($scope, Cluster, $location, Alert, ROUTES, ConfirmationModal,
$rootScope, Stack) {
   $scope.cluster = null;
+  $scope.totalRepos = 0;
   $scope.editCluster = {
     name        : '',
     editingName : false
@@ -28,6 +29,13 @@ angular.module('ambariAdminConsole')
   function loadClusterData() {
     Cluster.getStatus().then(function (cluster) {
       $scope.cluster = cluster;
+      Stack.allRepos({version: '',
+        cluster: {
+          options: [],
+          current: null
+        }}, {}).then(function (repos) {
+          $scope.totalRepos = repos.itemTotal;
+        });
       if (cluster && cluster.Clusters.provisioning_state === 'INIT') {
         setTimeout(loadClusterData, 1000);
       }

http://git-wip-us.apache.org/repos/asf/ambari/blob/70b912c6/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html
index c332f80..4795ec8 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/leftNavbar.html
@@ -69,7 +69,7 @@
           <li><p class="noclusters">No clusters</p></li>
         </ul>
       </div>
-      <ul class="nav nav-pills nav-stacked" ng-show="cluster">
+      <ul class="nav nav-pills nav-stacked" ng-show="cluster && totalRepos >
0">
         <li ng-class="{active: isActive('stackVersions.list')}">
           <a href="#/stackVersions">Versions</a>
         </li>

http://git-wip-us.apache.org/repos/asf/ambari/blob/70b912c6/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 15730a1..ce137ea 100644
--- a/ambari-web/app/assets/test/tests.js
+++ b/ambari-web/app/assets/test/tests.js
@@ -179,6 +179,7 @@ var files = ['test/init_model_test',
   'test/views/main/admin/stack_upgrade/upgrade_wizard_view_test',
   'test/views/main/admin/stack_upgrade/version_view_test',
   'test/views/main/admin/stack_upgrade/services_view_test',
+  'test/views/main/admin/stack_upgrade/menu_view_test',
   'test/views/main/dashboard/config_history_view_test',
   'test/views/main/dashboard/widget_test',
   'test/views/main/dashboard/widgets_test',
@@ -197,6 +198,7 @@ var files = ['test/init_model_test',
   'test/views/main/dashboard/widgets/namenode_cpu_test',
   'test/views/main/host/details_test',
   'test/views/main/host/summary_test',
+  'test/views/main/host/menu_test',
   'test/views/main/host/stack_versions_view_test',
   'test/views/main/host/details/host_component_view_test',
   'test/views/main/host/details/host_component_views/decommissionable_test',

http://git-wip-us.apache.org/repos/asf/ambari/blob/70b912c6/ambari-web/app/config.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/config.js b/ambari-web/app/config.js
index 235f57f..02bf616 100644
--- a/ambari-web/app/config.js
+++ b/ambari-web/app/config.js
@@ -56,6 +56,8 @@ App.healthStatusRed = '#ff0000';
 App.healthStatusGreen = '#5AB400';
 App.healthStatusOrange = '#FF8E00';
 
+App.stackVersionsAvailable = true;
+
 // experimental features are automatically enabled if running on brunch server
 App.enableExperimental = false;
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/70b912c6/ambari-web/app/controllers/global/cluster_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/global/cluster_controller.js b/ambari-web/app/controllers/global/cluster_controller.js
index 5ca4a0b..ba3db08 100644
--- a/ambari-web/app/controllers/global/cluster_controller.js
+++ b/ambari-web/app/controllers/global/cluster_controller.js
@@ -325,6 +325,9 @@ App.ClusterController = Em.Controller.extend({
     }
     App.router.get('mainAdminStackAndUpgradeController').initDBProperties();
     App.router.get('mainAdminStackAndUpgradeController').loadUpgradeData(true);
+    App.router.get('mainAdminStackAndUpgradeController').loadStackVersionsToModel(true).done(function
() {
+      App.set('stackVersionsAvailable', App.StackVersion.find().content.length > 0);
+    });
   },
 
   loadRootService: function () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/70b912c6/ambari-web/app/controllers/main/admin/stack_and_upgrade_controller.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/admin/stack_and_upgrade_controller.js b/ambari-web/app/controllers/main/admin/stack_and_upgrade_controller.js
index 5daa092..aad5b46 100644
--- a/ambari-web/app/controllers/main/admin/stack_and_upgrade_controller.js
+++ b/ambari-web/app/controllers/main/admin/stack_and_upgrade_controller.js
@@ -693,5 +693,60 @@ App.MainAdminStackAndUpgradeController = Em.Controller.extend(App.LocalStorage,
     var currentVersionObject = App.RepositoryVersion.find().findProperty('status', 'CURRENT');
     var versionName = currentVersionObject && currentVersionObject.get('stackVersionType');
     App.set('isStormMetricsSupported', versionName != 'HDP' || stringUtils.compareVersions(versionNumber,
'2.2.2') > -1 || !versionNumber);
-  }.observes('currentVersion.repository_version')
+  }.observes('currentVersion.repository_version'),
+
+  /**
+   * get the installed repositories of HDP from server
+   */
+  loadRepositories: function () {
+    if (App.router.get('clusterController.isLoaded')) {
+      var nameVersionCombo = App.get('currentStackVersion');
+      var stackName = nameVersionCombo.split('-')[0];
+      var stackVersion = nameVersionCombo.split('-')[1];
+      App.ajax.send({
+        name: 'cluster.load_repositories',
+        sender: this,
+        data: {
+          stackName: stackName,
+          stackVersion: stackVersion
+        },
+        success: 'loadRepositoriesSuccessCallback',
+        error: 'loadRepositoriesErrorCallback'
+      });
+    }
+  }.observes('App.router.clusterController.isLoaded'),
+
+  loadRepositoriesSuccessCallback: function (data) {
+    var allRepos = [];
+    data.items.forEach(function (os) {
+      os.repositories.forEach(function (repository) {
+        var osType = repository.Repositories.os_type;
+        var repo = Em.Object.create({
+          baseUrl: repository.Repositories.base_url,
+          osType: osType,
+          repoId: repository.Repositories.repo_id,
+          repoName : repository.Repositories.repo_name,
+          stackName : repository.Repositories.stack_name,
+          stackVersion : repository.Repositories.stack_version,
+          isFirst: false
+        });
+        var group = allRepos.findProperty('name', osType);
+        if (!group) {
+          group = {
+            name: osType,
+            repositories: []
+          };
+          repo.set('isFirst', true);
+          allRepos.push(group);
+        }
+        group.repositories.push(repo);
+      });
+    }, this);
+    allRepos.stackVersion = App.get('currentStackVersionNumber');
+    this.set('allRepos', allRepos);
+  },
+
+  loadRepositoriesErrorCallback: function (request, ajaxOptions, error) {
+    console.log('Error message is: ' + request.responseText);
+  }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/70b912c6/ambari-web/app/routes/main.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/routes/main.js b/ambari-web/app/routes/main.js
index 43dbf3c..7ad5dc3 100644
--- a/ambari-web/app/routes/main.js
+++ b/ambari-web/app/routes/main.js
@@ -240,7 +240,12 @@ module.exports = Em.Route.extend(App.RouterRedirections, {
       stackVersions: Em.Route.extend({
         route: '/stackVersions',
         connectOutlets: function (router, context) {
-          router.get('mainHostDetailsController').connectOutlet('mainHostStackVersions');
+          if (App.get('stackVersionsAvailable')) {
+            router.get('mainHostDetailsController').connectOutlet('mainHostStackVersions');
+          }
+          else {
+            router.transitionTo('summary');
+          }
         }
       }),
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/70b912c6/ambari-web/app/styles/stack_versions.less
----------------------------------------------------------------------
diff --git a/ambari-web/app/styles/stack_versions.less b/ambari-web/app/styles/stack_versions.less
index 5c54ea3..6fd2954 100644
--- a/ambari-web/app/styles/stack_versions.less
+++ b/ambari-web/app/styles/stack_versions.less
@@ -271,3 +271,116 @@
     width: 97%;
   }
 }
+
+.admin-cluster {
+  .repositories-table {
+    margin-bottom: 10px;
+    border: 1px solid #dddddd;
+    overflow: auto;
+    div {
+      float: left;
+      min-height: 1px;
+    }
+    .thead {
+      width: 100%;
+      .th {
+        font-weight: bold;
+        padding: 8px;
+      }
+      .os-th {
+        width: 10%;
+      }
+      .name-th {
+        width: 16%;
+      }
+      .url-th {
+        width: 66%;
+      }
+    }
+    .tbody {
+      width: 100%;
+      .trow {
+        width: 100%;
+        border-top: 1px solid #dddddd;
+        padding-top: 8px;
+        .os-td {
+          padding-top: 4px;
+          padding-left: 8px;
+          width: 9%;
+        }
+        .sub-trow {
+          width: 100%;
+          min-height: 39px;
+          .name-td {
+            width: 16%;
+            padding-top: 4px;
+          }
+          .url-td {
+            width: 60%;
+            .ember-text-field {
+              width: 100%;
+              margin: -1px -1px -1px -2px;
+            }
+          }
+          .url-text-td {
+            width: 70%;
+            padding-top: 4px;
+            padding-left: 3px;
+            overflow: auto;
+          }
+          .edit-td {
+            width: 8%;
+            padding-top: 4px;
+            padding-left: 5px;
+            a {
+              cursor: pointer;
+            }
+          }
+          .edit-buttons-td {
+            // save or cancel
+            width: 9%;
+          }
+          .clear-td {
+            width: 3%;
+            padding-top: 5px;
+            padding-left: 12px;
+            a {
+              cursor: pointer;
+              text-decoration: none;
+            }
+            .icon-remove-sign {
+              color: #808080;
+            }
+          }
+        }
+      }
+    }
+    .textfield-error input {
+      border-color: #b94a48;
+      -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+      -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+      box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
+    }
+    .disabled-textfield input {
+      color: #808080;
+      disabled: disabled;
+      pointer-events: none;
+      cursor: default;
+      background: #E4E4E4;
+    }
+    .disabled-label {
+      color: #808080;
+    }
+  }
+  #skip-validation {
+    margin-top: 10px;
+    .checkbox {
+      margin-left: 3px;
+      margin-right: 8px;
+      margin-top: 0px;
+    }
+    .icon-question-sign {
+      color: @blue;
+    }
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/70b912c6/ambari-web/app/templates/main/admin/stack_upgrade/services.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/admin/stack_upgrade/services.hbs b/ambari-web/app/templates/main/admin/stack_upgrade/services.hbs
index 80cf302..56d13bf 100644
--- a/ambari-web/app/templates/main/admin/stack_upgrade/services.hbs
+++ b/ambari-web/app/templates/main/admin/stack_upgrade/services.hbs
@@ -27,7 +27,7 @@
   </tr>
   </thead>
   <tbody>
-  {{#each service in view.services}}
+    {{#each service in view.services}}
     <tr>
       <td class="service-display-name">{{service.displayName}}</td>
       <td class="service-stack-version">{{service.serviceVersion}}</td>
@@ -41,6 +41,80 @@
       </td>
       <td class="service-description">{{{service.comments}}}</td>
     </tr>
-  {{/each}}
+    {{/each}}
   </tbody>
 </table>
+
+{{#unless App.stackVersionsAvailable}}
+
+  <div class="header">
+    <strong>{{t admin.cluster.repositories.repositories}}</strong>
+  </div>
+  <ul class="nav nav-tabs">
+    <li class="active">
+      <a href="javascript:void(null);">{{view.allRepositoriesGroups.stackVersion}}</a>
+    </li>
+  </ul>
+
+  <div class="admin-cluster">
+    <div class="repositories-table">
+      <div class="thead">
+        <div class="th os-th">{{t common.os}}</div>
+        <div class="th name-th">{{t common.name}}</div>
+        <div class="th url-th">{{t installer.step1.advancedRepo.localRepo.column.baseUrl}}</div>
+      </div>
+      <div class="tbody">
+        {{#each repoGroup in view.allRepositoriesGroups}}
+          <div class="trow">
+            <div class="os-td">
+              <label>
+                <span class="os">{{repoGroup.name}}</span>
+              </label>
+            </div>
+            <div style="width:89%">
+              {{#each repository in repoGroup.repositories}}
+                <div class="sub-trow">
+                  <div class="name-td">{{repository.repoId}}</div>
+                  <!--edit mode for current url-->
+                  {{#if repository.onEdit}}
+                    <div {{bindAttr class=":url-td repository.empty-error:textfield-error
repository.invalid-error:textfield-error"}}>
+                      {{view Ember.TextField valueBinding="repository.baseUrl"}}
+                    </div>
+                    <div class="clear-td">
+                      {{#if repository.clearAll}}
+                        <a {{action "clearGroupLocalRepository" repository target="view"
}}>
+                          <i class="icon-remove-sign"></i>
+                        </a>
+                      {{/if}}
+                    </div>
+                    <div class="edit-buttons-td">
+                      <a class="btn" {{action doCancel repository target="view"}}>{{t
common.cancel}}</a>
+                    </div>
+                    <div class="edit-buttons-td">
+                      {{#if repository.empty-error}}
+                        <a class="btn btn-primary" disabled="disabled">{{t common.save}}</a>
+                      {{else}}
+                        <a class="btn btn-primary" {{action saveRepoUrls repository target="view"}}>{{t
common.save}}</a>
+                      {{/if}}
+                    </div>
+                    <!--non-edit mode for current url-->
+                  {{else}}
+                    <div class="url-text-td">
+                      {{repository.baseUrl}}
+                    </div>
+                    <div class="edit-td">
+                      <a {{action "onEditClick" repository target="view" }}>
+                        <i class="icon-edit"></i> {{t common.edit}}
+                      </a>
+                    </div>
+                  {{/if}}
+                </div>
+              {{/each}}
+            </div>
+          </div>
+        {{/each}}
+      </div>
+    </div>
+  </div>
+
+{{/unless}}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/70b912c6/ambari-web/app/templates/main/host.hbs
----------------------------------------------------------------------
diff --git a/ambari-web/app/templates/main/host.hbs b/ambari-web/app/templates/main/host.hbs
index 01f2951..40b9c61 100644
--- a/ambari-web/app/templates/main/host.hbs
+++ b/ambari-web/app/templates/main/host.hbs
@@ -68,7 +68,7 @@
         {{view view.parentView.memorySort}}
         {{view view.parentView.diskUsageSort}}
         {{view view.parentView.loadAvgSort}}
-        <th {{bindAttr class="App.supports.stackUpgrade::hidden :sort-view-11"}}>
+        <th {{bindAttr class="App.supports.stackUpgrade::hidden App.stackVersionsAvailable::hidden
:sort-view-11"}}>
           {{t hosts.host.menu.stackVersions}}
         </th>
         <th class="sort-view-6">{{t common.components}}</th>
@@ -84,7 +84,7 @@
         <th>{{view view.ramFilterView}}</th>
         <th> </th>
         <th>{{view view.loadAvgFilterView}}</th>
-        <th {{bindAttr class="App.supports.stackUpgrade::hidden"}}>
+        <th {{bindAttr class="App.supports.stackUpgrade::hidden App.stackVersionsAvailable::hidden"}}>
           {{view view.versionsFilterView}}
         </th>
         <th>{{view view.componentsFilterView}}</th>
@@ -132,7 +132,7 @@
           </td>
 
           <td class="load-avg">{{host.loadAvg}}</td>
-          <td {{bindAttr class="App.supports.stackUpgrade::hidden view.hasSingleVersion:not-active-link
:host-table-versions"}}>
+          <td {{bindAttr class="App.supports.stackUpgrade::hidden App.stackVersionsAvailable::hidden
view.hasSingleVersion:not-active-link :host-table-versions"}}>
             <a href="#" class="expander black" {{action toggleVersions target="view"}}>
               {{#unless view.hasSingleVersion}}
                 <span {{bindAttr class="view.isVersionsCollapsed:icon-caret-right:icon-caret-down"}}></span>

http://git-wip-us.apache.org/repos/asf/ambari/blob/70b912c6/ambari-web/app/views/main/admin/stack_upgrade/menu_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/admin/stack_upgrade/menu_view.js b/ambari-web/app/views/main/admin/stack_upgrade/menu_view.js
index cf4b500..1006013 100644
--- a/ambari-web/app/views/main/admin/stack_upgrade/menu_view.js
+++ b/ambari-web/app/views/main/admin/stack_upgrade/menu_view.js
@@ -23,18 +23,21 @@ App.MainAdminStackMenuView = Em.CollectionView.extend({
   classNames: ["nav", "nav-tabs"],
   defaultRoute: 'services',
 
-  content: [
-    Em.Object.create({
-      name: 'services',
-      label: Em.I18n.t('common.stack'),
-      routing: 'services'
-    }),
-    Em.Object.create({
-      name: 'versions',
-      label: Em.I18n.t('common.versions'),
-      routing: 'versions'
-    })
-  ],
+  content: function () {
+    return [
+      Em.Object.create({
+        name: 'services',
+        label: Em.I18n.t('common.stack'),
+        routing: 'services'
+      }),
+      Em.Object.create({
+        name: 'versions',
+        label: Em.I18n.t('common.versions'),
+        routing: 'versions',
+        hidden: !App.get('stackVersionsAvailable')
+      })
+    ]
+  }.property('App.stackVersionsAvailable'),
 
   didInsertElement: function () {
     this.activateView();
@@ -56,6 +59,6 @@ App.MainAdminStackMenuView = Em.CollectionView.extend({
   itemViewClass: Em.View.extend({
     classNameBindings: ["active"],
     active: "",
-    template: Ember.Handlebars.compile('<a {{action stackNavigate view.content.routing
}} href="#"> {{unbound view.content.label}}</a>')
+    template: Ember.Handlebars.compile('{{#unless view.content.hidden}}<a {{action stackNavigate
view.content.routing }} href="#"> {{unbound view.content.label}}</a>{{/unless}}')
   })
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/70b912c6/ambari-web/app/views/main/admin/stack_upgrade/services_view.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/admin/stack_upgrade/services_view.js b/ambari-web/app/views/main/admin/stack_upgrade/services_view.js
index 3d8e6dc..b36e5f3 100644
--- a/ambari-web/app/views/main/admin/stack_upgrade/services_view.js
+++ b/ambari-web/app/views/main/admin/stack_upgrade/services_view.js
@@ -33,6 +33,12 @@ App.MainAdminStackServicesView = Em.View.extend({
     });
   }.property('App.router.clusterController.isLoaded'),
 
+  didInsertElement: function () {
+    if (!App.get('stackVersionsAvailable')) {
+      this.get('controller').loadRepositories();
+    }
+  },
+
   /**
    * launch Add Service wizard
    * @param event
@@ -44,5 +50,217 @@ App.MainAdminStackServicesView = Em.View.extend({
       App.router.get('addServiceController').set('serviceToInstall', event.context);
       App.get('router').transitionTo('main.serviceAdd');
     }
+  },
+
+  /**
+   * List of all repo-groups
+   * @type {Object[][]}
+   */
+  allRepositoriesGroups: function () {
+    var repos = this.get('controller.allRepos');
+    var reposGroup = [];
+    var repositories = [];
+    reposGroup.set('stackVersion', App.get('currentStackVersionNumber'));
+    if (repos) {
+      repos.forEach(function (group) {
+        group.repositories.forEach (function(repo) {
+          var cur_repo = Em.Object.create({
+            'repoId': repo.repoId,
+            'id': repo.repoId + '-' + repo.osType,
+            'repoName' : repo.repoName,
+            'stackName' : repo.stackName,
+            'stackVersion' : repo.stackVersion,
+            'baseUrl': repo.baseUrl,
+            'originalBaseUrl': repo.baseUrl,
+            'osType': repo.osType,
+            'onEdit': false,
+            'empty-error': !repo.baseUrl,
+            'undo': false,
+            'clearAll': repo.baseUrl
+          });
+          var cur_group = reposGroup.findProperty('name', group.name);
+          if (!cur_group) {
+            var cur_group = Ember.Object.create({
+              name: group.name,
+              repositories: []
+            });
+            reposGroup.push(cur_group);
+          }
+          cur_group.repositories.push(cur_repo);
+          repositories.push(cur_repo);
+        });
+      });
+    }
+    this.set('allRepos', repositories);
+    return reposGroup;
+  }.property('controller.allRepos'),
+
+  /**
+   * Onclick handler for edit action of each repo, enter edit mode
+   * @param {object} event
+   */
+  onEditClick:function (event) {
+    var targetRepo = this.get('allRepos').findProperty('id', event.context.get('id'));
+    if (targetRepo) {
+      targetRepo.set('onEdit', true);
+    }
+  },
+
+  /**
+   * Onclick handler for undo action of each repo group
+   * @method undoGroupLocalRepository
+   * @param {object} event
+   */
+  undoGroupLocalRepository: function (event) {
+    this.doActionForGroupLocalRepository(event, 'originalBaseUrl');
+  },
+
+  /**
+   * Handler for clear icon click
+   * @method clearGroupLocalRepository
+   * @param {object} event
+   */
+  clearGroupLocalRepository: function (event) {
+    this.doActionForGroupLocalRepository(event, '');
+  },
+
+  /**
+   * Common handler for repo groups actions
+   * @method doActionForGroupLocalRepository
+   * @param {object} event
+   * @param {string} newBaseUrlField
+   */
+  doActionForGroupLocalRepository: function (event, newBaseUrlField) {
+    var targetRepo = this.get('allRepos').findProperty('id', event.context.get('id'));
+    if (targetRepo) {
+      targetRepo.set('baseUrl', Em.isEmpty(newBaseUrlField) ? '' : Em.get(targetRepo, newBaseUrlField));
+    }
+  },
+
+  /**
+   * Handler when editing any repo group BaseUrl
+   * @method editGroupLocalRepository
+   */
+  editGroupLocalRepository: function (event) {
+    var repos = this.get('allRepos');
+    repos.forEach(function (targetRepo) {
+      targetRepo.set('undo', targetRepo.get('baseUrl') != targetRepo.get('originalBaseUrl'));
+      targetRepo.set('clearAll', targetRepo.get('baseUrl'));
+      targetRepo.set('empty-error', !targetRepo.get('baseUrl'));
+
+    });
+  }.observes('allRepos.@each.baseUrl'),
+
+  /**
+   * onSuccess callback for save Repo URL.
+   */
+  doSaveRepoUrlsSuccessCallback: function (response, request, data) {
+    var id = data.repoId + '-' + data.osType;
+    console.log('Success in check Repo URL. data repoId+osType: ' + id);
+    var targetRepo = this.get('allRepos').findProperty('id', id);
+    if (!targetRepo) {
+      return;
+    } else {
+
+      var modalCloseHandler = function() {
+        this.hide();
+        targetRepo.set('baseUrl', data.data.Repositories.base_url);
+        targetRepo.set('originalBaseUrl', data.data.Repositories.base_url);
+        targetRepo.set('onEdit', false);
+      };
+
+      App.ModalPopup.show({
+        header: Em.I18n.t('admin.cluster.repositories.popup.header.success'),
+        secondary: null,
+        onPrimary: modalCloseHandler,
+        onClose: modalCloseHandler,
+        message: Em.I18n.t('admin.cluster.repositories.popup.body.success'),
+        bodyClass: Em.View.extend({
+          template: Em.Handlebars.compile('<div class="alert alert-success">{{{message}}}</div>')
+        })
+      })
+    }
+  },
+
+  /**
+   * onError callback for save Repo URL.
+   */
+  doSaveRepoUrlsErrorCallback: function (request, ajaxOptions, error, data) {
+    console.log('Error in check Repo URL. The baseURL sent is:  ' + data.data);
+    var self = this;
+    var id = data.url.split('/')[10] + '-' + data.url.split('/')[8];
+    var targetRepo = this.get('allRepos').findProperty('id', id);
+    if (!targetRepo) {
+      return;
+    } else {
+      App.ModalPopup.show({
+        header: Em.I18n.t('admin.cluster.repositories.popup.header.fail'),
+        primary: Em.I18n.t('common.saveAnyway'),
+        secondary: Em.I18n.t('common.revert'),
+        third: Em.I18n.t('common.cancel'),
+        onPrimary: function () {
+          // save anyway: Go ahead and save with Repo URL validation turned off and close
Dialog when done.
+          this.hide();
+          self.doSaveRepoUrls(id, false);
+        },
+        onSecondary: function () {
+          // Revert: Close dialog, revert URL value, go back to non-Edit mode
+          this.hide();
+          targetRepo.set('baseUrl', targetRepo.get('originalBaseUrl'));
+          targetRepo.set('onEdit', false);
+        },
+        onThird: function () {
+          // cancel: Close dialog but stay in Edit mode
+          this.hide();
+        },
+        message: Em.I18n.t('admin.cluster.repositories.popup.body.fail'),
+        bodyClass: Em.View.extend({
+          template: Em.Handlebars.compile('<div class="alert alert-warning">{{{message}}}</div>')
+        })
+      })
+    }
+  },
+
+  /**
+   * Check validation and Save the customized local urls
+   */
+  doSaveRepoUrls: function (id, verifyBaseUrl) {
+    var targetRepo = this.get('allRepos').findProperty('id', id);
+    var verifyBaseUrl = verifyBaseUrl;
+    App.ajax.send({
+      name: 'wizard.advanced_repositories.valid_url',
+      sender: this,
+      data: {
+        stackName: targetRepo.stackName,
+        stackVersion: targetRepo.stackVersion,
+        repoId: targetRepo.repoId,
+        osType: targetRepo.osType,
+        data: {
+          'Repositories': {
+            'base_url': targetRepo.baseUrl,
+            "verify_base_url": verifyBaseUrl
+          }
+        }
+      },
+      success: 'doSaveRepoUrlsSuccessCallback',
+      error: 'doSaveRepoUrlsErrorCallback'
+    });
+  },
+  /**
+   * Check validation and Save the customized local urls
+   */
+  saveRepoUrls: function (event) {
+    this.doSaveRepoUrls(event.context.get('id'), true);
+  },
+
+  /**
+   * on click handler 'Cancel' for current repo in edit mode
+   */
+  doCancel: function (event) {
+    var targetRepo = this.get('allRepos').findProperty('id', event.context.get('id'));
+    if (targetRepo) {
+      targetRepo.set('baseUrl', targetRepo.get('originalBaseUrl'));
+      targetRepo.set('onEdit', false);
+    }
   }
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/70b912c6/ambari-web/app/views/main/host/menu.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/host/menu.js b/ambari-web/app/views/main/host/menu.js
index d1c26d7..92c123c 100644
--- a/ambari-web/app/views/main/host/menu.js
+++ b/ambari-web/app/views/main/host/menu.js
@@ -23,37 +23,39 @@ App.MainHostMenuView = Em.CollectionView.extend({
   classNames: ["nav", "nav-tabs"],
   host: null,
 
-  content: [
-    Em.Object.create({
-      name: 'summary',
-      label: Em.I18n.t('common.summary'),
-      routing: 'summary',
-      id: 'host-details-summary-tab'
-    }),
-    Em.Object.create({
-      name: 'configs',
-      label: Em.I18n.t('common.configs'),
-      routing: 'configs',
-      id: 'host-details-summary-configs'
-    }),
-    Em.Object.create({
-      name: 'alerts',
-      label: Em.I18n.t('hosts.host.alerts.label'),
-      routing: 'alerts',
-      badgeText: '0',
-      badgeClasses: 'label',
-      id: 'host-details-summary-alerts'
-    }),
-    Em.Object.create({
-      name: 'versions',
-      label: Em.I18n.t('hosts.host.menu.stackVersions'),
-      routing: 'stackVersions',
-      hidden: function() {
-        return !App.get('supports.stackUpgrade')
-      }.property('App.get.supports.stackUpgrade'),
-      id: 'host-details-summary-version'
-    })
-  ],
+  content: function () {
+    return [
+      Em.Object.create({
+        name: 'summary',
+        label: Em.I18n.t('common.summary'),
+        routing: 'summary',
+        id: 'host-details-summary-tab'
+      }),
+      Em.Object.create({
+        name: 'configs',
+        label: Em.I18n.t('common.configs'),
+        routing: 'configs',
+        id: 'host-details-summary-configs'
+      }),
+      Em.Object.create({
+        name: 'alerts',
+        label: Em.I18n.t('hosts.host.alerts.label'),
+        routing: 'alerts',
+        badgeText: '0',
+        badgeClasses: 'label',
+        id: 'host-details-summary-alerts'
+      }),
+      Em.Object.create({
+        name: 'versions',
+        label: Em.I18n.t('hosts.host.menu.stackVersions'),
+        routing: 'stackVersions',
+        hidden: function () {
+          return !App.get('supports.stackUpgrade') || !App.get('stackVersionsAvailable')
+        }.property('App.supports.stackUpgrade'),
+        id: 'host-details-summary-version'
+      })
+    ];
+  }.property('App.stackVersionsAvailable'),
 
   /**
    * Update Alerts menu option counter text and class

http://git-wip-us.apache.org/repos/asf/ambari/blob/70b912c6/ambari-web/test/views/main/admin/stack_upgrade/menu_view_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/admin/stack_upgrade/menu_view_test.js b/ambari-web/test/views/main/admin/stack_upgrade/menu_view_test.js
new file mode 100644
index 0000000..cc06a5f
--- /dev/null
+++ b/ambari-web/test/views/main/admin/stack_upgrade/menu_view_test.js
@@ -0,0 +1,56 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var App = require('app');
+var view;
+
+describe('App.MainAdminStackMenuView', function () {
+
+  beforeEach(function () {
+    view = App.MainAdminStackMenuView.create({});
+  });
+
+  describe('#content', function () {
+
+    afterEach(function () {
+      App.get.restore();
+    });
+
+    Em.A([
+        {
+          stackVersionsAvailable: true,
+          m: '`versions` is visible',
+          e: false
+        },
+        {
+          stackVersionsAvailable: false,
+          m: '`versions` is invisible',
+          e: true
+        }
+      ]).forEach(function (test) {
+        it(test.m, function () {
+          var stub = sinon.stub(App, 'get');
+          stub.withArgs('stackVersionsAvailable').returns(test.stackVersionsAvailable);
+          view.propertyDidChange('content');
+          expect(view.get('content').findProperty('name', 'versions').get('hidden')).to.equal(test.e);
+        });
+      });
+
+  });
+
+});
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/70b912c6/ambari-web/test/views/main/host/menu_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/views/main/host/menu_test.js b/ambari-web/test/views/main/host/menu_test.js
new file mode 100644
index 0000000..d4e6d6a
--- /dev/null
+++ b/ambari-web/test/views/main/host/menu_test.js
@@ -0,0 +1,71 @@
+/**
+ * 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');
+var view;
+
+describe('App.MainHostMenuView', function () {
+
+  beforeEach(function () {
+    view = App.MainHostMenuView.create({});
+  });
+
+  describe('#content', function () {
+
+    afterEach(function () {
+      App.get.restore();
+    });
+
+    Em.A([
+        {
+          stackVersionsAvailable: true,
+          stackUpgrade: true,
+          m: '`versions` is visible',
+          e: false
+        },
+        {
+          stackVersionsAvailable: true,
+          stackUpgrade: false,
+          m: '`versions` is invisible (1)',
+          e: true
+        },
+        {
+          stackVersionsAvailable: false,
+          stackUpgrade: true,
+          m: '`versions` is invisible (2)',
+          e: true
+        },
+        {
+          stackVersionsAvailable: false,
+          stackUpgrade: false,
+          m: '`versions` is invisible (3)',
+          e: true
+        }
+      ]).forEach(function (test) {
+        it(test.m, function () {
+          var stub = sinon.stub(App, 'get');
+          stub.withArgs('stackVersionsAvailable').returns(test.stackVersionsAvailable);
+          stub.withArgs('supports.stackUpgrade').returns(test.stackUpgrade);
+          view.propertyDidChange('content');
+          expect(view.get('content').findProperty('name', 'versions').get('hidden')).to.equal(test.e);
+        });
+      });
+
+  });
+
+});
\ No newline at end of file


Mime
View raw message