You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by xi...@apache.org on 2016/02/04 22:56:54 UTC

[4/4] ambari git commit: AMBARI-14837. Versions: display all versions as tabs on left side, version details on selecting.(xiwang)

AMBARI-14837. Versions: display all versions as tabs on left side, version details on selecting.(xiwang)


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

Branch: refs/heads/branch-dev-patch-upgrade
Commit: 0f9da42829c5d7118284d09e98190403bfdce41e
Parents: efc3a07
Author: Xi Wang <xi...@apache.org>
Authored: Wed Feb 3 16:15:24 2016 -0800
Committer: Xi Wang <xi...@apache.org>
Committed: Wed Feb 3 16:15:24 2016 -0800

----------------------------------------------------------------------
 .../stackVersions/StackVersionsCreateCtrl.js    |  35 +--
 .../stackVersions/StackVersionsEditCtrl.js      | 241 ++++++++++++-------
 .../stackVersions/StackVersionsListCtrl.js      | 127 +++-------
 .../ui/admin-web/app/scripts/i18n.config.js     |   1 +
 .../ui/admin-web/app/scripts/services/Stack.js  |  30 ++-
 .../resources/ui/admin-web/app/styles/main.css  |  80 +++++-
 .../admin-web/app/views/stackVersions/list.html | 105 +++-----
 .../views/stackVersions/stackVersionPage.html   |  50 +++-
 .../stackVersions/StackversionsListCtrl_test.js | 152 ------------
 9 files changed, 357 insertions(+), 464 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/0f9da428/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsCreateCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsCreateCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsCreateCtrl.js
index 37f9c34..df76c15 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsCreateCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsCreateCtrl.js
@@ -23,7 +23,6 @@ angular.module('ambariAdminConsole')
   $scope.createController = true;
   $scope.osList = [];
   $scope.skipValidation = false;
-  $scope.repoSubversion = "";
 
   $scope.clusterName = $routeParams.clusterName;
   $scope.subversionPattern = /^\d+\.\d+(-\d+)?$/;
@@ -111,10 +110,8 @@ angular.module('ambariAdminConsole')
         };
       });
       $scope.repoVersionFullName = response.repoVersionFullName;
-      $scope.selectedOS = [];
       angular.forEach(response.osList, function (os) {
         os.selected = true;
-        $scope.selectedOS.push(os.OperatingSystems.os_type);
       });
       $scope.osList = response.osList;
       // load supported os type base on stack version
