You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by ab...@apache.org on 2015/01/21 13:27:50 UTC

ambari git commit: AMBARI-9232 Add Repo Base URL Validation as well as "Skip". (ababiichuk)

Repository: ambari
Updated Branches:
  refs/heads/trunk ea9e63662 -> 80202b89e


AMBARI-9232 Add Repo Base URL Validation as well as "Skip". (ababiichuk)


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

Branch: refs/heads/trunk
Commit: 80202b89e0525791b7b2a480e99981bfe343f17c
Parents: ea9e636
Author: aBabiichuk <ab...@cybervisiontech.com>
Authored: Wed Jan 21 13:39:45 2015 +0200
Committer: aBabiichuk <ab...@cybervisiontech.com>
Committed: Wed Jan 21 14:27:37 2015 +0200

----------------------------------------------------------------------
 .../stackVersions/StackVersionsCreateCtrl.js    | 123 ++++++++++++++-----
 .../stackVersions/StackVersionsEditCtrl.js      | 102 ++++++++++++---
 .../ui/admin-web/app/scripts/routes.js          |   4 +-
 .../ui/admin-web/app/scripts/services/Stack.js  |  62 ++++++++--
 .../app/views/stackVersions/create.html         |  94 --------------
 .../admin-web/app/views/stackVersions/edit.html |  81 ------------
 .../views/stackVersions/stackVersionPage.html   | 110 +++++++++++++++++
 7 files changed, 346 insertions(+), 230 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/80202b89/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 e62d227..a828086 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
