You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by al...@apache.org on 2015/04/17 05:18:04 UTC

ambari git commit: AMBARI-10544. Views: FE work for adding the ability for a view instance to be associated to a cluster for configuration (alexantonenko)

Repository: ambari
Updated Branches:
  refs/heads/trunk 23f7428a0 -> 68c68a6f0


AMBARI-10544. Views: FE work for adding the ability for a view instance to be associated to a cluster for configuration (alexantonenko)


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

Branch: refs/heads/trunk
Commit: 68c68a6f0eb09f0bbdd530c9c9e1baa8dbfa9828
Parents: 23f7428
Author: Alex Antonenko <hi...@gmail.com>
Authored: Fri Apr 17 06:17:28 2015 +0300
Committer: Alex Antonenko <hi...@gmail.com>
Committed: Fri Apr 17 06:17:28 2015 +0300

----------------------------------------------------------------------
 .../ambariViews/CreateViewInstanceCtrl.js       |  37 ++++-
 .../controllers/ambariViews/ViewsEditCtrl.js    | 149 +++++++++++++------
 .../ui/admin-web/app/scripts/services/View.js   |  37 +++--
 .../resources/ui/admin-web/app/styles/main.css  |  28 +++-
 .../admin-web/app/views/ambariViews/create.html |  68 ++++++---
 .../admin-web/app/views/ambariViews/edit.html   |  63 ++++++--
 6 files changed, 284 insertions(+), 98 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/68c68a6f/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
index 2492c91..e6c047b 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/CreateViewInstanceCtrl.js
@@ -18,22 +18,28 @@
 'use strict';
 
 angular.module('ambariAdminConsole')