@@ -130,8 +127,12 @@ angular.module('ambariAdminConsole')
       .then(function (data) {
         var operatingSystems = data.operating_systems;
         operatingSystems.map(function (os) {
-          // os not in the list, mark as un-selected, add this to the osList
-          if ($scope.selectedOS.indexOf(os.OperatingSystems.os_type) < 0) {
+          var existingOSHash = {};
+          angular.forEach($scope.osList, function (os) {
+            existingOSHash[os.OperatingSystems.os_type] = os;
+          });
+          // if os not in the list, mark as un-selected, add this to the osList
+          if (!existingOSHash[os.OperatingSystems.os_type]) {
             os.selected = false;
             os.repositories.forEach(function(repo) {
               repo.Repositories.base_url = '';
@@ -183,9 +184,10 @@ angular.module('ambariAdminConsole')
       if (invalidUrls.length === 0) {
         Stack.addRepo($scope.upgradeStack, $scope.actualVersion, $scope.osList)
           .success(function () {
-            var versionName = $scope.actualVersion + '';
-            var stackName = $scope.upgradeStack.stack_name;
-            Alert.success($t('versions.alerts.versionCreated'), {stackName: stackName, versionName: versionName});
+            Alert.success($t('versions.alerts.versionCreated', {
+              stackName: $scope.upgradeStack.stack_name,
+              versionName: $scope.actualVersion
+            }));
             $location.path('/stackVersions');
           })
           .error(function (data) {
@@ -196,19 +198,12 @@ angular.module('ambariAdminConsole')
       }
     });
   };
-  /**
-   * TODO create parent controller for StackVersionsEditCtrl and StackVersionsCreateCtrl and
-   * move this method to it
-   */
+
   $scope.cancel = function () {
     $scope.editVersionDisabled = true;
     $location.path('/stackVersions');
   };
 
-  /**
-   * TODO create parent controller for StackVersionsEditCtrl and StackVersionsCreateCtrl and
-   * move this method to it
-   */
   $scope.clearErrors = function() {
     if ($scope.osList) {
       $scope.osList.forEach(function(os) {
@@ -221,18 +216,10 @@ angular.module('ambariAdminConsole')
     }
   };
 
-  /**
-   * TODO create parent controller for StackVersionsEditCtrl and StackVersionsCreateCtrl and
-   * move this method to it
-   */
   $scope.clearError = function() {
     this.repository.hasError = false;
   };
 
-  /**
-   * TODO create parent controller for StackVersionsEditCtrl and StackVersionsCreateCtrl and
-   * move this method to it
-   */
   $scope.hasValidationErrors = function() {
     var hasErrors = false;
     if ($scope.osList) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/0f9da428/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsEditCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsEditCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsEditCtrl.js
index 0763726..9c5b2eb 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsEditCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsEditCtrl.js
@@ -24,17 +24,27 @@ angular.module('ambariAdminConsole')
   $scope.osList = [];
   $scope.skipValidation = false;
   $scope.selectedOS = 0;
+  $scope.upgradeStack = {
+    stack_name: '',
+    stack_version: '',
+    display_name: ''
+  };
 
   $scope.loadStackVersionInfo = function () {
     return Stack.getRepo($routeParams.versionId, $routeParams.stackName).then(function (response) {
       $scope.id = response.id;
-      $scope.stack = response.stack;
-      $scope.stackName = response.stackName;
-      $scope.versionName = response.versionName;
-      $scope.displayName = response.displayName;
-      $scope.stackVersion = response.stackVersion;
+      $scope.isPatch = response.type == 'PATCH';
+      $scope.stackNameVersion = response.stackNameVersion || 'n/a';
+      $scope.displayName = response.displayName || 'n/a';
+      $scope.version = response.version || 'n/a';
+      $scope.actualVersion = response.actualVersion || 'n/a';
       $scope.updateObj = response.updateObj;
-      $scope.subversion = response.versionName.substring(4); // cut off stack version
+      $scope.upgradeStack = {
+        stack_name: response.stackName,
+        stack_version: response.stackVersion,
+        display_name: response.displayName
+      };
+      $scope.services = response.services || [];
       //save default values of repos to check if they were changed
       $scope.defaulfOSRepos = {};
       response.updateObj.operating_systems.forEach(function(os) {
@@ -47,8 +57,10 @@ angular.module('ambariAdminConsole')
       angular.forEach(response.osList, function (os) {
         os.selected = true;
       });
-      $scope.selectedOS = response.osList.length;
       $scope.osList = response.osList;
+      // load supported os type base on stack version
+      $scope.afterStackVersionRead();
+
       // if user reach here from UI click, repo status should be cached
       // otherwise re-fetch repo status from cluster end point.
       $scope.repoStatus = Cluster.repoStatusCache[$scope.id];
@@ -63,50 +75,40 @@ angular.module('ambariAdminConsole')
       } else {
         $scope.deleteEnabled = $scope.isDeletable();
       }
-      $scope.addMissingOSList();
+      // fetch all repos to display the left menu
+      $scope.fetchRepos();
     });
   };
 
-  $scope.isDeletable = function() {
-    return !($scope.repoStatus == 'current' || $scope.repoStatus == 'installed');
+  /**
+   * Load supported OS list
+   */
+  $scope.afterStackVersionRead = function () {
+    Stack.getSupportedOSList($scope.upgradeStack.stack_name, $scope.upgradeStack.stack_version)
+      .then(function (data) {
+        var operatingSystems = data.operating_systems;
+        operatingSystems.map(function (os) {
+          var existingOSHash = {};
+          angular.forEach($scope.osList, function (os) {
+            existingOSHash[os.OperatingSystems.os_type] = os;
+          });
+          // if os not in the list, mark as un-selected, add this to the osList
+          if (!existingOSHash[os.OperatingSystems.os_type]) {
+            os.selected = false;
+            os.repositories.forEach(function(repo) {
+              repo.Repositories.base_url = '';
+            });
+            $scope.osList.push(os);
+          }
+        });
+      })
+      .catch(function (data) {
+        Alert.error($t('versions.alerts.osListError'), data.message);
+      });
   };
 
-  $scope.addMissingOSList = function() {
-    Stack.getSupportedOSList($scope.stackName, $scope.stackVersion)
-    .then(function (data) {
-      var existingOSHash = {};
-      angular.forEach($scope.osList, function (os) {
-        existingOSHash[os.OperatingSystems.os_type] = os;
-      });
-      var osList = data.operating_systems.map(function (os) {
-        return existingOSHash[os.OperatingSystems.os_type] || {
-          OperatingSystems: {
-            os_type : os.OperatingSystems.os_type
-          },
-          repositories: [
-            {
-              Repositories: {
-                base_url: '',
-                repo_id: 'HDP-' + $routeParams.versionId,
-                repo_name: 'HDP'
-              }
-            },
-            {
-              Repositories: {
-                base_url: '',
-                repo_id: 'HDP-UTILS-' + $routeParams.versionId,
-                repo_name: 'HDP-UTILS'
-              }
-            }
-          ],
-          selected: false
-        };
-      });
-      $scope.osList = osList;
-    })
-    .catch(function (data) {
-      Alert.error($t('versions.alerts.osListError'), data.message);
-    });
+  $scope.isDeletable = function() {
+    return !($scope.repoStatus == 'current' || $scope.repoStatus == 'installed');
   };
 
   $scope.defaulfOSRepos = {};
@@ -143,17 +145,13 @@ angular.module('ambariAdminConsole')
   };
 
   $scope.updateRepoVersions = function () {
-    var upgradeStack = {
-      stack_name: $scope.stackName,
-      stack_version: $scope.stackVersion
-    };
-    return Stack.validateBaseUrls($scope.skipValidation, $scope.osList, upgradeStack).then(function (invalidUrls) {
+    return Stack.validateBaseUrls($scope.skipValidation, $scope.osList, $scope.upgradeStack).then(function (invalidUrls) {
       if (invalidUrls.length === 0) {
-        Stack.updateRepo($scope.stackName, $scope.stackVersion, $scope.id, $scope.updateObj).then(function () {
+        Stack.updateRepo($scope.upgradeStack.stack_name, $scope.upgradeStack.stack_version, $scope.id, $scope.updateObj).then(function () {
           Alert.success($t('versions.alerts.versionEdited', {
-            stackName: $scope.stackName,
-            versionName: $scope.versionName,
-            displayName: $scope.displayName
+            stackName: $scope.upgradeStack.stack_name,
+            versionName: $scope.actualVersion,
+            displayName: $scope.repoVersionFullName
           }));
           $location.path('/stackVersions');
         }).catch(function (data) {
@@ -187,22 +185,56 @@ angular.module('ambariAdminConsole')
       $t('versions.deregister'),
       {
         "url": 'views/modals/BodyForDeregisterVersion.html',
-        "scope": {"displayName": $scope.displayName }
+        "scope": {"displayName": $scope.repoVersionFullName }
       }
     ).then(function() {
-      Stack.deleteRepo($scope.stackName, $scope.stackVersion, $scope.id).then( function () {
-        $location.path('/stackVersions');
-      }).catch(function (data) {
-        Alert.error($t('versions.alerts.versionDeleteError'), data.message);
+        Stack.deleteRepo($scope.upgradeStack.stack_name, $scope.upgradeStack.stack_version, $scope.id).then( function () {
+          $location.path('/stackVersions');
+        }).catch(function (data) {
+            Alert.error($t('versions.alerts.versionDeleteError'), data.message);
+          });
       });
-    });
   };
   $scope.loadStackVersionInfo();
-    
+
+  /**
+   * On click handler for removing OS
+   */
+  $scope.removeOS = function() {
+    this.os.selected = false;
+    if (this.os.repositories) {
+      this.os.repositories.forEach(function(repo) {
+        repo.hasError = false;
+      });
+    }
+  };
   /**
-   * TODO create parent controller for StackVersionsEditCtrl and StackVersionsCreateCtrl and
-   * move this method to it
+   * On click handler for adding new OS
    */
+  $scope.addOS = function() {
+    this.os.selected = true;
+    if (this.os.repositories) {
+      this.os.repositories.forEach(function(repo) {
+        repo.hasError = false;
+      });
+    }
+  };
+
+  $scope.isSaveButtonDisabled = function() {
+    var enabled = false;
+    $scope.osList.forEach(function(os) {
+      if (os.selected) {
+        enabled = true
+      }
+    });
+    return !enabled;
+  }
+
+  $scope.cancel = function () {
+    $scope.editVersionDisabled = true;
+    $location.path('/stackVersions');
+  };
+
   $scope.clearErrors = function() {
     if ($scope.osList) {
       $scope.osList.forEach(function(os) {
@@ -214,29 +246,11 @@ angular.module('ambariAdminConsole')
       });
     }
   };
-  /**
-   * TODO create parent controller for StackVersionsEditCtrl and StackVersionsCreateCtrl and
-   * move this method to it
-   */
+
   $scope.clearError = function () {
     this.repository.hasError = false;
   };
 
-  /**
-   * TODO create parent controller for StackVersionsEditCtrl and StackVersionsCreateCtrl and
-   * move this method to it
-   */
-  $scope.toggleOSSelect = function () {
-    this.os.repositories.forEach(function (repo) {
-      repo.hasError = false;
-    });
-    this.os.selected ? $scope.selectedOS++ : $scope.selectedOS--;
-  };
-
-  /**
-   * TODO create parent controller for StackVersionsEditCtrl and StackVersionsCreateCtrl and
-   * move this method to it
-   */
   $scope.hasValidationErrors = function () {
     var hasErrors = false;
     if ($scope.osList) {
@@ -253,13 +267,62 @@ angular.module('ambariAdminConsole')
     return hasErrors;
   };
 
+
+  // add all repos list
+  $scope.filter = {
+    version: '',
+    cluster: {
+      options: [],
+      current: null
+    }
+  };
+
+  $scope.pagination = {
+    totalRepos: 100,
+    maxVisiblePages: 1,
+    itemsPerPage: 100,
+    currentPage: 1
+  };
+  $scope.allRepos = [];
+  $scope.stackVersions = [];
+
+
+
   /**
-   * TODO create parent controller for StackVersionsEditCtrl and StackVersionsCreateCtrl and
-   * move this method to it
+   *  Formatted object to display all repos:
+   *
+   *  [{ 'name': 'HDP-2.3',
+   *     'repos': ['2.3.6.0-2343', '2.3.4.1', '2.3.4.0-56']
+   *   },
+   *   { 'name': 'HDP-2.2',
+   *     'repos': ['2.2.6.0', '2.2.4.5', '2.2.4.0']
+   *   }
+   *  ]
+   *
    */
-  $scope.cancel = function () {
-    $scope.editVersionDisabled = true;
-    $location.path('/stackVersions');
+  $scope.fetchRepos = function () {
+    return Stack.allRepos($scope.filter, $scope.pagination).then(function (repos) {
+      $scope.allRepos = repos.items.sort(function(a, b){return a.repository_version < b.repository_version});
+      var existingStackHash = {};
+      var stackVersions = [];
+      angular.forEach($scope.allRepos, function (repo) {
+        var stackVersionName = repo.stack_name + '-' + repo.stack_version;
+        var currentStackVersion = $scope.upgradeStack.stack_name + '-' + $scope.upgradeStack.stack_version;
+        repo.isActive = $scope.actualVersion == repo.repository_version;
+        if (!existingStackHash[stackVersionName]) {
+          existingStackHash[stackVersionName] = true;
+          stackVersions.push({
+            'name': stackVersionName,
+            'isOpened': stackVersionName == currentStackVersion,
+            'repos': [repo]
+          });
+        } else {
+          if (stackVersions[stackVersions.length -1].repos) {
+            stackVersions[stackVersions.length -1].repos.push(repo);
+          }
+        }
+      });
+      $scope.stackVersions = stackVersions;
+    });
   };
-
 }]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/0f9da428/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsListCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsListCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsListCtrl.js
index 010ec1b..3a8233a 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsListCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/stackVersions/StackVersionsListCtrl.js
@@ -24,6 +24,7 @@ angular.module('ambariAdminConsole')
     return $t('common.' + key).toLowerCase();
   }
   $scope.clusterName = $routeParams.clusterName;
+
   $scope.filter = {
     version: '',
     cluster: {
@@ -31,106 +32,52 @@ angular.module('ambariAdminConsole')
       current: null
     }
   };
-  $scope.isNotEmptyFilter = true;
 
   $scope.pagination = {
-    totalRepos: 10,
-    maxVisiblePages: 20,
-    itemsPerPage: 10,
+    totalRepos: 100,
+    maxVisiblePages: 1,
+    itemsPerPage: 100,
     currentPage: 1
   };
+  $scope.allRepos = [];
+  $scope.stackVersions = [];
 
-  $scope.tableInfo = {
-    total: 0,
-    showed: 0,
-    filtered: 0
-  };
-
-  $scope.stacks = [];
-  $scope.dropDownClusters = [];
-  $scope.selectedCluster = $scope.dropDownClusters[0];
-
-  $scope.resetPagination = function () {
-    $scope.pagination.currentPage = 1;
-    $scope.loadAllData();
-  };
-
-  $scope.pageChanged = function () {
-    $scope.loadAllData();
-  };
-
-  $scope.goToCluster = function() {
-    window.location.replace('/#/main/admin/stack/versions');
-  };
-
-  $scope.clearFilters = function () {
-    $scope.filter.version = '';
-    $scope.filter.cluster.current = $scope.filter.cluster.options[0];
-    $scope.resetPagination();
-  };
-
-  $scope.fetchRepoClusterStatus = function () {
-    var clusterName = ($scope.clusters && $scope.clusters.length > 0) ? $scope.clusters[0].Clusters.cluster_name : null; // only support one cluster at the moment
-    if (clusterName) {
-      angular.forEach($scope.repos, function (repo) {
-        Cluster.getRepoVersionStatus(clusterName, repo.id).then(function (response) {
-          repo.status = response.status;
-          repo.totalHosts = response.totalHosts;
-          repo.currentHosts = response.currentHosts;
-          repo.installedHosts = response.installedHosts;
-          repo.stackVersionId = response.stackVersionId;
-          repo.cluster = (repo.status == 'current' || repo.status == 'installed')? clusterName : '';
-        });
-      });
-    }
-  };
-
+  /**
+   *  Formatted object to display all repos:
+   *
+   *  [{ 'name': 'HDP-2.3',
+   *     'repos': ['2.3.6.0-2343', '2.3.4.1', '2.3.4.0-56']
+   *   },
+   *   { 'name': 'HDP-2.2',
+   *     'repos': ['2.2.6.0', '2.2.4.5', '2.2.4.0']
+   *   }
+   *  ]
+   *
+   */
   $scope.fetchRepos = function () {
     return Stack.allRepos($scope.filter, $scope.pagination).then(function (repos) {
-      $scope.pagination.totalRepos = repos.itemTotal;
-      $scope.repos = repos.items;
-      $scope.tableInfo.total = repos.itemTotal;
-      $scope.tableInfo.showed = repos.showed;
-    });
-  };
-
-    $scope.fillClusters = function (clusters) {
-      $scope.dropDownClusters = [].concat(clusters);
-      var options = [{label: $t('common.all'), value: ''}];
-      angular.forEach(clusters, function (cluster) {
-        options.push({
-          label: cluster.Clusters.cluster_name,
-          value: cluster.Clusters.cluster_name
-        });
+      $scope.allRepos = repos.items.sort(function(a, b){return a.repository_version < b.repository_version});
+      var existingStackHash = {};
+      var stackVersions = [];
+      angular.forEach($scope.allRepos, function (repo) {
+        var stackVersionName = repo.stack_name + '-' + repo.stack_version;
+        if (!existingStackHash[stackVersionName]) {
+          existingStackHash[stackVersionName] = true;
+          stackVersions.push({
+            'name': stackVersionName,
+            'isOpened': true,
+            'repos': [repo]
+          });
+        } else {
+          if (stackVersions[stackVersions.length -1].repos) {
+            stackVersions[stackVersions.length -1].repos.push(repo);
+          }
+        }
       });
-      $scope.filter.cluster.options = options;
-      if (!$scope.filter.cluster.current) {
-        $scope.filter.cluster.current = options[0];
-      }
-    };
-
-  $scope.fetchClusters = function () {
-    return Cluster.getAllClusters().then(function (clusters) {
-      if (clusters && clusters.length > 0) {
-        $scope.clusters = clusters;
-        $scope.fillClusters(clusters);
-      }
-    });
-  };
-
-  $scope.loadAllData = function () {
-    $scope.fetchClusters()
-    .then(function () {
-      return $scope.fetchRepos();
-    })
-    .then(function () {
-      $scope.fetchRepoClusterStatus();
+      $scope.stackVersions = stackVersions;
     });
   };
 
-  $scope.loadAllData();
+  $scope.fetchRepos();
 
-  $scope.$watch('filter', function (filter) {
-    $scope.isNotEmptyFilter = Boolean(filter.version || (filter.cluster.current && filter.cluster.current.value));
-  }, true);
 }]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/0f9da428/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
index 9f6add0..afc2f44 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
@@ -306,6 +306,7 @@ angular.module('ambariAdminConsole')
       'os': 'OS',
       'baseURL': 'Base URL',
       'skipValidation': 'Skip Repository Base URL validation (Advanced)',
+      'noVersions': 'Select version to display details.',
       'contents': {
         'title': 'Contents',
         'empty': 'No contents to display'

http://git-wip-us.apache.org/repos/asf/ambari/blob/0f9da428/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Stack.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Stack.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Stack.js
index a12b430..20781b6 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Stack.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Stack.js
@@ -157,14 +157,27 @@ angular.module('ambariAdminConsole')
         var response = {
           id : data.repository_versions[0].RepositoryVersions.id,
           stackVersion : data.Versions.stack_version,
-          stack: data.Versions.stack_name + '-' + data.Versions.stack_version,
           stackName: data.Versions.stack_name,
-          versionName: data.repository_versions[0].RepositoryVersions.repository_version,
-          displayName : data.repository_versions[0].RepositoryVersions.display_name,
+          type: data.repository_versions[0].RepositoryVersions.release? data.repository_versions[0].RepositoryVersions.release.type: null,
+          stackNameVersion: data.Versions.stack_name + '-' + data.Versions.stack_version, /// HDP-2.3
+          actualVersion: data.repository_versions[0].RepositoryVersions.repository_version, /// 2.3.4.0-3846
+          version: data.repository_versions[0].RepositoryVersions.release ? data.repository_versions[0].RepositoryVersions.release.version: null, /// 2.3.4.0
+          releaseNotes: data.repository_versions[0].RepositoryVersions.release ? data.repository_versions[0].RepositoryVersions.release.release_notes: null,
+          displayName: data.repository_versions[0].RepositoryVersions.release ? data.Versions.stack_name + '-' + data.repository_versions[0].RepositoryVersions.release.version :
+            data.Versions.stack_name + '-' + data.repository_versions[0].RepositoryVersions.repository_version.split('-')[0], //HDP-2.3.4.0
           repoVersionFullName : data.Versions.stack_name + '-' + data.repository_versions[0].RepositoryVersions.repository_version,
           osList: data.repository_versions[0].operating_systems,
           updateObj: data.repository_versions[0]
         };
+        var services = [];
+        angular.forEach(data.repository_versions[0].RepositoryVersions.services, function (service) {
+          services.push({
+            name: service.name,
+            version: service.versions[0].version,
+            components: service.versions[0].components
+          });
+        });
+        response.services = services;
         deferred.resolve(response);
       })
       .error(function (data) {
@@ -286,12 +299,13 @@ angular.module('ambariAdminConsole')
             id : data.repository_versions[0].RepositoryVersions.id,
             stackVersion : data.Versions.stack_version,
             stackName: data.Versions.stack_name,
-            type: data.repository_versions[0].RepositoryVersions.release.type,
+            type: data.repository_versions[0].RepositoryVersions.type,
             stackNameVersion: data.Versions.stack_name + '-' + data.Versions.stack_version, /// HDP-2.3
             actualVersion: data.repository_versions[0].RepositoryVersions.repository_version, /// 2.3.4.0-3846
-            version: data.repository_versions[0].RepositoryVersions.release.version, /// 2.3.4.0
-            releaseNotes: data.repository_versions[0].RepositoryVersions.release.release_notes,
-            displayName: data.Versions.stack_name + '-' + data.repository_versions[0].RepositoryVersions.release.version, //HDP-2.3.4.0
+            version: data.repository_versions[0].RepositoryVersions.release ? data.repository_versions[0].RepositoryVersions.release.version: null, /// 2.3.4.0
+            releaseNotes: data.repository_versions[0].RepositoryVersions.release ? data.repository_versions[0].RepositoryVersions.release.release_notes: null,
+            displayName: data.repository_versions[0].RepositoryVersions.release ? data.Versions.stack_name + '-' + data.repository_versions[0].RepositoryVersions.release.version :
+              data.Versions.stack_name + '-' + data.repository_versions[0].RepositoryVersions.repository_version.split('-')[0], //HDP-2.3.4.0
             repoVersionFullName : data.Versions.stack_name + '-' + data.repository_versions[0].RepositoryVersions.repository_version,
             osList: data.repository_versions[0].operating_systems,
             updateObj: data.repository_versions[0]
@@ -299,7 +313,7 @@ angular.module('ambariAdminConsole')
           var services = [];
           angular.forEach(data.repository_versions[0].RepositoryVersions.services, function (service) {
             services.push({
-              name: service.name,
+              name: service.display_name,
               version: service.versions[0].version,
               components: service.versions[0].components
             });

http://git-wip-us.apache.org/repos/asf/ambari/blob/0f9da428/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
index 83d4ffa..93f2271 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
@@ -1378,11 +1378,57 @@ thead.view-permission-header > tr > th {
 }
 
 .enable-ldap input[type="checkbox"] {
-  margin-top: 10px;
+    margin-top: 10px;
 }
 
 .test-ldap-icon.ng-hide-add-active, .test-ldap-icon.ng-hide-remove {
-  display: inline-block!important;
+    display: inline-block!important;
+}
+
+.left-menu-all-repos {
+  padding-left: 5px;
+  padding-right: 5px;
+}
+
+.left-menu-all-repos .glyphicon.glyphicon-chevron-right{
+  -webkit-transition: all 0.3s;
+  -o-transition: all 0.3s;
+  transition: all 0.3s;
+}
+.left-menu-all-repos .glyphicon.glyphicon-chevron-right.opened{
+  -webkit-transform: rotateZ(90deg);
+  -ms-transform: rotateZ(90deg);
+  -o-transform: rotateZ(90deg);
+  transform: rotateZ(90deg);
+}
+
+.left-menu-all-repos .stack-version-title {
+  font-size: 14px;
+  cursor: pointer;
+  text-decoration: none;
+  padding-left: 10px;
+}
+
+.left-menu-all-repos .repos-table {
+  margin-bottom: 0px;
+}
+
+.left-menu-all-repos .panel-body {
+  padding: 15px 0px;
+}
+
+.left-menu-all-repos .repos-table .repos-td{
+  border-top: none;
+  padding: 5px 10px;
+}
+.left-menu-all-repos .repos-table .repos-td > a {
+  text-decoration: none;
+}
+.left-menu-all-repos .repos-table .repos-td.active{
+  background-color: #666;;
+}
+.left-menu-all-repos .repos-table .repos-td.active > a {
+  color: white;
 }
 
 .register-version-options .read-info-button {
@@ -1398,11 +1444,24 @@ thead.view-permission-header > tr > th {
   padding-bottom: 20px;
 }
 
-.register-version-form .patch-icon {
+.register-version-form .details-panel .patch-icon {
   color: #ff4500;
 }
+.register-version-form .deregister-button {
+    margin-top: -23px;
+}
+.register-version-form .version-info {
+    padding-top: 7px;
+    margin-top: 0;
+    margin-bottom: 0;
+}
+
+.register-version-form .contents-panel .version-contents-body {
+    max-height: 150px;
+    overflow: scroll;
+}
 
-.register-version-form .remove-icon {
+.register-version-form .repos-panel .remove-icon {
   color: red;
   margin: 20px 0px;
   padding: 0px;
@@ -1410,14 +1469,13 @@ thead.view-permission-header > tr > th {
   cursor: pointer;
 }
 
-.register-version-form .version-info {
-  padding-top: 7px;
-  margin-top: 0;
-  margin-bottom: 0;
+.register-version-form .repos-panel .os-type-label {
+  margin-top: 27px;;
 }
 
-.version-contents-body {
-  max-height: 150px;
-  overflow: scroll;
+#stack-versions .no-version-alert {
+  text-align: center;
 }
 
+
+

http://git-wip-us.apache.org/repos/asf/ambari/blob/0f9da428/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/list.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/list.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/list.html
index 5f5421b..3de92c1 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/list.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/list.html
@@ -29,85 +29,34 @@
     </div>
   </div>
   <hr/>
-  <table class="table table-striped table-hover">
-    <thead>
-    <tr>
-      <th class="col-medium">
-        <label>{{'common.name' | translate}}</label>
-        <input type="text" class="form-control" ng-change="resetPagination()" ng-model="filter.version" placeholder="{{'common.any' | translate}}">
-      </th>
-      <th class="col-small">
-        <label>{{'common.cluster' | translate}}</label>
-        <select class="form-control"
-                ng-change="resetPagination()"
-                ng-model="filter.cluster.current"
-                ng-options="item.label for item in filter.cluster.options track by item.value"
-          ></select>
-      </th>
-      <th></th>
-    </tr>
-    </thead>
-    <tbody>
-    <tr ng-repeat="repo in repos">
-      <td class="col-medium">
-        <a href="#/stackVersions/{{repo.stack_name}}/{{repo.repository_version}}/edit">{{repo.display_name}}</a>
-      </td>
-      <td class="col-small">
-        <a href="/#/main/admin/stack/versions" ng-show="repo.cluster">
-          {{repo.cluster}}
-        </a>
-        <span ng-show="!repo.cluster">
-          {{'common.none' | translate}}
-        </span>
-      </td>
-      <td class="verison-label-row">
-        <div ng-show="repo.status == 'current'">
-          <span class="label {{'status-' + repo.status}}">{{'versions.current' | translate}}:&nbsp;{{repo.currentHosts}}/{{repo.totalHosts}}</span>
-        </div>
-        <div ng-show="repo.status == 'installed'">
-          <span class="label {{'status-' + repo.status}}">{{'versions.installed' | translate}}:&nbsp;{{repo.installedHosts}}/{{repo.totalHosts}}</span>
-        </div>
-        <div ng-show="!repo.cluster">
-          <div class="btn-group display-inline-block" dropdown is-open="viewsdropdown.isopen" ng-mouseover="viewsdropdown.isopen=true" ng-mouseout="viewsdropdown.isopen=false" ng-init="viewsdropdown.isopen=false">
-            <a class="btn dropdown-toggle">
-              <span>{{'versions.installOn' | translate}}</span>
-            </a>
-            <ul class="dropdown-menu" ng-show="viewsdropdown.isopen">
-              <li ng-repeat="cluster in dropDownClusters">
-                <a href="javascript:void(null)" ng-click="goToCluster()">
-                    <span>{{cluster.Clusters.cluster_name}}</span>
-                </a>
-              </li>
-            </ul>
-          </div>
+
+  <accordion close-others="false" class="col-sm-2 left-menu-all-repos">
+    <accordion-group ng-repeat="stackVersion in stackVersions" is-open="stackVersion.isOpened">
+      <accordion-heading>
+        <div class="row stack-version-title">
+          <i class="glyphicon glyphicon-chevron-right" ng-class="{'opened': stackVersion.isOpened}"></i>
+          {{stackVersion.name}}
         </div>
-      </td>
-    </tr>
-    </tbody>
-  </table>
-  <div class="alert alert-info col-sm-12" ng-show="!repos.length">
-    {{'common.alerts.nothingToDisplay' | translate: '{term: getConstant("version")}'}}
-  </div>
-  <div class="col-sm-12 table-bar">
-    <div class="pull-left filtered-info">
-      <span>{{'common.filterInfo' | translate: '{showed: tableInfo.showed, total: tableInfo.total, term: getConstant("versions")}'}}</span>
-      <span ng-show="isNotEmptyFilter">- <a href ng-click="clearFilters()">{{'common.controls.clearFilters' | translate}}</a></span>
+      </accordion-heading>
+      <table class="table repos-table">
+        <tbody>
+        <tr ng-repeat="repo in stackVersion.repos">
+          <td class="repos-td">
+            <a href="#/stackVersions/{{repo.stack_name}}/{{repo.repository_version}}/edit">{{repo.repository_version}}</a>
+          </td>
+        </tr>
+        </tbody>
+        </table>
+    </accordion-group>
+    <div class="alert alert-info" ng-show="stackVersions && !stackVersions.length">
+      {{'versions.contents.empty' | translate}}
     </div>
-    <div class="pull-right left-margin">
-      <pagination class="paginator"
-                  total-items="pagination.totalRepos"
-                  max-size="pagination.maxVisiblePages"
-                  items-per-page="pagination.itemsPerPage"
-                  ng-model="pagination.currentPage"
-                  ng-change="pageChanged()"
-        ></pagination>
-    </div>
-    <div class="pull-right">
-      <select class="form-control"
-              ng-model="pagination.itemsPerPage"
-              ng-options="item for item in [10, 25, 50, 100]"
-              ng-change="resetPagination()"
-        ></select>
+  </accordion>
+
+  <form class="col-sm-10 form-horizontal" role="form"novalidate>
+    <div class="alert alert-info no-version-alert">
+      {{'versions.noVersions' | translate}}
     </div>
-  </div>
+  </form>
+
 </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/0f9da428/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html
index 61d2d8d..1fad9a3 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html
@@ -23,14 +23,15 @@
     <li class="active" ng-if="createController">{{'versions.register' | translate}}</li>
   </ol>
 
-  <div class="pull-right top-margin-4" ng-switch="deleteEnabled"  ng-if="editController">
-    <button ng-switch-when="false" class="btn disabled btn-default" tooltip="Cannot delete version already installed.">{{'versions.deregister' | translate}}</button>
-    <button ng-switch-when="true" class="btn btn-danger" ng-click="delete()">{{'versions.deregister' | translate}}</button>
+  <div class="pull-right top-margin-4">
+    <a href="#/stackVersions/create" class="btn btn-primary">
+      <span class="glyphicon glyphicon-plus"></span>
+        {{'versions.register' | translate}}
+    </a>
   </div>
 </div>
 <hr>
 
-
 <div id="upload-definition-file-panel" ng-if="createController">
   <div class="clearfix register-version-options">
     <div class="col-sm-5 option-radio-button">
@@ -60,10 +61,37 @@
   </div>
 </div>
 
-<form class="form-horizontal register-version-form" role="form" name="repoRegForm" novalidate>
-  <div class="panel panel-default">
+<accordion close-others="false" class="col-sm-2 left-menu-all-repos" ng-if="editController">
+  <accordion-group ng-repeat="stackVersion in stackVersions" is-open="stackVersion.isOpened">
+    <accordion-heading>
+      <div class="row stack-version-title">
+        <i class="glyphicon glyphicon-chevron-right" ng-class="{'opened': stackVersion.isOpened}"></i>
+          {{stackVersion.name}}
+      </div>
+    </accordion-heading>
+    <table class="table repos-table">
+      <tbody>
+      <tr ng-repeat="repo in stackVersion.repos">
+        <td class="repos-td" ng-class="{'active': repo.isActive}">
+            <a href="#/stackVersions/{{repo.stack_name}}/{{repo.repository_version}}/edit">{{repo.repository_version}}</a>
+        </td>
+      </tr>
+      </tbody>
+    </table>
+  </accordion-group>
+  <div class="alert alert-info" ng-show="stackVersions && !stackVersions.length">
+    {{'versions.contents.empty' | translate}}
+  </div>
+</accordion>
+
+<form ng-class="{'col-sm-10': editController}" class="form-horizontal register-version-form" role="form" name="repoRegForm" novalidate>
+  <div class="panel panel-default details-panel">
     <div class="panel-heading">
       <h3 class="panel-title">{{'common.details' | translate}}</h3>
+        <div class="pull-right deregister-button" ng-switch="deleteEnabled"  ng-if="editController">
+            <button ng-switch-when="false" class="btn disabled btn-default" tooltip="Cannot delete version already installed.">{{'versions.deregister' | translate}}</button>
+            <button ng-switch-when="true" class="btn btn-danger" ng-click="delete()">{{'versions.deregister' | translate}}</button>
+        </div>
     </div>
     <div class="panel-body">
       <div class="clearfix">
@@ -85,7 +113,7 @@
       </div>
     </div>
   </div>
-  <div class="panel panel-default">
+  <div class="panel panel-default contents-panel">
     <div class="panel-heading">
       <h3 class="panel-title">{{'versions.contents.title' | translate}}</h3>
     </div>
@@ -97,7 +125,7 @@
       </div>
     </div>
   </div>
-  <div class="panel panel-default">
+  <div class="panel panel-default repos-panel">
     <div class="panel-heading">
       <h3 class="panel-title">{{'versions.repos' | translate}}</h3>
     </div>
@@ -114,10 +142,8 @@
         <div ng-if="os.selected==true">
           <div class="clearfix border-bottom bottom-margin">
             <!-- show selected os in list table-->
-            <div class="col-sm-2">
-              <div class="">
-                <label>{{os.OperatingSystems.os_type}}</label>
-              </div>
+            <div class="col-sm-2 os-type-label">
+              <label>{{os.OperatingSystems.os_type}}</label>
             </div>
             <div class="col-sm-9">
               <div class="form-group {{repository.Repositories.repo_name}}" ng-class="{'has-error': repository.hasError }" ng-repeat="repository in os.repositories">

http://git-wip-us.apache.org/repos/asf/ambari/blob/0f9da428/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/stackVersions/StackversionsListCtrl_test.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/stackVersions/StackversionsListCtrl_test.js b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/stackVersions/StackversionsListCtrl_test.js
index 1e47c20..6f168db 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/stackVersions/StackversionsListCtrl_test.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/test/unit/controllers/stackVersions/StackversionsListCtrl_test.js
@@ -40,157 +40,5 @@ describe('#Cluster', function () {
 
     });
 
-    describe('#fillClusters()', function () {
-
-      var clusters = [
-          {
-            Clusters: {
-              cluster_name: 'c0'
-            }
-          }
-        ],
-        cases = [
-          {
-            prev: null,
-            current: {
-              label: 'All',
-              value: ''
-            },
-            title: 'no cluster selected before'
-          },
-          {
-            prev: {
-              label: 'c0',
-              value: 'c0'
-            },
-            current: {
-              label: 'c0',
-              value: 'c0'
-            },
-            title: 'cluster was selected before'
-          }
-        ];
-
-      angular.forEach(cases, function (item) {
-        it(item.title, function() {
-          scope.filter.cluster.current = item.prev;
-          scope.fillClusters(clusters);
-          expect(scope.dropDownClusters).toEqual(clusters);
-          expect(scope.filter.cluster.current).toEqual(item.current);
-        });
-      });
-
-    });
-
-    describe('#isNotEmptyFilter', function () {
-
-      var cases = [
-        {
-          filter: {
-            version: '',
-            cluster: {
-              current: null
-            }
-          },
-          isNotEmptyFilter: false,
-          title: 'no filters'
-        },
-        {
-          filter: {
-            version: '',
-            cluster: {
-              current: {
-                value: ''
-              }
-            }
-          },
-          isNotEmptyFilter: false,
-          title: 'empty filters'
-        },
-        {
-          filter: {
-            version: 'a',
-            cluster: {
-              current: {
-                value: ''
-              }
-            }
-          },
-          isNotEmptyFilter: true,
-          title: 'version filter'
-        },
-        {
-          filter: {
-            version: '0',
-            cluster: {
-              current: {
-                value: ''
-              }
-            }
-          },
-          isNotEmptyFilter: true,
-          title: 'version filter with "0" as string'
-        },
-        {
-          filter: {
-            version: '',
-            cluster: {
-              current: {
-                value: 'a'
-              }
-            }
-          },
-          isNotEmptyFilter: true,
-          title: 'cluster filter'
-        },
-        {
-          filter: {
-            version: '',
-            cluster: {
-              current: {
-                value: '0'
-              }
-            }
-          },
-          isNotEmptyFilter: true,
-          title: 'cluster filter with "0" as string'
-        },
-        {
-          filter: {
-            version: 'a',
-            cluster: {
-              current: {
-                value: 'a'
-              }
-            }
-          },
-          isNotEmptyFilter: true,
-          title: 'both filters'
-        },
-        {
-          filter: {
-            version: '0',
-            cluster: {
-              current: {
-                value: '0'
-              }
-            }
-          },
-          isNotEmptyFilter: true,
-          title: 'both filters with "0" as string'
-        }
-      ];
-
-      cases.forEach(function (item) {
-        it(item.title, function () {
-          $httpBackend.expectGET(/\/api\/v1\/clusters\?_=\d+/).respond(200);
-          scope.filter = item.filter;
-          scope.$digest();
-          expect(scope.isNotEmptyFilter).toEqual(item.isNotEmptyFilter);
-        });
-      });
-
-    });
-
   });
 });