@@ -19,6 +19,12 @@
 
 angular.module('ambariAdminConsole')
 .controller('StackVersionsCreateCtrl', ['$scope', 'Stack', '$routeParams', '$location', 'Alert', function($scope, Stack, $routeParams, $location, Alert) {
+  $scope.createController = true;
+  $scope.osList = [];
+  $scope.skipValidation = false;
+  $scope.selectedOS = 0;
+  $scope.repoSubversion = "";
+
   $scope.clusterName = $routeParams.clusterName;
   $scope.subversionPattern = /^\d(\.\d)?(\-\d*)?$/;
   $scope.upgradeStack = {
@@ -43,26 +49,26 @@ angular.module('ambariAdminConsole')
     });
   };
   $scope.fetchStackVersionFilterList();
-  $scope.repositories = [];
-
-  $scope.selectedOS = 0;
-  $scope.toggleOSSelect = function () {
-    this.repository.selected? $scope.selectedOS++ : $scope.selectedOS--;
-  };
 
-  $scope.create = function () {
-    return Stack.addRepo($scope.upgradeStack.selected, $scope.repoSubversion, $scope.repositories)
-    .success(function () {
-      var versionName = $scope.upgradeStack.selected.stack_version + '.' + $scope.repoSubversion;
-      var stackName = $scope.upgradeStack.selected.stack_name;
-      Alert.success('Created version ' +
-      '<a href="#/stackVersions/' + stackName + '/' + versionName + '/edit">'
-        + stackName + "-" + versionName +
-      '</a>');
-      $location.path('/stackVersions');
-    })
-    .error(function (data) {
-        Alert.error('Version creation error', data.message);
+  $scope.save = function () {
+    return Stack.validateBaseUrls($scope.skipValidation, $scope.osList, $scope.upgradeStack.selected).then(function (invalidUrls) {
+      if (invalidUrls.length === 0) {
+        Stack.addRepo($scope.upgradeStack.selected, $scope.repoSubversion, $scope.osList)
+          .success(function () {
+            var versionName = $scope.upgradeStack.selected.stack_version + '.' + $scope.repoSubversion;
+            var stackName = $scope.upgradeStack.selected.stack_name;
+            Alert.success('Created version ' +
+            '<a href="#/stackVersions/' + stackName + '/' + versionName + '/edit">'
+              + stackName + versionName +
+            '</a>');
+            $location.path('/stackVersions');
+          })
+          .error(function (data) {
+              Alert.error('Version creation error', data.message);
+          });
+      } else {
+        Stack.highlightInvalidUrls(invalidUrls);
+      }
     });
   };
 
@@ -71,17 +77,13 @@ angular.module('ambariAdminConsole')
     .then(function (data) {
       //TODO map data.operating_systems after API is fixed
       var operatingSystems = data.operating_systems || data.operatingSystems;
-      var repositories = operatingSystems.map(function (os) {
-        return {
-          os: os.OperatingSystems.os_type,
-          packages: [
-            {label:'HDP', value: null},
-            {label:'HDP-UTILS', value: null}
-          ],
-          selected: false
-        };
-      });
-      $scope.repositories = repositories;
+        $scope.osList = operatingSystems.map(function (os) {
+          os.selected = false;
+          os.repositories.forEach(function(repo) {
+            repo.Repositories.base_url = '';
+          });
+          return os;
+        });
     })
     .catch(function (data) {
       Alert.error('getSupportedOSList error', data.message);
@@ -91,4 +93,65 @@ angular.module('ambariAdminConsole')
   $scope.updateCurrentVersionInput = function () {
     $scope.currentVersionInput = $scope.upgradeStack.selected.displayName + '.' + angular.element('[name="version"]')[0].value;
   };
+
+  /**
+   * 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) {
+        if (os.repositories) {
+          os.repositories.forEach(function(repo) {
+            repo.hasError = false;
+          })
+        }
+      });
+    }
+  };
+  /**
+   * 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) {
+      $scope.osList.forEach(function(os) {
+        if (os.repositories) {
+          os.repositories.forEach(function(repo) {
+            if (repo.hasError) {
+              hasErrors = true;
+            }
+          })
+        }
+      });
+    }
+    return hasErrors;
+  };
+  /**
+   * TODO create parent controller for StackVersionsEditCtrl and StackVersionsCreateCtrl and
+   * move this method to it
+   */
+  $scope.cancel = function () {
+    $scope.editVersionDisabled = true;
+    $location.path('/stackVersions');
+  };
+
 }]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/80202b89/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 66b51df..47e4bd3 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
@@ -19,6 +19,11 @@
 
 angular.module('ambariAdminConsole')
 .controller('StackVersionsEditCtrl', ['$scope', '$location', 'Cluster', 'Stack', '$routeParams', 'ConfirmationModal', 'Alert', function($scope, $location, Cluster, Stack, $routeParams, ConfirmationModal, Alert) {
+  $scope.editController = true;
+  $scope.osList = [];
+  $scope.skipValidation = false;
+  $scope.selectedOS = 0;
+
   $scope.loadStackVersionInfo = function () {
     return Stack.getRepo($routeParams.versionId, $routeParams.stackName).then(function (response) {
       $scope.id = response.id;
@@ -27,6 +32,7 @@ angular.module('ambariAdminConsole')
       $scope.versionName = response.versionName;
       $scope.stackVersion = response.stackVersion;
       $scope.updateObj = response.updateObj;
+      $scope.subversion = response.versionName.substring(4); // cut off stack version
       //save default values of repos to check if they were changed
       $scope.defaulfOSRepos = {};
       response.updateObj.operating_systems.forEach(function(os) {
@@ -39,6 +45,7 @@ angular.module('ambariAdminConsole')
       angular.forEach(response.osList, function (os) {
         os.selected = true;
       });
+      $scope.selectedOS = response.osList.length;
       $scope.osList = response.osList;
       // if user reach here from UI click, repo status should be cached
       // otherwise re-fetch repo status from cluster end point.
@@ -100,12 +107,10 @@ angular.module('ambariAdminConsole')
     .catch(function (data) {
       Alert.error('getSupportedOSList error', data.message);
     });
-  }
+  };
 
   $scope.defaulfOSRepos = {};
 
-  $scope.skipValidation = false;
-
   $scope.save = function () {
     $scope.editVersionDisabled = true;
     delete $scope.updateObj.href;
@@ -115,7 +120,7 @@ angular.module('ambariAdminConsole')
       var savedUrls = $scope.defaulfOSRepos[os.OperatingSystems.os_type];
       if (os.selected) {
         var currentRepos = os.repositories;
-        if (currentRepos[0].Repositories.base_url != savedUrls.defaultBaseUrl
+        if (!savedUrls || currentRepos[0].Repositories.base_url != savedUrls.defaultBaseUrl
             || currentRepos[1].Repositories.base_url != savedUrls.defaultUtilsUrl) {
           updateRepoUrl = true;
         }
@@ -134,19 +139,24 @@ angular.module('ambariAdminConsole')
   };
 
   $scope.updateRepoVersions = function () {
-    Stack.updateRepo($scope.stackName, $scope.stackVersion, $scope.id, $scope.updateObj).then(function () {
-      Alert.success('Edited version <a href="#/stackVersions/' + $scope.stackName + '/' + $scope.versionName + '/edit">' + $scope.repoVersionFullName + '</a>');
-      $location.path('/stackVersions');
-    }).catch(function (data) {
-      Alert.error('Version update error', data.message);
+    var upgradeStack = {
+      stack_name: $scope.stackName,
+      stack_version: $scope.stackVersion
+    };
+    return Stack.validateBaseUrls($scope.skipValidation, $scope.osList, upgradeStack).then(function (invalidUrls) {
+      if (invalidUrls.length === 0) {
+        Stack.updateRepo($scope.stackName, $scope.stackVersion, $scope.id, $scope.updateObj).then(function () {
+          Alert.success('Edited version <a href="#/stackVersions/' + $scope.stackName + '/' + $scope.versionName + '/edit">' + $scope.repoVersionFullName + '</a>');
+          $location.path('/stackVersions');
+        }).catch(function (data) {
+          Alert.error('Version update error', data.message);
+        });
+      } else {
+        Stack.highlightInvalidUrls(invalidUrls);
+      }
     });
   };
 
-  $scope.cancel = function () {
-    $scope.editVersionDisabled = true;
-    $location.path('/stackVersions');
-  };
-
   $scope.fetchRepoClusterStatus = function () {
     var clusterName = $scope.clusters[0].Clusters.cluster_name; // only support one cluster at the moment
     return Cluster.getRepoVersionStatus(clusterName, $scope.id).then(function (response) {
@@ -171,4 +181,68 @@ angular.module('ambariAdminConsole')
     });
   };
   $scope.loadStackVersionInfo();
+    
+  /**
+   * 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) {
+        if (os.repositories) {
+          os.repositories.forEach(function(repo) {
+            repo.hasError = false;
+          })
+        }
+      });
+    }
+  };
+  /**
+   * 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) {
+      $scope.osList.forEach(function (os) {
+        if (os.repositories) {
+          os.repositories.forEach(function (repo) {
+            if (repo.hasError) {
+              hasErrors = true;
+            }
+          })
+        }
+      });
+    }
+    return hasErrors;
+  };
+
+  /**
+   * TODO create parent controller for StackVersionsEditCtrl and StackVersionsCreateCtrl and
+   * move this method to it
+   */
+  $scope.cancel = function () {
+    $scope.editVersionDisabled = true;
+    $location.path('/stackVersions');
+  };
+
 }]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/80202b89/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
index f86a47f..f34d931 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
@@ -88,12 +88,12 @@ angular.module('ambariAdminConsole')
     },
     create: {
       url: '/stackVersions/create',
-      templateUrl: 'views/stackVersions/create.html',
+      templateUrl: 'views/stackVersions/stackVersionPage.html',
       controller: 'StackVersionsCreateCtrl'
     },
     edit: {
       url: '/stackVersions/:stackName/:versionId/edit',
-      templateUrl: 'views/stackVersions/edit.html',
+      templateUrl: 'views/stackVersions/stackVersionPage.html',
       controller: 'StackVersionsEditCtrl'
     }
   },

http://git-wip-us.apache.org/repos/asf/ambari/blob/80202b89/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 83bd21a..681b844 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
@@ -122,19 +122,19 @@ angular.module('ambariAdminConsole')
       payload.repository_version = stack.stack_version + '.' + repoSubversion;
       payload.display_name = stack.stack_name + '-' + payload.repository_version;
       payloadWrap.operating_systems = [];
-      angular.forEach(osList, function (osItem) {
+      osList.forEach(function (osItem) {
         if (osItem.selected)
         {
           payloadWrap.operating_systems.push({
             "OperatingSystems" : {
-              "os_type" : osItem.os
+              "os_type" : osItem.OperatingSystems.os_type
             },
-            "repositories" : osItem.packages.map(function (pack) {
+            "repositories" : osItem.repositories.map(function (repo) {
               return {
                 "Repositories" : {
-                  "repo_id": (pack.label + '-' + payload.repository_version),
-                  "repo_name": pack.label,
-                  "base_url": pack.value? pack.value : ''
+                  "repo_id": repo.Repositories.repo_id,
+                  "repo_name": repo.Repositories.repo_name,
+                  "base_url": repo.Repositories.base_url
                 }
               };
             })
@@ -197,10 +197,9 @@ angular.module('ambariAdminConsole')
     },
 
     getSupportedOSList: function (stackName, stackVersion) {
-      //http://c6401.ambari.apache.org:8080/api/v1/stacks/HDP/versions/2.2?fields=operating_systems
-      var url = Settings.baseUrl + '/stacks/' + stackName + '/versions/' + stackVersion + '?fields=operating_systems'
+      var url = Settings.baseUrl + '/stacks/' + stackName + '/versions/' + stackVersion + '?fields=operating_systems/repositories/Repositories'
       var deferred = $q.defer();
-      $http.get(url, {mock: 'stacks/operatingSystems.json'})
+      $http.get(url, {mock: 'stack/operatingSystems.json'})
       .success(function (data) {
         deferred.resolve(data);
       })
@@ -208,6 +207,51 @@ angular.module('ambariAdminConsole')
         deferred.reject(data);
       });
       return deferred.promise;
+    },
+
+    validateBaseUrls: function(skip, osList, stack) {
+      var deferred = $q.defer(),
+        url = Settings.baseUrl + '/stacks/' + stack.stack_name + '/versions/' + stack.stack_version,
+        totalCalls = 0,
+        invalidUrls = [];
+
+      if (skip) {
+        deferred.resolve(invalidUrls);
+      } else {
+        osList.forEach(function (os) {
+          if (os.selected) {
+            os.repositories.forEach(function (repo) {
+              totalCalls++;
+              $http.post(url + '/operating_systems/' + os.OperatingSystems.os_type + '/repositories/' + repo.Repositories.repo_id + '?validate_only=true',
+                {
+                  "Repositories": {
+                    "base_url": repo.Repositories.base_url
+                  }
+                },
+                {
+                  repo: repo
+                }
+              )
+                .success(function () {
+                  totalCalls--;
+                  if (totalCalls === 0) deferred.resolve(invalidUrls);
+                })
+                .error(function (response, status, callback, params) {
+                  invalidUrls.push(params.repo);
+                  totalCalls--;
+                  if (totalCalls === 0) deferred.resolve(invalidUrls);
+                });
+            });
+          }
+        });
+      }
+      return deferred.promise;
+    },
+
+    highlightInvalidUrls :function(invalidrepos) {
+      invalidrepos.forEach(function(repo) {
+        repo.hasError = true;
+      });
     }
 
   };

http://git-wip-us.apache.org/repos/asf/ambari/blob/80202b89/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/create.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/create.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/create.html
deleted file mode 100644
index f0e3ef4..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/create.html
+++ /dev/null
@@ -1,94 +0,0 @@
-<!--
-* 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.
--->
-
-<ol class="breadcrumb">
-  <li><a href="#/stackVersions">Versions</a></li>
-  <li class="active">Register Version</li>
-</ol>
-<hr>
-<form class="form-horizontal register-version-form" role="form" name="repoRegForm" novalidate>
-  <div class="panel panel-default">
-    <div class="panel-heading">
-      <h3 class="panel-title">Details</h3>
-    </div>
-    <div class="panel-body">
-      <div class="form-inline repo-version-inline">
-        <label class="control-label col-sm-2 repo-version-label">Version</label>
-        <div class="col-sm-10">
-          <select class="form-control repo-version-select"
-                  ng-model="upgradeStack.selected"
-                  ng-options="o as o.displayName for o in upgradeStack.options"
-                  ng-change="afterStackVersionChange()">
-          </select>
-          <span class="bold-dot">.</span>
-          <div class="form-group" ng-class="{'has-error' : repoRegForm.version.$error.pattern}">
-            <input class="form-control" name="version" type="text" ng-model="repoSubversion" ng-pattern="subversionPattern"
-                   placeholder="Version Name" ng-change="updateCurrentVersionInput()" required/>
-            <span class="text-danger" ng-show="repoRegForm.version.$error.pattern">
-              &nbsp{{currentVersionInput}} Invalid.
-            </span>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-  <div class="panel panel-default">
-    <div class="panel-heading">
-      <h3 class="panel-title">Repositories</h3>
-    </div>
-    <div class="panel-body ">
-      <div class="alert alert-info" role="alert">
-        Provide Base URLs for the Operating Systems you are configuring. Uncheck all other Operating Systems.
-      </div>
-      <div class="border-bottom bottom-margin clearfix">
-        <div class="col-sm-2"><h5><label>OS</label></h5></div>
-        <div class="name-label-adjust col-sm-2"><h5><label>Name</label></h5></div>
-        <div class="col-sm-7"><h5><label>Base URL</label></h5></div>
-      </div>
-      <div class="clearfix border-bottom bottom-margin" ng-repeat="repository in repositories">
-        <div class="col-sm-2">
-          <div class="checkbox">
-            <label>
-              <input type="checkbox" ng-model="repository.selected" ng-change="toggleOSSelect()"> {{repository.os}}
-            </label>
-          </div>
-        </div>
-        <div class="col-sm-10">
-          <div class="form-group" ng-repeat="package in repository.packages">
-            <div class="col-sm-3"><label class="control-label">{{package.label}}</label></div>
-            <div class="col-sm-9"><input type="text" class="form-control" ng-model="package.value"></div>
-          </div>
-        </div>
-      </div>
-      <div class="clearfix">
-        <div class="col-sm-12">
-          <div class="checkbox">
-            <label>
-              <input type="checkbox" ng-model="repository.selected"> Skip Repository Base URL validation (Advanced) <span class="glyphicon glyphicon-question-sign" tooltip-html-unsafe="<b>Warning:</b> This is for advanced users only. Use this option if you want to skip validation for Repository Base URLs."></span>
-            </label>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-  <div class="col-sm-12">
-    <button class="btn btn-primary pull-right left-margin" ng-click="create()"
-            ng-disabled="repoRegForm.version.$invalid || selectedOS === 0">Save</button>
-    <button class="btn btn-default pull-right">Cancel</button>
-  </div>
-</form>

http://git-wip-us.apache.org/repos/asf/ambari/blob/80202b89/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/edit.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/edit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/edit.html
deleted file mode 100644
index 30c3d2d..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/edit.html
+++ /dev/null
@@ -1,81 +0,0 @@
-<!--
-* 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.
--->
-
-<div class="clearfix">
-  <ol class="breadcrumb pull-left">
-    <li><a href="#/stackVersions">Versions</a></li>
-    <li class="active">{{repoVersionFullName}}</li>
-  </ol>
-  <div class="pull-right top-margin-4" ng-switch="deleteEnabled">
-    <button ng-switch-when="false" class="btn disabled btn-default" tooltip="Cannot Delete Static Instances">Deregister
-      Version
-    </button>
-    <button ng-switch-when="true" class="btn btn-danger" ng-click="delete()">Deregister Version
-    </button>
-  </div>
-</div>
-<hr>
-<form class="form-horizontal edit-version-form" role="form" name="form-editVersionForm" novalidate>
-  <div class="panel panel-default">
-    <div class="panel-heading clearfix">
-      <h3 class="panel-title pull-left">Repositories</h3>
-      <div class="pull-right" ng-switch="editReposDisabled">
-        <a href ng-switch-when="true" ng-click="toggleReposEdit()" class="settings-edit-toggle"> <span class="glyphicon glyphicon-pencil" ></span> Edit</a>
-        <span ng-switch-when="false"> <span class="glyphicon glyphicon-pencil" ></span> Edit</span>
-      </div>
-    </div>
-    <div class="panel-body ">
-      <div class="alert alert-info" role="alert">
-        Provide Base URLs for the Operating Systems you are configuring. Uncheck all other Operating Systems.
-      </div>
-      <div class="border-bottom bottom-margin clearfix">
-        <div class="col-sm-2"><h5><label>OS</label></h5></div>
-        <div class="name-label-adjust col-sm-2"><h5><label>Name</label></h5></div>
-        <div class="col-sm-7"><h5><label>Base URL</label></h5></div>
-      </div>
-      <div class="clearfix border-bottom bottom-margin" ng-repeat="os in osList">
-        <div class="col-sm-2">
-          <div class="checkbox">
-            <label>
-              <input type="checkbox" ng-model="os.selected"> {{os.OperatingSystems.os_type}}
-            </label>
-          </div>
-        </div>
-        <div class="col-sm-10">
-          <div class="form-group" ng-repeat="repository in os.repositories">
-            <div class="col-sm-3"><label class="control-label">{{repository.Repositories.repo_name}}</label></div>
-            <div class="col-sm-9"><input type="text" class="form-control" ng-model="repository.Repositories.base_url"></div>
-          </div>
-        </div>
-      </div>
-      <div class="clearfix">
-        <div class="col-sm-12">
-          <div class="checkbox">
-            <label>
-              <input type="checkbox" ng-model="skipValidation"> Skip Repository Base URL validation (Advanced) <span class="glyphicon glyphicon-question-sign" tooltip-html-unsafe="<b>Warning:</b> This is for advanced users only. Use this option if you want to skip validation for Repository Base URLs."></span>
-            </label>
-          </div>
-        </div>
-      </div>
-    </div>
-  </div>
-  <div class="col-sm-12">
-    <button class="btn btn-primary pull-right left-margin" ng-click="save()">Save</button>
-    <button class="btn btn-default pull-right" ng-click="cancel()">Cancel</button>
-  </div>
-</form>

http://git-wip-us.apache.org/repos/asf/ambari/blob/80202b89/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
new file mode 100644
index 0000000..11d42f9
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/stackVersionPage.html
@@ -0,0 +1,110 @@
+<!--
+* 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.
+-->
+
+<div class="clearfix">
+  <ol class="breadcrumb pull-left">
+    <li><a href="#/stackVersions">Versions</a></li>
+    <li class="active" ng-if="editController">{{repoVersionFullName}}</li>
+    <li class="active" ng-if="createController">Register Version</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 Static Instances">Deregister
+      Version
+    </button>
+    <button ng-switch-when="true" class="btn btn-danger" ng-click="delete()">Deregister Version
+    </button>
+  </div>
+</div>
+<hr>
+<form class="form-horizontal register-version-form" role="form" name="repoRegForm" novalidate>
+  <div class="panel panel-default" ng-if="createController">
+    <div class="panel-heading">
+      <h3 class="panel-title">Details</h3>
+    </div>
+    <div class="panel-body">
+      <div class="form-inline repo-version-inline">
+        <label class="control-label col-sm-2 repo-version-label">Version</label>
+        <div class="col-sm-10">
+          <select class="form-control repo-version-select"
+                  ng-model="upgradeStack.selected"
+                  ng-options="o as o.displayName for o in upgradeStack.options"
+                  ng-change="afterStackVersionChange()">
+          </select>
+          <span class="bold-dot">.</span>
+          <div class="form-group" ng-class="{'has-error' : repoRegForm.version.$error.pattern}">
+            <input class="form-control" name="version" type="text" ng-model="repoSubversion" ng-pattern="subversionPattern"
+                   placeholder="Version Name" ng-change="updateCurrentVersionInput()" required/>
+            <span class="text-danger" ng-show="repoRegForm.version.$error.pattern">
+              &nbsp{{currentVersionInput}} Invalid.
+            </span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+  <div class="panel panel-default">
+    <div class="panel-heading">
+      <h3 class="panel-title">Repositories</h3>
+    </div>
+    <div class="panel-body ">
+      <div class="alert alert-info" role="alert">
+        Provide Base URLs for the Operating Systems you are configuring. Uncheck all other Operating Systems.
+      </div>
+      <div class="alert alert-warning hide-soft" ng-class="{'visible' : hasValidationErrors()}" role="alert">
+        Some of the repositories failed validation. Make changes to the base url or skip validation if you are sure that urls are correct
+      </div>
+      <div class="border-bottom bottom-margin clearfix">
+        <div class="col-sm-2"><h5><label>OS</label></h5></div>
+        <div class="name-label-adjust col-sm-2"><h5><label>Name</label></h5></div>
+        <div class="col-sm-7"><h5><label>Base URL</label></h5></div>
+      </div>
+      <div class="clearfix border-bottom bottom-margin" ng-repeat="os in osList">
+        <div class="col-sm-2">
+          <div class="checkbox">
+            <label>
+              <input type="checkbox" ng-model="os.selected" ng-change="toggleOSSelect()"> {{os.OperatingSystems.os_type}}
+            </label>
+          </div>
+        </div>
+        <div class="col-sm-10">
+          <div class="form-group" ng-class="{'has-error': repository.hasError }" ng-repeat="repository in os.repositories">
+            <div class="col-sm-3"><label class="control-label">{{repository.Repositories.repo_name}}</label></div>
+            <div class="col-sm-9"><input type="text" class="form-control" ng-model="repository.Repositories.base_url"
+                                         ng-change="clearError()"></div>
+          </div>
+        </div>
+      </div>
+      <div class="clearfix">
+        <div class="col-sm-12">
+          <div class="checkbox">
+            <label>
+              <input type="checkbox" ng-model="skipValidation" ng-change="clearErrors()">
+              Skip Repository Base URL validation (Advanced) <span class="glyphicon glyphicon-question-sign" tooltip-html-unsafe="<b>Warning:</b> This is for advanced users only. Use this option if you want to skip validation for Repository Base URLs."></span>
+            </label>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+  <div class="col-sm-12">
+    <button class="btn btn-primary pull-right left-margin" ng-click="save()"
+            ng-disabled="(createController && repoRegForm.version.$invalid) || selectedOS === 0">Save</button>
+    <button class="btn btn-default pull-right" ng-click="cancel()">Cancel</button>
+  </div>
+</form>