-.controller('CreateViewInstanceCtrl',['$scope', 'View', 'Alert', '$routeParams', '$location', 'UnsavedDialog', function($scope, View, Alert, $routeParams, $location, UnsavedDialog) {
+.controller('CreateViewInstanceCtrl',['$scope', 'View', 'Alert', 'Cluster', '$routeParams', '$location', 'UnsavedDialog', function($scope, View, Alert, Cluster, $routeParams, $location, UnsavedDialog) {
   $scope.form = {};
   var targetUrl = '';
 
   function loadMeta(){
     View.getMeta($routeParams.viewId, $scope.version).then(function(data) {
-      var viewVersion = data.data;
-      $scope.view = viewVersion;
+      var viewVersion = data.data,
+        parameters;
 
-      var parameters = viewVersion.ViewVersionInfo.parameters;
+      $scope.view = viewVersion;
+      parameters = viewVersion.ViewVersionInfo.parameters;
 
       angular.forEach(parameters, function (item) {
         item.value = item['defaultValue'];
+        item.clusterConfig = !!item.clusterConfig;
         item.displayName = item.name.replace(/\./g, '\.\u200B');
+        $scope.numberOfClusterConfigs = item.clusterConfig ? $scope.numberOfClusterConfigs+1 : $scope.numberOfClusterConfigs;
       });
 
+      $scope.clusterConfigurable = viewVersion.ViewVersionInfo.cluster_configurable;
+      $scope.clusterConfigurableErrorMsg = $scope.clusterConfigurable ? "" : "This view cannot use this option";
+
       $scope.instance = {
         view_name: viewVersion.ViewVersionInfo.view_name,
         version: viewVersion.ViewVersionInfo.version,
@@ -43,7 +49,8 @@ angular.module('ambariAdminConsole')
         icon_path: '',
         icon64_path: '',
         properties: parameters,
-        description: ''
+        description: '',
+        isLocalCluster: false
       };
     });
   }
@@ -61,6 +68,25 @@ angular.module('ambariAdminConsole')
   $scope.isAdvancedClosed = true;
   $scope.instanceExists = false;
 
+  $scope.clusterConfigurable = false;
+  $scope.clusterConfigurableErrorMsg = "";
+  $scope.clusters = [];
+  $scope.noClusterAvailible = true;
+  $scope.cluster = null;
+  $scope.numberOfClusterConfigs = 0;
+
+  Cluster.getAllClusters().then(function (clusters) {
+    if(clusters.length >0){
+      clusters.forEach(function(cluster) {
+        $scope.clusters.push(cluster.Clusters.cluster_name)
+      });
+      $scope.noClusterAvailible = false;
+    }else{
+      $scope.clusters.push("No Clusters");
+    }
+    $scope.cluster = $scope.clusters[0];
+  });
+
   $scope.versions = [];
   $scope.version = null;
 
@@ -77,6 +103,7 @@ angular.module('ambariAdminConsole')
     $scope.form.instanceCreateForm.submitted = true;
     if($scope.form.instanceCreateForm.$valid){
       $scope.form.instanceCreateForm.isSaving = true;
+      $scope.instance.clusterName = $scope.cluster;
       View.createInstance($scope.instance)
         .then(function(data) {
           Alert.success('Created View Instance ' + $scope.instance.instance_name);

http://git-wip-us.apache.org/repos/asf/ambari/blob/68c68a6f/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js
index cbf3b0c..ab1d948 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/ambariViews/ViewsEditCtrl.js
@@ -18,7 +18,7 @@
 'use strict';
 
 angular.module('ambariAdminConsole')
-.controller('ViewsEditCtrl', ['$scope', '$routeParams' , 'View', 'Alert', 'PermissionLoader', 'PermissionSaver', 'ConfirmationModal', '$location', 'UnsavedDialog', function($scope, $routeParams, View, Alert, PermissionLoader, PermissionSaver, ConfirmationModal, $location, UnsavedDialog) {
+.controller('ViewsEditCtrl', ['$scope', '$routeParams' , 'Cluster', 'View', 'Alert', 'PermissionLoader', 'PermissionSaver', 'ConfirmationModal', '$location', 'UnsavedDialog', function($scope, $routeParams, Cluster, View, Alert, PermissionLoader, PermissionSaver, ConfirmationModal, $location, UnsavedDialog) {
   $scope.identity = angular.identity;
   $scope.isConfigurationEmpty = true;
   function reloadViewInfo(){
@@ -33,8 +33,15 @@ angular.module('ambariAdminConsole')
         'description': $scope.instance.ViewInstanceInfo.description
       };
 
-        initConfigurations();
-        $scope.isConfigurationEmpty = angular.equals({}, $scope.configuration);
+      initConfigurations();
+      if(instance.ViewInstanceInfo.cluster_handle) {
+        $scope.isLocalCluster = true;
+        $scope.cluster = instance.ViewInstanceInfo.cluster_handle;
+      }else{
+        $scope.isLocalCluster = false;
+        $scope.cluster = $scope.clusters.length > 0 ? $scope.clusters[0] : "No Clusters";
+      }
+      $scope.isConfigurationEmpty = !$scope.numberOfClusterConfigs;
     })
     .catch(function(data) {
       Alert.error('Cannot load instance info', data.data.message);
@@ -53,8 +60,12 @@ angular.module('ambariAdminConsole')
   // Get META for properties
   View.getMeta($routeParams.viewId, $routeParams.version).then(function(data) {
     $scope.configurationMeta = data.data.ViewVersionInfo.parameters;
+    $scope.clusterConfigurable = data.data.ViewVersionInfo.cluster_configurable;
+    $scope.clusterConfigurableErrorMsg = $scope.clusterConfigurable ? "" : "This view cannot use this option";
     angular.forEach($scope.configurationMeta, function (item) {
       item.displayName = item.name.replace(/\./g, '\.\u200B');
+      item.clusterConfig = !!item.clusterConfig;
+      $scope.numberOfClusterConfigs = $scope.numberOfClusterConfigs + !!item.clusterConfig;
     });
     reloadViewInfo();
   });
@@ -80,20 +91,57 @@ angular.module('ambariAdminConsole')
 
   reloadViewPrivileges();
 
-  $scope.editSettingsDisabled = true;
+  $scope.clusterConfigurable = false;
+  $scope.clusterConfigurableErrorMsg = "";
+  $scope.clusters = [];
+  $scope.cluster = null;
+  $scope.noClusterAvailible = true;
+
+
+    $scope.editSettingsDisabled = true;
+  $scope.numberOfClusterConfigs = 0;
+
   $scope.toggleSettingsEdit = function() {
     $scope.editSettingsDisabled = !$scope.editSettingsDisabled;
+    $scope.settingsBeforeEdit = angular.copy($scope.configuration);
+    $scope.configurationMeta.forEach(function (element) {
+      if (element.masked && !$scope.editSettingsDisabled && !element.clusterConfig) {
+        $scope.configuration[element.name] = '';
+      }
+      if(element.clusterConfig) {
+        delete $scope.settingsBeforeEdit[element.name];
+      }
+    });
   };
 
+  Cluster.getAllClusters().then(function (clusters) {
+    if(clusters.length >0){
+      clusters.forEach(function(cluster) {
+        $scope.clusters.push(cluster.Clusters.cluster_name)
+      });
+      $scope.noClusterAvailible = false;
+    }else{
+      $scope.clusters.push("No Clusters");
+    }
+    $scope.cluster = $scope.clusters[0];
+  });
+
   $scope.saveSettings = function(callback) {
     if( $scope.settingsForm.$valid ){
-      return View.updateInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId, {
+      var data = {
         'ViewInstanceInfo':{
           'visible': $scope.settings.visible,
           'label': $scope.settings.label,
-          'description': $scope.settings.description
+          'description': $scope.settings.description,
+          'properties':{}
         }
-      })
+      };
+      $scope.configurationMeta.forEach(function (element) {
+        if(!element.clusterConfig) {
+          data.ViewInstanceInfo.properties[element.name] = $scope.configuration[element.name];
+        }
+      });
+      return View.updateInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId, data)
       .success(function() {
         if( callback ){
           callback();
@@ -114,6 +162,7 @@ angular.module('ambariAdminConsole')
       'label': $scope.instance.ViewInstanceInfo.label,
       'description': $scope.instance.ViewInstanceInfo.description
     };
+    angular.extend($scope.configuration, $scope.settingsBeforeEdit);
     $scope.editSettingsDisabled = true;
     $scope.settingsForm.$setPristine();
   };
@@ -123,50 +172,62 @@ angular.module('ambariAdminConsole')
   $scope.togglePropertiesEditing = function () {
     $scope.editConfigurationDisabled = !$scope.editConfigurationDisabled;
     $scope.configurationBeforeEdit = angular.copy($scope.configuration);
-    if (!$scope.editConfigurationDisabled) {
+    $scope.configurationMeta.forEach(function (element) {
+      if (element.masked && !$scope.editConfigurationDisabled && element.clusterConfig) {
+        $scope.configuration[element.name] = '';
+      }
+      if(!element.clusterConfig) {
+        delete $scope.configurationBeforeEdit[element.name];
+      }
+    });
+  };
+  $scope.saveConfiguration = function() {
+    var data = {
+      'ViewInstanceInfo':{
+        'properties':{}
+      }
+    };
+    if($scope.isLocalCluster) {
+      data.ViewInstanceInfo.cluster_handle = $scope.cluster;
+    } else {
+      data.ViewInstanceInfo.cluster_handle = null;
       $scope.configurationMeta.forEach(function (element) {
-        if (element.masked) {
-          $scope.configuration[element.name] = '';
+        if(element.clusterConfig) {
+          data.ViewInstanceInfo.properties[element.name] = $scope.configuration[element.name];
         }
       });
     }
-  };
-  $scope.saveConfiguration = function() {
 
-      return View.updateInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId, {
-        'ViewInstanceInfo':{
-          'properties': $scope.configuration
-        }
-      })
-      .success(function() {
-        $scope.editConfigurationDisabled = true;
-        $scope.propertiesForm.$setPristine();
-      })
-      .catch(function(data) {
-        var errorMessage = data.data.message;
-
-        //TODO: maybe the BackEnd should sanitize the string beforehand?
-        errorMessage = errorMessage.substr(errorMessage.indexOf("\{"));
-
-        if (data.status >= 400) {
-          try {
-            var errorObject = JSON.parse(errorMessage);
-            errorMessage = errorObject.detail;
-            angular.forEach(errorObject.propertyResults, function (item, key) {
-              $scope.propertiesForm[key].validationError = !item.valid;
-              if (!item.valid) {
-                $scope.propertiesForm[key].validationMessage = item.detail;
-              }
-            });
-          } catch (e) {
-            console.error('Unable to parse error message:', data.message);
-          }
+    return View.updateInstance($routeParams.viewId, $routeParams.version, $routeParams.instanceId, data)
+    .success(function() {
+      $scope.editConfigurationDisabled = true;
+      $scope.propertiesForm.$setPristine();
+    })
+    .catch(function(data) {
+      var errorMessage = data.data.message;
+
+      //TODO: maybe the BackEnd should sanitize the string beforehand?
+      errorMessage = errorMessage.substr(errorMessage.indexOf("\{"));
+
+      if (data.status >= 400) {
+        try {
+          var errorObject = JSON.parse(errorMessage);
+          errorMessage = errorObject.detail;
+          angular.forEach(errorObject.propertyResults, function (item, key) {
+            $scope.propertiesForm[key].validationError = !item.valid;
+            if (!item.valid) {
+              $scope.propertiesForm[key].validationMessage = item.detail;
+            }
+          });
+        } catch (e) {
+          console.error('Unable to parse error message:', data.message);
         }
-        Alert.error('Cannot save properties', errorMessage);
-      });
-    };
+      }
+      Alert.error('Cannot save properties', errorMessage);
+    });
+  };
   $scope.cancelConfiguration = function() {
-    $scope.configuration = angular.copy($scope.configurationBeforeEdit);
+    angular.extend($scope.configuration, $scope.configurationBeforeEdit);
     $scope.editConfigurationDisabled = true;
     $scope.propertiesForm.$setPristine();
   };

http://git-wip-us.apache.org/repos/asf/ambari/blob/68c68a6f/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
index 06a9e8f..7bf1672 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
@@ -159,26 +159,39 @@ angular.module('ambariAdminConsole')
   };
 
   View.createInstance = function(instanceInfo) {
-    var deferred = $q.defer();
-    var properties = {};
+    var deferred = $q.defer(),
+      properties = {},
+      settings = {},
+      data = {
+        instance_name: instanceInfo.instance_name,
+        label: instanceInfo.label,
+        visible: instanceInfo.visible,
+        icon_path: instanceInfo.icon_path,
+        icon64_path: instanceInfo.icon64_path,
+        description: instanceInfo.description
+      };
 
     angular.forEach(instanceInfo.properties, function(property) {
-      properties[property.name] = property.value
+      if(property.clusterConfig) {
+        properties[property.name] = property.value
+      }else {
+        settings[property.name] = property.value
+      }
     });
 
+    data.properties = settings;
+
+    if(instanceInfo.isLocalCluster) {
+      data.cluster_handle = instanceInfo.clusterName;
+    } else {
+      angular.extend(data.properties, properties);
+    }
+
     $http({
       method: 'POST',
       url: Settings.baseUrl + '/views/' + instanceInfo.view_name +'/versions/'+instanceInfo.version + '/instances/'+instanceInfo.instance_name,
       data:{
-        'ViewInstanceInfo' : {
-          instance_name: instanceInfo.instance_name,
-          label: instanceInfo.label,
-          visible: instanceInfo.visible,
-          icon_path: instanceInfo.icon_path,
-          icon64_path: instanceInfo.icon64_path,
-          properties: properties,
-          description: instanceInfo.description
-        }
+        'ViewInstanceInfo' : data
       }
     })
     .success(function(data) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/68c68a6f/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 5b82129..d273d07 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
@@ -127,7 +127,7 @@
   display: block;
   color: #888;
   text-align: center;
-  padding: 10px 0px;
+  padding: 10px 0;
   cursor: default;
 }
 
@@ -239,7 +239,7 @@
   margin-left: 20px;
   margin-right: 10px;
   border: none;
-  border-radius: 0px;
+  border-radius: 0;
 }
 .mainpage .panel-body #main-operations-boxes .thumbnail .title,
 .mainpage .panel-body #main-operations-boxes .thumbnail .description,
@@ -533,7 +533,7 @@ a.gotoinstance{
   padding-left: 33px;
   padding-top: 8px;
   padding-bottom: 8px;
-  margin: 0px;
+  margin: 0;
 }
 .left-navbar .panel-body li.active a{
   background: #666;
@@ -657,7 +657,7 @@ table.no-border tr td{
 }
 
 .property-form label{
-  width: 214px;
+  width: 254px;
   word-wrap: break-word;
   text-overflow: ellipsis;
   overflow: hidden;
@@ -1178,7 +1178,6 @@ button.btn.btn-xs{
   border-radius: 50%;
   vertical-align: middle;
   position: relative;
-  border-radius: 50%;
 }
 
 .viewstatus.pending:before, .viewstatus.pending:after{
@@ -1319,4 +1318,23 @@ accordion .panel-group .panel{
 }
 .verison-label-row .label {
   font-size: 100%;
+}
+
+.panel-body .sub-group {
+    margin-left: 10px;
+}
+.clusters-name-dropdown {
+  margin-top: 7px;
+  margin-left: 16px;
+  width: 200px;
+}
+.cluster-configurable-form {
+  width: 350px;
+  margin-top: 15px;
+  margin-bottom: 15px;
+  padding: 0 15px;
+}
+.edit-view-custom-wrap {
+  padding-top: 0;
+  margin-top: -28px;
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/68c68a6f/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
index 772abae..08e4f26 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
@@ -23,14 +23,14 @@
 <form class="form-horizontal create-view-form" role="form" name="form.instanceCreateForm" novalidate>
   <div class="view-header">
     <div class="form-group">
-      <div class="col-sm-2">
+      <div class="col-sm-3">
         <label for="" class="control-label">View</label>
       </div>
       <div class="col-sm-10"><label for="" class="control-label">{{view.ViewVersionInfo.view_name}}</label></div>
     </div>
     <div class="form-group">
-      <div class="col-sm-2"><label for="" class="control-label">Version</label></div>
-      <div class="col-sm-2">
+      <div class="col-sm-3"><label for="" class="control-label">Version</label></div>
+      <div class="col-sm-3">
         <select ng-model="version" class="instanceversion-input form-control" ng-change="versionChanged()" ng-options="o as o for o in versions"></select>
       </div>
     </div>
@@ -38,14 +38,14 @@
 
   <div class="panel panel-default">
     <div class="panel-heading">
-      <h3 class="panel-title">Details</h3>
+      <h3 class="panel-title">Settings</h3>
     </div>
     <div class="panel-body">
       <div class="form-group"
       ng-class="{'has-error' : ( (form.instanceCreateForm.instanceNameInput.$error.required || form.instanceCreateForm.instanceNameInput.$error.pattern) && form.instanceCreateForm.submitted) || instanceExists }"
       >
-        <label for="" class="control-label col-sm-2">Instance Name</label>
-        <div class="col-sm-10">
+        <label for="" class="control-label col-sm-3">Instance Name</label>
+        <div class="col-sm-9">
           <input type="text" class="form-control instancename-input" name="instanceNameInput" ng-pattern="nameValidationPattern" required ng-model="instance.instance_name" autocomplete="off">
 
           <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.instanceNameInput.$error.required && form.instanceCreateForm.submitted'>
@@ -61,8 +61,8 @@
       </div>
       <div class="form-group"
       ng-class="{'has-error' : ( (form.instanceCreateForm.displayLabel.$error.required || form.instanceCreateForm.displayLabel.$error.pattern) && form.instanceCreateForm.submitted)}">
-        <label for="" class="control-label col-sm-2">Display Name</label>
-        <div class="col-sm-10">
+        <label for="" class="control-label col-sm-3">Display Name</label>
+        <div class="col-sm-9">
           <input type="text" class="form-control instancelabel-input" name="displayLabel" ng-model="instance.label" required ng-pattern="/^([a-zA-Z0-9._\s]+)$/" autocomplete="off">
 
           <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.displayLabel.$error.required && form.instanceCreateForm.submitted'>
@@ -74,16 +74,34 @@
         </div>
       </div>
       <div class="form-group" ng-class="{'has-error' : form.instanceCreateForm.description.$error.required && form.instanceCreateForm.submitted }">
-        <label for="" class="control-label col-sm-2">Description</label>
-        <div class="col-sm-10">
+        <label for="" class="control-label col-sm-3">Description</label>
+        <div class="col-sm-9">
           <input type="text" class="form-control" name="description" ng-model="instance.description" maxlength="140" required>
           <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.description.$error.required && form.instanceCreateForm.submitted'>
             This field is required.
           </div>
         </div>
       </div>
+      <div class="form-group" ng-repeat="parameter in instance.properties | filter:{clusterConfig:false}"
+           ng-class="{'has-error' : ((form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted) || form.instanceCreateForm[parameter.name].validationError)}" >
+        <label for="" class="col-sm-3 control-label" ng-class="{'not-required': !parameter.required}">{{parameter.label || parameter.displayName}}{{parameter.required ? '*' : ''}}</label>
+        <div ng-switch="parameter.type">
+          <div class="col-sm-9 checkbox" ng-switch-when="boolean">
+            <input type="checkbox" class="viewproperty-input" name="{{parameter.name}}" ng-required="parameter.required" ng-model="parameter.value" popover="{{parameter.description}}" popover-title="{{parameter.name}}" popover-trigger="mouseenter">
+          </div>
+          <div class="col-sm-9" ng-switch-default>
+            <input type="{{parameter.masked ? 'password' : 'text'}}" class="form-control viewproperty-input" name="{{parameter.name}}" ng-change="form.instanceCreateForm[parameter.name].validationError=''" ng-required="parameter.required" ng-model="parameter.value" autocomplete="off" popover="{{parameter.description}}" popover-title="{{parameter.name}}" popover-trigger="mouseenter" placeholder="{{parameter.placeholder}}">
+            <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted'>
+              This field is required.
+            </div>
+            <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm[parameter.name].validationError'>
+              {{form.instanceCreateForm[parameter.name].validationMessage}}
+            </div>
+          </div>
+        </div>
+      </div>
       <div class="form-group">
-        <div class="col-sm-10 col-sm-offset-2">
+        <div class="col-sm-10 col-sm-offset-3">
           <div class="checkbox">
             <label>
               <input type="checkbox" ng-model='instance.visible' class="visibilityCheckbox"> Visible
@@ -93,24 +111,40 @@
       </div>
     </div>
   </div>
-  <div class="panel panel-default">
+  <div class="panel panel-default" ng-hide="!numberOfClusterConfigs">
     <div class="panel-heading">
-      <h3 class="panel-title">Properties</h3>
+      <h3 class="panel-title">Cluster Configuration</h3>
+    </div>
+
+    <div class="panel-body property-form cluster-configurable-form" popover="{{clusterConfigurableErrorMsg}}" popover-trigger="mouseenter">
+      <div class="checkbox">
+        <label>
+          <input type="radio" ng-disabled="!clusterConfigurable || noClusterAvailible" ng-model="instance.isLocalCluster" ng-value="true" class="visibilityCheckbox"> Local Ambari Managed Cluster
+        </label>
+      </div>
+      <div class="form-group sub-group">
+        <select ng-model="cluster" ng-disabled="!instance.isLocalCluster" ng-change="onClusterChange()" class="clusters-name-dropdown form-control"  ng-options="o as o for o in clusters"></select>
+      </div>
     </div>
     <div class="panel-body property-form">
+      <div class="checkbox">
+        <label>
+          <input type="radio" ng-model="instance.isLocalCluster" ng-value="false" class="visibilityCheckbox"> Custom
+        </label>
+      </div>
       <div class="alert alert-danger bottom-margin top-margin" ng-show='form.instanceCreateForm.generalValidationError'>
         {{form.instanceCreateForm.generalValidationError}}
       </div>
-      <div class="form-group" ng-repeat="parameter in instance.properties"
+      <div class="form-group sub-group" ng-repeat="parameter in instance.properties | filter:{clusterConfig:true}"
         ng-class="{'has-error' : ((form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted) || form.instanceCreateForm[parameter.name].validationError)}" >
         <label for="" class="col-sm-3 control-label" ng-class="{'not-required': !parameter.required}">{{parameter.label || parameter.displayName}}{{parameter.required ? '*' : ''}}</label>
         <div ng-switch="parameter.type">
           <div class="col-sm-9 checkbox" ng-switch-when="boolean">
-            <input type="checkbox" class="viewproperty-input" name="{{parameter.name}}" ng-required="parameter.required" ng-model="parameter.value" popover="{{parameter.description}}" popover-title="{{parameter.name}}" popover-trigger="mouseenter">
+            <input type="checkbox" class="viewproperty-input" name="{{parameter.name}}" ng-disabled="instance.isLocalCluster" ng-required="parameter.required && instance.isLocalCluster" ng-model="parameter.value" popover="{{parameter.description}}" popover-title="{{parameter.name}}" popover-trigger="mouseenter">
           </div>
           <div class="col-sm-9" ng-switch-default>
-            <input type="{{parameter.masked ? 'password' : 'text'}}" class="form-control viewproperty-input" name="{{parameter.name}}" ng-change="form.instanceCreateForm[parameter.name].validationError=''" ng-required="parameter.required" ng-model="parameter.value" autocomplete="off" popover="{{parameter.description}}" popover-title="{{parameter.name}}" popover-trigger="mouseenter" placeholder="{{parameter.placeholder}}">
-            <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted'>
+            <input type="{{parameter.masked ? 'password' : 'text'}}" class="form-control viewproperty-input" name="{{parameter.name}}" ng-disabled="instance.isLocalCluster" ng-change="form.instanceCreateForm[parameter.name].validationError=''" ng-required="parameter.required && !instance.isLocalCluster" ng-model="parameter.value" autocomplete="off" popover="{{parameter.description}}" popover-title="{{parameter.name}}" popover-trigger="mouseenter" placeholder="{{parameter.placeholder}}">
+            <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted && !instance.isLocalCluster'>
               This field is required.
             </div>
             <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm[parameter.name].validationError'>

http://git-wip-us.apache.org/repos/asf/ambari/blob/68c68a6f/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html
index 910b2ad..960222d 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/edit.html
@@ -37,21 +37,21 @@
   <div class="panel-body">
     <form class="form-horizontal" name="settingsForm" novalidate>
       <div class="form-group">
-        <label for="" class="col-sm-2 control-label">View Name</label>
-        <div class="col-sm-10"><input disabled="disabled" type="text" class="form-control instancename-input" placeholder="Display Name" value="{{instance.ViewInstanceInfo.view_name}}"></div>
+        <label for="" class="col-sm-3 control-label">View Name</label>
+        <div class="col-sm-9"><input disabled="disabled" type="text" class="form-control instancename-input" placeholder="Display Name" value="{{instance.ViewInstanceInfo.view_name}}"></div>
       </div>
       <div class="form-group">
-        <label for="" class="col-sm-2 control-label">View Version</label>
-        <div class="col-sm-10"><input disabled="disabled" type="text" class="form-control instancename-input" placeholder="Display Name" value="{{instance.ViewInstanceInfo.version}}"></div>
+        <label for="" class="col-sm-3 control-label">View Version</label>
+        <div class="col-sm-9"><input disabled="disabled" type="text" class="form-control instancename-input" placeholder="Display Name" value="{{instance.ViewInstanceInfo.version}}"></div>
       </div>
       <fieldset ng-disabled="editSettingsDisabled">
         <div class="form-group">
-          <label for="" class="col-sm-2 control-label">Instance Name</label>
-          <div class="col-sm-10"><input disabled="disabled" type="text" class="form-control instancename-input" placeholder="Display Name" value="{{instance.ViewInstanceInfo.instance_name}}"></div>
+          <label for="" class="col-sm-3 control-label">Instance Name</label>
+          <div class="col-sm-9"><input disabled="disabled" type="text" class="form-control instancename-input" placeholder="Display Name" value="{{instance.ViewInstanceInfo.instance_name}}"></div>
         </div>
         <div class="form-group" ng-class="{'has-error' : (settingsForm.displayName.$error.required || settingsForm.displayName.$error.pattern) && !editSettingsDisabled}">
-          <label for="" class="col-sm-2 control-label">Display Name</label>
-          <div class="col-sm-10">
+          <label for="" class="col-sm-3 control-label">Display Name</label>
+          <div class="col-sm-9">
             <input type="text" class="form-control instancename-input" placeholder="Display Name" name="displayName" required ng-model="settings.label" ng-pattern="/^([a-zA-Z0-9._\s]+)$/">
             <div class="alert alert-danger no-margin-bottom top-margin" ng-show='settingsForm.displayName.$error.required  && !editSettingsDisabled'>
               This field is required.
@@ -62,16 +62,33 @@
           </div>
         </div>
         <div class="form-group" ng-class="{'has-error' : settingsForm.description.$error.required  && !editSettingsDisabled}">
-          <label for="" class="control-label col-sm-2">Description</label>
-          <div class="col-sm-10">
+          <label for="" class="control-label col-sm-3">Description</label>
+          <div class="col-sm-9">
             <input type="text" class="form-control" ng-model="settings.description" name="description" placeholder="Instance Description" required>
             <div class="alert alert-danger no-margin-bottom top-margin" ng-show='settingsForm.description.$error.required  && !editSettingsDisabled'>
               This field is required.
             </div>
           </div>
         </div>
+        <div class="form-group" ng-repeat="property in configurationMeta | filter:{clusterConfig:false}" ng-class="{'has-error' : (!editSettingsDisabled && ((property.required && settingsForm[property.name].$error.required && !editSettingsDisabled) || settingsForm[property.name].validationError))}">
+          <label for="" class="control-label col-sm-3" ng-class="{'not-required': !property.required}">{{property.label || property.displayName}}{{property.required ? '*' : ''}}</label>
+          <div ng-switch="property.type">
+            <div class="col-sm-9 checkbox" ng-switch-when="boolean">
+              <input type="checkbox" class="propertie-input" ng-disabled="editSettingsDisabled" name="{{property.name}}" ng-model="configuration[property.name]" ng-true-value="true" ng-false-value="false" popover="{{property.description}}" popover-title="{{property.name}}" popover-trigger="mouseenter">
+            </div>
+            <div class="col-sm-9" ng-switch-default>
+              <input type="{{property.masked ? 'password' : 'text'}}" class="form-control propertie-input" ng-required="property.required" ng-change="settingsForm[property.name].validationError=''" ng-disabled="editSettingsDisabled" name="{{property.name}}" ng-model="configuration[property.name]" popover="{{property.description}}" popover-title="{{property.name}}" popover-trigger="mouseenter" placeholder="{{property.placeholder}}">
+              <div class="alert alert-danger no-margin-bottom top-margin" ng-show='property.required && settingsForm[property.name].$error.required && !editSettingsDisabled'>
+                This field is required.
+              </div>
+              <div class="alert alert-danger no-margin-bottom top-margin" ng-show='property.required && settingsForm[property.name].validationError && !editSettingsDisabled'>
+                {{propertiesForm[property.name].validationMessage}}
+              </div>
+            </div>
+          </div>
+        </div>
         <div class="form-group">
-          <div class="col-sm-offset-2 col-sm-10">
+          <div class="col-sm-offset-3 col-sm-10">
             <div class="checkbox">
               <label>
                 <input type="checkbox" ng-model="settings.visible" ng-class="instancevisibility-input"> Visible
@@ -125,18 +142,34 @@
   </div>
 </div>
 
-<div class="panel panel-default">
+<div class="panel panel-default" ng-hide="isConfigurationEmpty">
   <div class="panel-heading clearfix">
-    <h3 class="panel-title pull-left">Properties</h3>
+    <h3 class="panel-title pull-left">Cluster Configuration</h3>
     <div class="pull-right" ng-switch="instance.ViewInstanceInfo.static">
       <a href ng-switch-when="false" ng-hide="isConfigurationEmpty" ng-click="togglePropertiesEditing()" ng-show="editConfigurationDisabled" class="properties-toggle"> <span class="glyphicon glyphicon-pencil"></span> Edit</a>
       <a href ng-switch-when="true" ng-hide="isConfigurationEmpty"  class="properties-toggle disabled"> <span class="glyphicon glyphicon-pencil"></span> Edit</a>
     </div>
   </div>
-  <div class="panel-body">
+  <div class="panel-body property-form cluster-configurable-form" popover="{{clusterConfigurableErrorMsg}}" popover-trigger="mouseenter">
+    <div class="checkbox">
+      <label>
+        <input type="radio" ng-model="$parent.isLocalCluster" ng-disabled="!clusterConfigurable || editConfigurationDisabled || noClusterAvailible" ng-value="true" class="visibilityCheckbox"> Local Ambari Managed Cluster
+      </label>
+    </div>
+    <div class="form-group sub-group">
+      <select ng-model="cluster" ng-disabled="!$parent.isLocalCluster || editConfigurationDisabled" ng-change="onClusterChange()" class="clusters-name-dropdown form-control"  ng-options="o as o for o in clusters"></select>
+    </div>
+    <p>&nbsp</p>
+    <div class="checkbox">
+      <label>
+        <input type="radio" ng-model="$parent.isLocalCluster" ng-disabled="editConfigurationDisabled" ng-value="false" class="visibilityCheckbox"> Custom
+      </label>
+    </div>
+  </div>
+  <div class="panel-body edit-view-custom-wrap">
     <form name="propertiesForm" class="form-horizontal property-form" ng-hide="isConfigurationEmpty" novalidate>
       <fieldset>
-        <div class="form-group" ng-repeat="property in configurationMeta" ng-class="{'has-error' : (!editConfigurationDisabled && ((property.required && propertiesForm[property.name].$error.required && !editConfigurationDisabled) || propertiesForm[property.name].validationError))}">
+        <div class="form-group sub-group" ng-repeat="property in configurationMeta | filter:{clusterConfig:true}" ng-class="{'has-error' : (!editConfigurationDisabled && ((property.required && propertiesForm[property.name].$error.required && !editConfigurationDisabled) || propertiesForm[property.name].validationError))}">
           <label for="" class="control-label col-sm-3" ng-class="{'not-required': !property.required}">{{property.label || property.displayName}}{{property.required ? '*' : ''}}</label>
           <div ng-switch="property.type">
             <div class="col-sm-9 checkbox" ng-switch-when="boolean">