ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From yus...@apache.org
Subject [49/51] [partial] AMBARI-7718. Rebase branch-windows-dev against trunk. (Jayush Luniya and Florian Barca via yusaku)
Date Thu, 16 Oct 2014 20:12:13 GMT
http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/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
new file mode 100644
index 0000000..d9f5eb5
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
@@ -0,0 +1,29 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.config(['$translateProvider', function($translateProvider) {
+  $translateProvider.translations('en',{
+    'CLUSTER.OPERATE': 'Operator',
+    'CLUSTER.READ': 'Read-Only',
+    'VIEW.USE': 'Use'
+  });
+
+  $translateProvider.preferredLanguage('en');
+}]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/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
new file mode 100644
index 0000000..e47c97d
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/routes.js
@@ -0,0 +1,111 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.constant('ROUTES', {
+  root: {
+    url: '/',
+    templateUrl: 'views/main.html',
+    controller: 'MainCtrl'
+  },
+  users: {
+    list: {
+      url: '/users',
+      templateUrl: 'views/users/list.html',
+      controller: 'UsersListCtrl'
+    },
+    edit: {
+      url: '/users/:id/edit',
+      templateUrl: 'views/users/create.html',
+      controller: 'UsersCreateCtrl'
+    },
+    create: {
+      url: '/users/new',
+      templateUrl: 'views/users/create.html',
+      controller: 'UsersCreateCtrl'
+    },
+    show: {
+      url: '/users/:id',
+      templateUrl: 'views/users/show.html',
+      controller: 'UsersShowCtrl'
+    }
+  },
+  groups: {
+    list: {
+      url: '/groups',
+      templateUrl: 'views/groups/list.html',
+      controller: 'GroupsListCtrl'
+    },
+    edit: {
+      url: '/groups/:id/edit',
+      templateUrl: 'views/groups/edit.html',
+      controller: 'GroupsEditCtrl'
+    },
+    create: {
+      url: '/groups/new',
+      templateUrl: 'views/groups/create.html',
+      controller: 'GroupsCreateCtrl'
+    }
+  },
+  views: {
+    list: {
+      url: '/views',
+      templateUrl: 'views/ambariViews/listTable.html',
+      controller: 'ViewsListCtrl',
+    },
+    edit: {
+      url: '/views/:viewId/versions/:version/instances/:instanceId/edit',
+      templateUrl: 'views/ambariViews/edit.html',
+      controller: 'ViewsEditCtrl'
+    },
+    create: {
+      url: '/views/:viewId/versions/:version/new',
+      templateUrl: 'views/ambariViews/create.html',
+      controller: 'CreateViewInstanceCtrl'
+    }
+  },
+  clusters:{
+    manageAccess: {
+      url: '/clusters/:id/manageAccess',
+      templateUrl: 'views/clusters/manageAccess.html',
+      controller: 'ClustersManageAccessCtrl'
+    }
+  },
+  dashboard:{
+    url: '/dashboard',
+    controller: ['$window', function($window) {
+      $window.location.href = '/#/main/dashboard';
+    }],
+    template: ''
+  }
+})
+.config(['$routeProvider', '$locationProvider', 'ROUTES', function($routeProvider, $locationProvider, ROUTES) {
+  var createRoute = function(routeObj) {
+    if(routeObj.url){
+      $routeProvider.when(routeObj.url, routeObj);
+    } else {
+      angular.forEach(routeObj, createRoute);
+    }
+  };
+  angular.forEach(ROUTES, createRoute);
+}])
+.run(['$rootScope', 'ROUTES', function($rootScope, ROUTES) {
+  // Make routes available in every template and controller
+  $rootScope.ROUTES = ROUTES;
+}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Alert.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Alert.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Alert.js
new file mode 100644
index 0000000..bd81b9a
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Alert.js
@@ -0,0 +1,106 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.factory('Alert', [function() {
+
+  var hideTimeout = null;
+  var $boxContainer = null;
+  var removingTimeout = null;
+
+  function createAlertBox(innerHTML, moreInfo, type){
+    if (!$boxContainer) {
+      $boxContainer = angular.element('<div class="alert-container"/>').appendTo('body');
+      $boxContainer
+        .on('mouseenter', function() {
+          clearTimeout(removingTimeout);
+        })
+        .on('mouseleave', function() {
+          startRemovingTimeout();
+        });
+    }
+    var elem = angular.element('<div><div class="icon-box"></div></div>').addClass('ambariAlert').addClass(type).addClass('invisible');
+
+    elem.append('<div class="content">' + innerHTML + '</div>');
+    if (moreInfo) {
+      $(' <a href class="more-collapse"> more...</a>').appendTo(elem.find('.content'))
+      .on('click', function() {
+        elem.find('.more').show();
+        $(this).remove();
+        return false;
+      });
+      elem.append('<div class="more">'+moreInfo+'</div>');
+    }
+
+    $('<button type="button" class="close"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>')
+      .appendTo(elem)
+      .on('click', function() {
+        var $box = $(this).closest('.ambariAlert');
+        $box.remove();
+      });
+
+    var $icon = $('<span class="glyphicon"></span>');
+    switch (type){
+      case 'error':
+        $icon.addClass('glyphicon-remove-sign');
+        break;
+      case 'success':
+        $icon.addClass('glyphicon-ok-sign');
+        break;
+      case 'info':
+        $icon.addClass('glyphicon-info-sign');
+        break;
+    }
+    elem.find('.icon-box').append($icon);
+
+    elem.appendTo($boxContainer);
+    setTimeout(function() {
+      elem.removeClass('invisible');
+    }, 0);
+
+    startRemovingTimeout();
+  };
+
+  function startRemovingTimeout(){
+    clearTimeout(removingTimeout);
+    removingTimeout = setTimeout(removeTopBox, 5000);
+  }
+
+  function removeTopBox(){
+    $boxContainer.children().first().remove();
+    if (!$boxContainer.children().length) {
+      $boxContainer.remove();
+      $boxContainer = null;
+    } else {
+      startRemovingTimeout();
+    }
+  }
+
+  return {
+    error: function(innerHTML, moreInfo) {
+      createAlertBox(innerHTML, moreInfo, 'error');
+    },
+    success: function(innerHTML, moreInfo) {
+      createAlertBox(innerHTML, moreInfo, 'success');
+    },
+    info: function(innerHTML, moreInfo) {
+      createAlertBox(innerHTML, moreInfo, 'info');
+    }
+  };
+}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Auth.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Auth.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Auth.js
new file mode 100644
index 0000000..36b29b1
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Auth.js
@@ -0,0 +1,41 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.factory('Auth',['$http', 'Settings', function($http, Settings) {
+  var ambari;
+  var currentUserName;
+  if (localStorage.ambari) {
+    ambari = JSON.parse(localStorage.ambari);
+    if (ambari && ambari.app && ambari.app.loginName) {
+      currentUserName = ambari.app.loginName;
+    }
+  }
+  return {
+    signout: function() {
+      return $http({
+        method: 'GET',
+        url: Settings.baseUrl + '/logout'
+      });
+    },
+    getCurrentUser: function() {
+	return currentUserName;
+    }
+  };
+}]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js
new file mode 100644
index 0000000..624e773
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Cluster.js
@@ -0,0 +1,118 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.factory('Cluster', ['$http', '$q', 'Settings', function($http, $q, Settings) {
+  return {
+    getStatus: function() {
+      var deferred = $q.defer();
+
+      $http.get(Settings.baseUrl + '/clusters?fields=Clusters/provisioning_state')
+      .then(function(data, status, headers) {
+        deferred.resolve(data.data.items[0]);
+      })
+      .catch(function(data) {
+        deferred.reject(data);
+      });
+
+      return deferred.promise;
+    },
+    getPermissions: function() {
+      var deferred = $q.defer();
+
+      $http({
+        method: 'GET',
+        url: Settings.baseUrl + '/permissions',
+        params: {
+          fields: 'PermissionInfo',
+          'PermissionInfo/resource_name': 'CLUSTER'
+        }
+      })
+      .success(function(data) {
+        deferred.resolve(data.items);
+      })
+      .catch(function(data) {
+        deferred.reject(data); });
+
+      return deferred.promise;
+    },
+    getPrivileges: function(params) {
+      var deferred = $q.defer();
+
+      $http({
+        method: 'GET',
+        url: Settings.baseUrl + '/clusters/'+params.clusterId,
+        params : {
+          'fields': 'privileges/PrivilegeInfo'
+        }
+      })
+      .success(function(data) {
+        deferred.resolve(data.privileges);
+      })
+      .catch(function(data) {
+        deferred.reject(data);
+      });
+
+      return deferred.promise;
+    },
+    createPrivileges: function(params, data) {
+      return $http({
+        method: 'POST',
+        url: Settings.baseUrl + '/clusters/'+params.clusterId+'/privileges',
+        data: data
+      });
+    },
+    deletePrivileges: function(params, data) {
+      return $http({
+        method: 'DELETE',
+        url: Settings.baseUrl + '/clusters/'+params.clusterId+'/privileges',
+        data: data
+      });
+    },
+    updatePrivileges: function(params, privileges) {
+      return $http({
+        method: 'PUT',
+        url: Settings.baseUrl + '/clusters/' + params.clusterId + '/privileges',
+        data: privileges
+      });
+    },
+    deletePrivilege: function(clusterId, permissionName, principalType, principalName) {
+      return $http({
+        method: 'DELETE',
+        url: Settings.baseUrl + '/clusters/'+clusterId+'/privileges',
+        params: {
+          'PrivilegeInfo/principal_type': principalType,
+          'PrivilegeInfo/principal_name': principalName,
+          'PrivilegeInfo/permission_name': permissionName
+        }
+      });
+    },
+    editName: function(oldName, newName) {
+      return $http({
+        method: 'PUT',
+        url: Settings.baseUrl + '/clusters/' + oldName,
+        data: {
+          Clusters: {
+            "cluster_name": newName
+          }
+        }
+      });
+    }
+  };
+}]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/ConfirmationModal.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/ConfirmationModal.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/ConfirmationModal.js
new file mode 100644
index 0000000..a26f1df
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/ConfirmationModal.js
@@ -0,0 +1,46 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.factory('ConfirmationModal', ['$modal', '$q', function($modal, $q) {
+
+	return {
+		show: function(header, body) {
+			var deferred = $q.defer();
+
+			var modalInstance = $modal.open({
+				templateUrl: 'views/modals/ConfirmationModal.html',
+				controller: ['$scope', '$modalInstance', function($scope, $modalInstance) {
+					$scope.header = header;
+					$scope.body = body;
+
+					$scope.ok = function() {
+						$modalInstance.close();
+						deferred.resolve();
+					};
+					$scope.cancel = function() {
+						$modalInstance.dismiss();
+						deferred.reject();
+					}
+				}]
+			});
+			return deferred.promise;
+		}
+	};
+}]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/GetDifference.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/GetDifference.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/GetDifference.js
new file mode 100644
index 0000000..b15aa8c
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/GetDifference.js
@@ -0,0 +1,40 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.factory('getDifference', [function() {
+	return function(oldArr, newArr) {
+    var result = {
+      add: [],
+      del: []
+    };
+    angular.forEach(newArr, function(item) {
+      var itemIndex = oldArr.indexOf(item);
+      if(itemIndex >= 0){
+        oldArr.splice(itemIndex, 1);
+      } else {
+        result.add.push(item);
+      }
+    });
+
+    result.del = oldArr;
+
+    return result;
+  };
+}]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js
new file mode 100644
index 0000000..cf35d4f
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/Group.js
@@ -0,0 +1,194 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.factory('Group', ['$http', '$q', 'Settings', function($http, $q, Settings) {
+  function Group(item){
+    if(typeof item === 'string'){
+      this.group_name = item;
+    } else if(typeof item === 'object'){
+      angular.extend(this, item.Groups);
+      this.getMembers();
+    }
+  }
+
+  Group.prototype.isLDAP = function() {
+    var deferred = $q.defer();
+    var self = this;
+    if( typeof this.ldap_group === 'boolean' ){
+      deferred.resolve(this.ldap_group)
+    } else {
+      $http({
+        method: 'GET',
+        url: Settings.baseUrl + '/groups/'+this.group_name
+      }).
+      success(function(data) {
+        self.ldap_group = data.Groups.ldap_group;
+        deferred.resolve(self.ldap_group);
+      });
+    }
+
+    return deferred.promise;
+  }
+
+  Group.prototype.save = function() {
+    return $http({
+      method : 'POST',
+      url: Settings.baseUrl + '/groups',
+      data:{
+        'Groups/group_name': this.group_name
+      }
+    });
+  };
+
+  Group.prototype.destroy = function() {
+    var deferred = $q.defer();
+    $http.delete(Settings.baseUrl + '/groups/' +this.group_name)
+    .success(function() {
+      deferred.resolve();
+    })
+    .error(function(data) {
+      deferred.reject(data);
+    });
+
+    return deferred.promise;
+  };
+
+  Group.prototype.getMembers = function() {
+    var deferred = $q.defer();
+    var self = this;
+
+    $http({
+      method: 'GET',
+      url: Settings.baseUrl + '/groups/' + this.group_name + '/members'
+    })
+    .success(function(data) {
+      self.members = [];
+      angular.forEach(data.items, function(member) {
+        self.members.push(member.MemberInfo.user_name);
+      });
+      deferred.resolve(self.members);
+    })
+    .error(function(data) {
+      deferred.reject(data);
+    });
+
+    return deferred.promise;
+  };
+
+  Group.prototype.saveMembers = function() {
+    var self = this;
+    var deferred = $q.defer();
+
+    var members = [];
+    angular.forEach(this.members, function(member) {
+      members.push({
+        'MemberInfo/user_name' : member,
+        'MemberInfo/group_name' : self.group_name
+      });
+    });
+
+    $http({
+      method: 'PUT',
+      url: Settings.baseUrl + '/groups/' + this.group_name + '/members',
+      data: members
+    })
+    .success(function(data) {
+      deferred.resolve(data);
+    })
+    .error(function(data) {
+      deferred.reject(data);
+    });
+    return deferred.promise;
+  }
+
+  Group.prototype.addMember = function(memberName) {
+    var deferred = $q.defer();
+
+    $http({
+      method: 'POST',
+      url: Settings.baseUrl + '/groups/' + this.group_name + '/members' + '/'+ member.user_name
+    })
+    .success(function(data) {
+      deferred.resolve(data)
+    })
+    .error(function(data) {
+      deferred.reject(data);
+    });
+
+    return deferred.promise;
+  };
+
+  Group.prototype.removeMember = function(memberId) {
+    return $http.delete(Settings.baseUrl + '/groups/'+this.group_name+'/members/'+memberId);
+  };
+
+  Group.removeMemberFromGroup = function(groupName, memberName) {
+    return $http.delete(Settings.baseUrl + '/groups/'+groupName + '/members/'+memberName);
+  };
+
+  Group.addMemberToGroup = function(groupName, memberName) {
+    return $http.post(Settings.baseUrl + '/groups/' + groupName + '/members/'+memberName);
+  };
+
+  Group.all = function(params) {
+    var deferred = $q.defer();
+
+    $http.get(Settings.baseUrl + '/groups?'
+      + 'Groups/group_name.matches(.*'+params.searchString+'.*)'
+      + '&fields=*'
+      + '&from='+ (params.currentPage-1)*params.groupsPerPage
+      + '&page_size=' + params.groupsPerPage
+      + (params.ldap_group === '*' ? '' : '&Groups/ldap_group='+params.ldap_group)
+    )
+    .success(function(data) {
+      var groups = [];
+      if(Array.isArray(data.items)){
+        angular.forEach(data.items, function(item) {
+          groups.push(new Group(item));
+        });
+      }
+      groups.itemTotal = data.itemTotal;
+      deferred.resolve(groups);
+    })
+    .error(function(data) {
+      deferred.reject(data);
+    });
+
+    return deferred.promise;
+  };
+
+  Group.listByName = function(name) {
+    return $http.get(Settings.baseUrl + '/groups?'
+      + 'Groups/group_name.matches(.*'+name+'.*)'
+    );
+  };
+
+  Group.getPrivileges = function(groupId) {
+    return $http.get(Settings.baseUrl + '/privileges', {
+        params:{
+          'PrivilegeInfo/principal_type': 'GROUP',
+          'PrivilegeInfo/principal_name': groupId,
+          'fields': '*'
+        }
+      });
+  };
+
+  return Group;
+}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js
new file mode 100644
index 0000000..2fed344
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionLoader.js
@@ -0,0 +1,62 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.factory('PermissionLoader', ['Cluster', 'View', '$q', function(Cluster, View, $q) {
+
+  function getPermissionsFor(resource, params){
+    var deferred = $q.defer();
+    resource.getPermissions(params).then(function(permissions) {
+      var permissionsInner = {}; // Save object into closure, until it completely fills to prevent blinkong
+      angular.forEach(permissions, function(permission) {
+        permission.GROUP = [];
+        permission.USER = [];
+        permissionsInner[permission.PermissionInfo.permission_name] = permission;
+      });
+
+      // Now we can get privileges
+      resource.getPrivileges(params).then(function(privileges) {
+        angular.forEach(privileges, function(privilege) {
+          permissionsInner[privilege.PrivilegeInfo.permission_name][privilege.PrivilegeInfo.principal_type].push(privilege.PrivilegeInfo.principal_name);
+        });
+
+        // After all builded - return object
+        deferred.resolve(permissionsInner);
+      }).
+      catch(function(data) {
+        deferred.reject(data);
+      });
+
+    })
+    .catch(function(data) {
+      deferred.reject(data);
+    });
+
+    return deferred.promise;
+  }
+
+  return {
+    getClusterPermissions: function(params) {
+      return getPermissionsFor(Cluster, params);
+    },
+    getViewPermissions: function(params) {
+      return getPermissionsFor(View, params);
+    }
+  };
+}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionsSaver.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionsSaver.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionsSaver.js
new file mode 100644
index 0000000..1c36ceb
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/PermissionsSaver.js
@@ -0,0 +1,140 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.factory('PermissionSaver', ['Cluster', 'View', '$q', 'getDifference', function(Cluster, View, $q, getDifference) {
+
+  function savePermissionsFor(resource, permissions, params){
+    var arr = [];
+
+    angular.forEach(permissions, function(permission) {
+      // Sanitaize input
+      var users = permission.USER.toString().split(',').filter(function(item) {return item.trim();}).map(function(item) {return item.trim()});
+      var groups = permission.GROUP.toString().split(',').filter(function(item) {return item.trim();}).map(function(item) {return item.trim()});
+      // Build array
+      arr = arr.concat(users.map(function(user) {
+        return {
+          'PrivilegeInfo':{
+            'permission_name': permission.PermissionInfo.permission_name,
+            'principal_name': user,
+            'principal_type': 'USER'
+          }
+        }
+      }));
+
+      arr = arr.concat(groups.map(function(group) {
+        return {
+          'PrivilegeInfo':{
+            'permission_name': permission.PermissionInfo.permission_name,
+            'principal_name': group,
+            'principal_type': 'GROUP'
+          }
+        }
+      }));
+    });
+
+    return resource.updatePrivileges(params, arr);
+  }
+
+  function savePermissionsForOld(resource, oldPermissions, newPermissions, params){
+    var deferred = $q.defer();
+
+    var addArr = [];
+    var delArr = [];
+    angular.forEach(newPermissions, function(permission) {
+      // Sanitize input
+      var users = permission.USER.toString().split(',').filter(function(item) {return item.trim();}).map(function(item) {return item.trim()});
+      var groups = permission.GROUP.toString().split(',').filter(function(item) {return item.trim();}).map(function(item) {return item.trim()});
+
+      var userObj = getDifference(angular.copy(oldPermissions[permission.PermissionInfo.permission_name].USER) , users);
+      var groupObj = getDifference(angular.copy(oldPermissions[permission.PermissionInfo.permission_name].GROUP) , groups);
+
+      // Build Add array
+      addArr = addArr.concat(userObj.add.map(function(user) {
+        return {
+          'PrivilegeInfo':{
+            'permission_name': permission.PermissionInfo.permission_name,
+            'principal_name': user,
+            'principal_type': 'USER'
+          }
+        }
+      }));
+      addArr = addArr.concat(groupObj.add.map(function(group) {
+        return {
+          'PrivilegeInfo':{
+            'permission_name': permission.PermissionInfo.permission_name,
+            'principal_name': group,
+            'principal_type': 'GROUP'
+          }
+        }
+      }));
+
+      // Build del array
+      delArr = delArr.concat(userObj.del.map(function(user) {
+        return {
+          'PrivilegeInfo':{
+            'permission_name': permission.PermissionInfo.permission_name,
+            'principal_name': user,
+            'principal_type': 'USER'
+          }
+        }
+      }));
+      delArr = delArr.concat(groupObj.del.map(function(group) {
+        return {
+          'PrivilegeInfo':{
+            'permission_name': permission.PermissionInfo.permission_name,
+            'principal_name': group,
+            'principal_type': 'GROUP'
+          }
+        }
+      }));
+    });
+
+    if(addArr.length){
+      resource.createPrivileges(params, addArr)
+      .then(function() {
+        deferred.resolve();
+      })
+      .catch(function(data) {
+        deferred.reject(data);
+      });
+    }
+
+    if(delArr.length){
+      resource.deletePrivileges(params, delArr)
+      .then(function() {
+        deferred.resolve();
+      })
+      .catch(function(data) {
+        deferred.resolve(data);
+      });
+    }
+
+    return deferred.promise;
+  }
+
+  return {
+    saveClusterPermissions: function(oldPermissions, newPermissions, params) {
+      return savePermissionsFor(Cluster, oldPermissions, newPermissions, params);
+    },
+    saveViewPermissions: function(permissions, params) {
+      return savePermissionsFor(View, permissions, params);
+    }
+  };
+}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/UnsavedDialog.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/UnsavedDialog.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/UnsavedDialog.js
new file mode 100644
index 0000000..2966a8c
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/UnsavedDialog.js
@@ -0,0 +1,41 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.service('UnsavedDialog', ['$modal', function($modal) {
+
+	return function(){
+		var modalInstance = $modal.open({
+      template: '<div class="modal-header"><h3 class="modal-title">Warning</h3></div><div class="modal-body">You have unsaved changes. Save changes or discard?</div><div class="modal-footer"><div class="btn btn-default" ng-click="cancel()">Cancel</div><div class="btn btn-warning" ng-click="discard()">Discard</div><div class="btn btn-primary" ng-click="save()">Save</div></div>',
+      controller: ['$scope', '$modalInstance', function($scope, $modalInstance) {
+        $scope.save = function() {
+          $modalInstance.close('save');
+        };
+        $scope.discard = function() {
+          $modalInstance.close('discard');
+        };
+        $scope.cancel = function() {
+          $modalInstance.close('cancel');
+        };
+      }]
+    });
+
+    return modalInstance.result;
+	};
+}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js
new file mode 100644
index 0000000..379b2ca
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/User.js
@@ -0,0 +1,91 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.factory('User', ['Restangular', '$http', 'Settings', function(Restangular, $http, Settings) {
+  Restangular.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
+    var extractedData;
+    if(operation === 'getList'){
+      extractedData = data.items;
+      extractedData.itemTotal = data.itemTotal;
+    } else {
+      extractedData = data;
+    }
+
+    return extractedData;
+  });
+
+  var Users = Restangular.all('users');
+
+  return {
+    list: function(params) {
+      return $http.get(
+        Settings.baseUrl + '/users/?'
+        + 'Users/user_name.matches(.*'+params.searchString+'.*)'
+        + '&fields=*'
+        + '&from=' + (params.currentPage-1)*params.usersPerPage
+        + '&page_size=' + params.usersPerPage
+        + (params.ldap_user === '*' ? '' : '&Users/ldap_user=' + params.ldap_user)
+        + (params.active === '*' ? '' : '&Users/active=' + params.active)
+        + (params.admin ? '&Users/admin=true' : '')
+      );
+    },
+    listByName: function(name) {
+      return $http.get(
+        Settings.baseUrl + '/users?'
+        + 'Users/user_name.matches(.*'+name+'.*)'
+        + '&from=0&page_size=20'
+      );
+    },
+    get: function(userId) {
+      return Restangular.one('users', userId).get();
+    },
+    create: function(userObj) {
+      return Restangular.all('users').post(userObj);
+    },
+    setActive: function(userId, isActive) {
+      return Restangular.one('users', userId).customPUT({'Users/active':isActive});
+    },
+    setAdmin: function(userId, isAdmin) {
+      return Restangular.one('users', userId).customPUT({'Users/admin':isAdmin});
+    },
+    setPassword: function(user, password, currentUserPassword) {
+      return $http({
+        method: 'PUT',
+        url: Settings.baseUrl + '/users/' + user.user_name,
+        data: {
+          'Users/password': password,
+          'Users/old_password': currentUserPassword
+        }
+      });
+    },
+    delete: function(userId) {
+      return Restangular.one('users', userId).remove();
+    },
+    getPrivileges : function(userId) {
+      return $http.get(Settings.baseUrl + '/privileges', {
+        params:{
+          'PrivilegeInfo/principal_type': 'USER',
+          'PrivilegeInfo/principal_name': userId,
+          'fields': '*'
+        }
+      });
+    }
+  };
+}]);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/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
new file mode 100644
index 0000000..b945984
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/View.js
@@ -0,0 +1,308 @@
+/**
+ * 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.
+ */
+'use strict';
+
+angular.module('ambariAdminConsole')
+.factory('View', ['$http', '$q', 'Settings', function($http, $q, Settings) {
+
+  function ViewInstance(item){
+    angular.extend(this, item);
+  };
+
+  ViewInstance.find = function(viewName, version, instanceName) {
+    var deferred = $q.defer();
+    var fields = [
+      'privileges/PrivilegeInfo',
+      'ViewInstanceInfo',
+      'resources'
+    ];
+
+    $http({
+      method: 'GET',
+      url: Settings.baseUrl + '/views/'+viewName+'/versions/'+version+'/instances/'+instanceName,
+      params:{
+        'fields': fields.join(',')
+      }
+    })
+    .success(function(data) {
+      deferred.resolve(new ViewInstance(data));
+    })
+    .error(function(data) {
+      deferred.reject(data);
+    });
+
+    return deferred.promise;
+  };
+
+
+  function View(item){
+    var self = this;
+    self.view_name = item.ViewInfo.view_name;
+    self.versions = '';
+    self.instances = [];
+    self.canCreateInstance = false;
+    var versions = {};
+    angular.forEach(item.versions, function(version) {
+      versions[version.ViewVersionInfo.version] = {count: version.instances.length, status: version.ViewVersionInfo.status};
+      if(version.ViewVersionInfo.status === 'DEPLOYED'){ // if atelast one version is deployed
+        self.canCreateInstance = true;
+      }
+
+      angular.forEach(version.instances, function(instance) {
+        instance.label = instance.ViewInstanceInfo.label || version.ViewVersionInfo.label || instance.ViewInstanceInfo.view_name;
+      });
+
+      self.instances = self.instances.concat(version.instances);
+    });
+    self.versions = versions;
+
+    self.versionsList = item.versions;
+  }
+
+  View.getInstance = function(viewName, version, instanceName) {
+    return ViewInstance.find(viewName, version, instanceName);
+  };
+
+  View.deleteInstance = function(viewName, version, instanceName) {
+    return $http.delete(Settings.baseUrl +'/views/'+viewName+'/versions/'+version+'/instances/'+instanceName, {
+      headers: {
+        'X-Requested-By': 'ambari'
+      }
+    });
+  };
+
+  View.updateInstance = function(viewName, version, instanceName, data) {
+    return $http({
+      method: 'PUT',
+      url: Settings.baseUrl + '/views/' +viewName + '/versions/'+version+'/instances/' + instanceName,
+      data: data
+    });
+  };
+
+  View.getPermissions = function(params) {
+    var deferred = $q.defer();
+
+    var fields = [
+      'permissions/PermissionInfo/permission_name'
+    ];
+    $http({
+      method: 'GET',
+      url: Settings.baseUrl + '/views/' + params.viewName + '/versions/'+ params.version,
+      params: {
+        'fields': fields.join(',')
+      }
+    }).success(function(data) {
+      deferred.resolve(data.permissions);
+    })
+    .catch(function(data) {
+      deferred.reject(data);
+    });
+
+    return deferred.promise;
+  };
+
+  View.getPrivileges = function(params) {
+    var deferred = $q.defer();
+
+    $http({
+      method: 'GET',
+      url: Settings.baseUrl + '/views/' + params.viewName + '/versions/' + params.version + '/instances/' + params.instanceId,
+      params: {
+        fields: 'privileges/PrivilegeInfo'
+      }
+    })
+    .success(function(data) {
+      deferred.resolve(data.privileges);
+    })
+    .catch(function(data) {
+      deferred.reject(data);
+    });
+
+    return deferred.promise;
+  };
+
+
+
+  View.getVersions = function(viewName) {
+    var deferred = $q.defer();
+
+    $http({
+      method: 'GET',
+      url: Settings.baseUrl + '/views/'+viewName + '?versions/ViewVersionInfo/status=DEPLOYED'
+    }).success(function(data) {
+      var versions = [];
+      angular.forEach(data.versions, function(version) {
+        versions.push(version.ViewVersionInfo.version);
+      });
+
+      deferred.resolve(versions);
+    }).catch(function(data) {
+      deferred.reject(data);
+    });
+    return deferred.promise;
+  };
+
+  View.createInstance = function(instanceInfo) {
+    var deferred = $q.defer();
+    var properties = {};
+
+    angular.forEach(instanceInfo.properties, function(property) {
+      properties[property.name] = property.value
+    });
+
+    $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
+        }
+      }
+    })
+    .success(function(data) {
+      deferred.resolve(data);
+    })
+    .error(function(data) {
+      deferred.reject(data);
+    });
+
+    return deferred.promise;
+  };
+
+  View.createPrivileges = function(params, data) {
+    return $http({
+      method: 'POST',
+      url: Settings.baseUrl + '/views/' + params.view_name +'/versions/'+params.version+'/instances/'+params.instance_name+'/privileges',
+      data: data
+    });
+  };
+
+  View.deletePrivileges = function(params, data) {
+    return $http({
+      method: 'DELETE',
+      url: Settings.baseUrl + '/views/' + params.view_name +'/versions/'+params.version+'/instances/'+params.instance_name+'/privileges',
+      data: data
+    });
+  };
+
+  View.updatePrivileges = function(params, privileges) {
+    return $http({
+      method: 'PUT',
+      url: Settings.baseUrl + '/views/' + params.view_name +'/versions/'+params.version+'/instances/'+params.instance_name+'/privileges',
+      data: privileges
+    });
+  };
+
+  View.deletePrivilege = function(params) {
+    return $http({
+      method: 'DELETE',
+      url: Settings.baseUrl + '/views/' + params.view_name +'/versions/'+params.version+'/instances/'+params.instance_name+'/privileges',
+      params: {
+        'PrivilegeInfo/principal_type': params.principalType,
+        'PrivilegeInfo/principal_name': params.principalName,
+        'PrivilegeInfo/permission_name': params.permissionName
+      }
+    });
+  };
+
+  View.getMeta = function(view_name, version) {
+    return $http({
+      method: 'GET',
+      url: Settings.baseUrl + '/views/'+view_name+'/versions/'+version
+    });
+  };
+
+  View.checkViewVersionStatus = function(view_name, version) {
+    var deferred = $q.defer();
+
+    $http({
+      method: 'GET',
+      url: Settings.baseUrl + '/views/' + view_name + '/versions/' + version,
+      params:{
+        'fields': 'ViewVersionInfo/status'
+      }
+    }).then(function(data) {
+      deferred.resolve(data.data.ViewVersionInfo.status);
+    }).catch(function(err) {
+      deferred.reject(err);
+    });
+
+    return deferred;
+  };
+
+  View.getAllVisibleInstance = function() {
+    var deferred = $q.defer();
+    $http({
+      method: 'GET',
+      url: Settings.baseUrl + '/views',
+      params:{
+        'fields': 'versions/instances/ViewInstanceInfo',
+        'versions/ViewVersionInfo/system': false,
+        'versions/instances/ViewInstanceInfo/visible': true
+      }
+    }).then(function(data) {
+      var instances = [];
+      data.data.items.forEach(function(view) {
+        view.versions.forEach(function(version) {
+          version.instances.forEach(function(instance) {
+            instances.push(instance.ViewInstanceInfo);
+          });
+        })
+      });
+      deferred.resolve(instances);
+    });
+
+    return deferred.promise;
+  };
+
+  View.all = function() {
+    var deferred = $q.defer();
+    var fields = [
+      'versions/ViewVersionInfo/version',
+      'versions/instances/ViewInstanceInfo',
+      'versions/*'
+    ];
+
+    $http({
+      method: 'GET',
+      url: Settings.baseUrl + '/views',
+      params:{
+        'fields': fields.join(','),
+        'versions/ViewVersionInfo/system': false
+      }
+    }).success(function(data) {
+      var views = [];
+      angular.forEach(data.items, function(item) {
+        views.push(new View(item));
+      });
+      deferred.resolve(views);
+    })
+    .error(function(data) {
+      deferred.reject(data);
+    });
+
+    return deferred.promise;
+  };
+  return View;
+}]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/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
new file mode 100644
index 0000000..e7e4391
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/styles/main.css
@@ -0,0 +1,1245 @@
+/**
+ * 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.
+ */
+
+
+
+/*
+  ------ START editable-list DIRECTIVE SECTION ------ -
+*/
+.editable-list-container.well{
+  padding: 10px;
+  position: relative;
+  margin-bottom: 25px;
+  cursor: pointer;
+}
+.editable-list-container.well.edit-mode{
+  cursor: default;
+}
+.editable-list-container.well.disabled{
+  background: white;
+}
+
+.editable-list-container .items-box{
+
+}
+.editable-list-container .items-box ul.items-list{
+  list-style-type: none;
+  margin: 0;
+  padding: 0;
+}
+
+.editable-list-container .items-box ul.items-list li.item{
+  display: inline-block;
+  padding: 4px 8px;
+  margin: 0 5px 5px 2px;
+  background: white;
+  border: 1px solid #ebebeb;
+  max-width: 100%;
+  white-space: nowrap;
+  position: relative;
+}
+
+.editable-list-container.edit-mode .items-box ul.items-list li.item{
+  padding-right: 25px;
+}
+
+.editable-list-container .items-box ul.items-list li.item.ng-leave-active{
+  display: none;
+}
+.editable-list-container .items-box ul.items-list li a{
+  text-decoration: none;
+}
+
+.editable-list-container .items-box ul.items-list li.item .close{
+  margin: -2px 0 0 5px;
+  width: 13px;
+  outline: none;
+  position: absolute;
+  display: none;
+}
+.editable-list-container.edit-mode .items-box ul.items-list li.item .close{
+  display: inline-block;
+}
+
+.editable-list-container .actions-panel{
+  position: absolute;
+  right: 5px;
+  bottom: -30px;
+  padding: 2px 5px 5px 5px;
+  background: #f5f5f5;
+  border: 1px solid #e3e3e3;
+  border-top: none;
+  border-radius: 0 0 4px 4px;
+
+  -webkit-transition: all 0.3s;
+  -o-transition: all 0.3s;
+  transition: all 0.3s;
+
+  -ms-transform-origin: 0% 0%; /* IE 9 */
+  -webkit-transform-origin: 0% 0%; /* Chrome, Safari, Opera */
+  transform-origin: 0% 0%;
+
+  -webkit-transform: rotateX(0deg);
+  -ms-transform: rotateX(0deg);
+  -o-transform: rotateX(0deg);
+  transform: rotateX(0deg);
+}
+.editable-list-container .actions-panel.ng-hide{
+  -webkit-transform: rotateX(90deg);
+  -ms-transform: rotateX(90deg);
+  -o-transform: rotateX(90deg);
+  transform: rotateX(90deg);
+}
+
+.editable-list-container.edit-mode .items-box ul.items-list li.item.add-item-input.ng-hidden{
+  display: none !important;
+}
+.editable-list-container.edit-mode .items-box ul.items-list li.item.add-item-input{
+  display: inline-block!important;
+  outline: none;
+  line-height: 20px;
+  max-width: 200px;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  position: relative;
+  padding-right: 8px;
+  -webkit-transition: none;
+  -o-transition: none;
+  transition: none;
+}
+
+.cluster-installation-progress-label{
+  display: block;
+  color: #888;
+  text-align: center;
+  padding: 10px 0px;
+  cursor: default;
+}
+
+.add-item-input span{
+  display: block;
+  outline: none;
+  min-width: 30px;
+  position: relative;
+  cursor: pointer;
+}
+.add-item-input span:focus{
+  cursor: default;
+}
+.editable-list-container .items-box ul.items-list li.item.add-item{
+  color: #ddd;
+}
+.add-item-input span:empty:before{
+  content: 'New';
+  position: absolute;
+  left: 0;
+  color: #ddd;
+}
+.add-item-input span:focus:before{
+  display: none;
+}
+.typeahead-box{
+  position: absolute;
+  left: 0;
+  margin-top: 5px;
+  background: white;
+  border: 1px solid #ebebeb;
+  z-index: 1000;
+  min-width: 65px;
+}
+.typeahead-box ul{
+  list-style-type: none;
+  margin: 0;
+  padding: 0;
+}
+.typeahead-box ul li{
+  padding: 3px 5px;
+  display: block;
+  cursor: pointer;
+}
+
+.typeahead-box ul li.selected, .typeahead-box ul li:hover{
+  background: #eee;
+}
+
+.editable-list-container.disabled .pencil-box{
+  display: none;
+}
+.editable-list-container .pencil-box{
+  position: absolute;
+  right: 5px;
+  top: 5px;
+  opacity: 0;
+  -webkit-transition: all 0.3s;
+  -o-transition: all 0.3s;
+  transition: all 0.3s;
+}
+.editable-list-container:hover .pencil-box{
+  opacity: 1;
+}
+.editable-list-container.edit-mode:hover .pencil-box{
+  opacity: 0;
+}
+
+/*
+  ------ END editable-list DIRECTIVE SECTION ------ -
+*/
+
+.tooltip-inner{
+  word-wrap: break-word;
+    text-align: left;
+}
+
+ .instances-table{
+  table-layout: fixed;
+ }
+ .description-column{
+  text-overflow: ellipsis;
+  overflow: hidden;
+  white-space: nowrap;
+  max-width: 100%;
+  display: inline-block;
+ }
+
+.paginator{
+  margin: 0;
+}
+.mainpage .panel-body{
+  padding: 20px;
+  height: 620px;
+}
+.mainpage h1{
+  font-size: 24px;
+  margin-top: 10px;
+}
+.mainpage .panel-body #main-operations-boxes {
+  padding: 10px;
+}
+.mainpage .panel-body #main-operations-boxes .thumbnail{
+  display: block;
+  height: 230px;
+  padding: 8px;
+  background-color: #eeeeee;
+  margin-bottom: 20px;
+  margin-left: 20px;
+  margin-right: 10px;
+  border: none;
+  border-radius: 0px;
+}
+.mainpage .panel-body #main-operations-boxes .thumbnail .title,
+.mainpage .panel-body #main-operations-boxes .thumbnail .description,
+.mainpage .panel-body #main-operations-boxes .thumbnail .buttons {
+  text-align: center;
+  line-height: 1.5;
+}
+.mainpage .panel-body #main-operations-boxes .thumbnail .buttons .btn{
+  width: 200px;
+  margin: 5px;
+}
+.mainpage .panel-body #main-operations-boxes .thumbnail .buttons .btn.userslist-button,
+.mainpage .panel-body #main-operations-boxes .thumbnail .buttons .btn.groupslist-button {
+  width: 100px;
+}
+.mainpage .panel-body #main-operations-boxes .thumbnail .glyphicon {
+  font-size: 50px;
+  text-align: center;
+  display: block;
+  line-height: 1.5;
+}
+.mainpage .panel-body #main-operations-boxes .col-sm-5 {
+  width: 43.5%;
+}
+
+.views-list-table .panel{
+  border-radius: 0;
+  border: none;
+  margin-top: 0;
+}
+.views-list-table h4{
+  font-size: 14px;
+}
+.views-list-table .panel-group .panel + .panel{
+  margin-top: 0;
+}
+.views-list-table .panel-group .panel .panel-heading{
+  border-radius: 0;
+  border-top: 1px solid #ddd;
+}
+.views-list-table .panel-group .panel .panel-heading{
+  background: #f9f9f9;
+}
+.views-list-table .panel-group .panel:nth-child(even) .panel-heading{
+  background: none;
+}
+.views-list-table .panel-group .panel .panel-heading .panel-title{
+  font-size: 14px;
+  font-weight: normal;
+  cursor: pointer;
+}
+.views-list-table .panel-group .panel .panel-body{
+  padding-top: 0;
+  padding-bottom: 0;
+}
+.views-list-table .panel-group .panel .panel-body table tr:first-child td{
+  border-top: none;
+}
+.views-list-table .glyphicon.glyphicon-chevron-right{
+  -webkit-transition: all 0.3s;
+  -o-transition: all 0.3s;
+  transition: all 0.3s;
+}
+.views-list-table .glyphicon.glyphicon-chevron-right.opened{
+  -webkit-transform: rotateZ(90deg);
+  -ms-transform: rotateZ(90deg);
+  -o-transform: rotateZ(90deg);
+  transform: rotateZ(90deg);
+}
+
+a.gotoinstance{
+  font-size: 12px;
+}
+
+.ats-switch{
+  border-color: #333;
+}
+.ats-switch.disabled, .ats-switch.disabled:hover{
+  cursor: not-allowed !important;
+  box-shadow: none!important;
+  border-color: #ccc!important;
+}
+.ats-switch.disabled .switch-left, .ats-switch.disabled .switch-right, .ats-switch.disabled .knob{
+  cursor: not-allowed!important;
+}
+.hide-soft{
+  display: none;
+}
+.visible{
+  display: block;
+}
+.not-required{
+  font-weight: normal;
+}
+.panel{
+  box-shadow: none;
+  border-radius: 0;
+}
+
+.views-list-table .panel-group .panel:nth-child(even) .panel-heading{
+  background: #f9f9f9;
+}
+
+.users-pane table .glyphicon{
+  width: 14px;
+}
+
+.groups-pane table .search-container .namefilter,
+.users-pane table .search-container .namefilter {
+  font-weight: normal;
+}
+
+.settings-edit-toggle.disabled, .properties-toggle.disabled{
+  color: #999;
+  cursor: not-allowed;
+}
+
+.pulldown2{
+  -webkit-transform: translateY(2px);
+  -ms-transform: translateY(2px);
+  -o-transform: translateY(2px);
+  transform: translateY(2px);
+}
+.btn.deleteuser-btn.disabled, .btn.deleteuser-btn[disabled], .btn.btn-delete-instance.disabled, .btn-default.disabled{
+  pointer-events: auto;
+  cursor: not-allowed !important;
+  background-color: #e6e6e6 !important;
+}
+
+.about .logo{
+  float: left;
+  width: 20%;
+}
+.about .content{
+  float: left;
+}
+.about .content .project{
+  font-weight: bold;
+  font-size: 2em;
+}
+
+.breadcrumb{
+  background: none;
+  font-size: 24px;
+  margin: 0;
+  padding: 0;
+}
+
+.user-edit-panel .ats-switch span.switch-right , .create-user-form .ats-switch span.switch-right{
+  background-color: #da4f49;
+  color: white;
+}
+/*
+  Style topnav menu
+*/
+.navbar-views-dropdown > a{
+  color: #c3c3c3;
+  font-size: 1.3em;
+  padding: 10px 25px 18px;
+  display: block;
+  box-shadow: none!important;
+  background: none!important;
+  text-decoration: none;
+}
+.navbar-views-dropdown > a:hover{
+  color: #fff;
+}
+.navbar-views-dropdown > a > i{
+  display: block;
+  margin-top: 1px;
+  margin-bottom: -12px;
+}
+.navbar-views-dropdown .dropdown-menu{
+  margin-top: -2px;
+}
+
+.navbar-views-dropdown .dropdown-menu a:hover{
+  background: #666;
+  color: #fff;
+}
+.navbar-views-dropdown .dropdown-menu .disabled a:hover{
+  background: none;
+  color: #999;
+}
+#top-nav .navbar.navbar-static-top{
+  min-height: 40px;
+}
+#top-nav .navbar-inverse{
+  background: none;
+  border: none;
+}
+#top-nav .navbar.navbar-static-top .navbar-inner {
+  background-image: -moz-linear-gradient(top, #555555, #333333);
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#555555), to(#333333));
+  background-image: -webkit-linear-gradient(top, #555555, #333333);
+  background-image: -o-linear-gradient(top, #555555, #333333);
+  background-image: linear-gradient(to bottom, #555555, #333333);
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#555555, endColorstr=#333333);
+  -webkit-box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);
+  -moz-box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);
+  box-shadow: inset 0 0 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1);
+  max-height: 40px;
+  height: 40px;
+}
+#top-nav .dropdown-toggle.navbar-btn{
+  margin: 4px 0 0 0;
+}
+#top-nav .navbar.navbar-static-top .logo {
+  float: left;
+  padding-top: 2px;
+}
+#top-nav .navbar.navbar-static-top .logo img {
+  height: 32px;
+}
+#top-nav .navbar.navbar-static-top .brand {
+  color: #ffffff;
+  font-size: 16px;
+  font-weight: normal;
+  line-height: 32px;
+  margin-left: 0;
+  padding: 2px 5px 0 10px;
+  text-shadow: 0 1px 0 #555555;
+  display: block;
+  float: left;
+  text-decoration: none;
+
+}
+#top-nav .navbar.navbar-static-top .brand.cluster-name{
+  margin-left: 10px;
+}
+
+.create-view-form{
+  padding-bottom: 50px;
+}
+
+.create-view-form .description{
+  display: inline-block;
+  vertical-align: middle;
+}
+.create-view-form .description h4 span{
+  font-weight: normal;
+
+}
+.create-view-form .view-header{
+}
+
+.left-navbar .panel{
+  border-radius: 0;
+}
+.left-navbar .panel-heading {
+  padding: 8px 15px;
+  font-size: 15px;
+}
+.left-navbar .panel-body {
+  padding: 5px 15px;
+  font-size: 14px;
+}
+.left-navbar .panel-body #cluster-name input{
+  font-size: 14px;
+}
+.left-navbar .panel-body #cluster-name form{
+  margin-top: 4px;
+  margin-bottom: -12px;
+}
+.left-navbar .panel-body h5 .glyphicon{
+  font-size: 13px;
+  color: #428bca;
+}
+.left-navbar .panel-body hr{
+  margin-top: 5px;
+  margin-bottom: 5px;
+}
+.left-navbar .panel-body li{
+  margin: 0 -15px;
+}
+.left-navbar .panel-body li a{
+  border-radius: 0;
+  padding-left: 33px;
+  padding-top: 8px;
+  padding-bottom: 8px;
+}
+.left-navbar .panel-body li .noclusters{
+  color: #808080;
+  padding-left: 33px;
+  padding-top: 8px;
+  padding-bottom: 8px;
+  margin: 0px;
+}
+.left-navbar .panel-body li.active a{
+  background: #666;
+}
+
+.search-container{
+  position: relative;
+}
+.search-container .close{
+  position: absolute;
+  right: 10px;
+  top: 30px;
+}
+.groups-pane .search-container .close{
+  top: 30px;
+}
+.views-list-table .search-container .close{
+  top: 5px;
+  right: 50px;
+  z-index: 10;
+}
+.views-list-pane .search-container .close{
+  right: 50px;
+  top: 5px;
+  z-index: 100;
+}
+.groups-pane table thead th{
+  border-top: 0;
+}
+.groups-pane table thead tr:first-child th{
+  border: 0;
+}
+
+.container{
+  padding-left: 0;
+  width: 940px;
+}
+
+
+@media (min-width: 1200px) {
+  .container, .navbar-static-top .container, .navbar-fixed-top .container, .navbar-fixed-bottom .container{
+    width: 1130px;
+  }
+  .container{
+    width: 1170px;
+  }
+  .mainpage .panel-body #main-operations-boxes .col-sm-5 {
+    width: 44%;
+  }
+}
+
+ul.nav li > a{
+  cursor: pointer;
+}
+
+.admin-filter{
+  cursor: pointer;
+}
+
+.glyphicon-flash.no-filter{
+  color: #999;
+}
+
+.top-buffer{
+  padding-top: 20px;
+}
+.bottom-buffer{
+  padding-bottom: 20px;
+}
+.right-buffer{
+  padding-right: 20px;
+}
+.right-margin{
+  margin-right: 20px;
+}
+.left-margin{
+  margin-left: 10px;
+}
+.bottom-margin{
+  margin-bottom: 10px;
+}
+.top-margin{
+  margin-top: 10px;
+}
+.text-left{
+  text-align: left !important;
+}
+.text-center{
+  text-align: center!important;
+}
+.padding-top-7{
+  padding-top: 7px;
+}
+.padding-left-30{
+  padding-left: 30px;
+}
+.no-margin-bottom{
+  margin-bottom: 0!important;
+}
+table.no-border tr td{
+  border: none;
+}
+.no-border{
+  border: none !important;
+}
+.top-margin-4{
+  margin-top: 4px;
+}
+.table > thead > tr > th.vertical-top{
+  vertical-align: top;
+}
+
+.groups-pane table ul{
+  list-style-type: none;
+  margin: 0;
+  padding: 0;
+}
+.groups-pane table ul li {
+  margin: 0;
+  padding: 0;
+}
+
+.property-form label{
+  width: 214px;
+  word-wrap: break-word;
+  text-overflow: ellipsis;
+  overflow: hidden;
+}
+
+.views-list-pane{}
+.views-list-pane .panel-body table{
+  margin-bottom: 0;
+}
+.views-list-pane .panel-body table tbody td{
+  border-top: none;
+  vertical-align: middle;
+}
+
+.group-edit .users button.close , .remove-button{
+  float: none;
+  -webkit-transform: translateY(1px);
+  -ms-transform: translateY(1px);
+  -o-transform: translateY(1px);
+  transform: translateY(1px);
+}
+
+.cluster-manage-access-pane .well, .views-permissions-panel .well{
+  min-height: 63px;
+}
+
+.views-permissions-panel .panel-body{
+  padding-bottom: 0;
+}
+
+.views-permissions-panel .panel-body table{
+  margin-bottom: 0;
+}
+
+
+.views-list-pane accordion .panel-group .panel-heading{
+  cursor: pointer;
+}
+
+
+
+.btn {
+  display: inline-block;
+  *display: inline;
+  padding: 4px 14px;
+  margin-bottom: 0;
+  *margin-left: .3em;
+  font-size: 14px;
+  line-height: 20px;
+  *line-height: 20px;
+  color: #333333;
+  text-align: center;
+  text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
+  vertical-align: middle;
+  cursor: pointer;
+  background-color: #f5f5f5;
+  *background-color: #e6e6e6;
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
+  background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
+  background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
+  background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
+  background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
+  background-repeat: repeat-x;
+  border: 1px solid #bbbbbb;
+  *border: 0;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+  border-color: #e6e6e6 #e6e6e6 #bfbfbf;
+  border-bottom-color: #a2a2a2;
+  -webkit-border-radius: 4px;
+     -moz-border-radius: 4px;
+          border-radius: 4px;
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);
+  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+  *zoom: 1;
+  -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+     -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+          box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+.btn:hover,
+.btn:active,
+.btn.active,
+.btn.disabled,
+.btn[disabled] {
+  color: #333333;
+  background-color: #e6e6e6;
+  *background-color: #d9d9d9;
+}
+
+.btn:active,
+.btn.active {
+  background-color: #cccccc \9;
+}
+
+.btn:first-child {
+  *margin-left: 0;
+}
+
+.btn:hover {
+  color: #333333;
+  text-decoration: none;
+  background-color: #e6e6e6;
+  *background-color: #d9d9d9;
+  /* Buttons in IE7 don't get borders, so darken on hover */
+
+  background-position: 0 -15px;
+  -webkit-transition: background-position 0.1s linear;
+     -moz-transition: background-position 0.1s linear;
+       -o-transition: background-position 0.1s linear;
+          transition: background-position 0.1s linear;
+}
+
+.btn:focus {
+  outline: thin dotted #333;
+  outline: 5px auto -webkit-focus-ring-color;
+  outline-offset: -2px;
+}
+
+.btn.active,
+.btn:active {
+  background-color: #e6e6e6;
+  background-color: #d9d9d9 \9;
+  background-image: none;
+  outline: 0;
+  -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+     -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+          box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+.btn.disabled,
+.btn[disabled] {
+  cursor: default;
+  background-color: #e6e6e6;
+  background-image: none;
+  opacity: 0.65;
+  filter: alpha(opacity=65);
+  -webkit-box-shadow: none;
+     -moz-box-shadow: none;
+          box-shadow: none;
+}
+
+
+
+.btn-primary.active,
+.btn-warning.active,
+.btn-danger.active,
+.btn-success.active,
+.btn-info.active,
+.btn-inverse.active {
+  color: rgba(255, 255, 255, 0.75);
+}
+
+.btn {
+  border-color: #c5c5c5;
+  border-color: rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25);
+}
+
+.btn-primary {
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  background-color: #006dcc;
+  *background-color: #0044cc;
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
+  background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
+  background-image: -o-linear-gradient(top, #0088cc, #0044cc);
+  background-image: linear-gradient(to bottom, #0088cc, #0044cc);
+  background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
+  background-repeat: repeat-x;
+  border-color: #0044cc #0044cc #002a80;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);
+  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+
+.btn-primary:hover,
+.btn-primary:active,
+.btn-primary.active,
+.btn-primary.disabled,
+.btn-primary[disabled] {
+  color: #ffffff;
+  background-color: #0044cc;
+  *background-color: #003bb3;
+}
+
+.btn-primary:active,
+.btn-primary.active {
+  background-color: #003399 \9;
+}
+
+.btn-warning {
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  background-color: #faa732;
+  *background-color: #f89406;
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));
+  background-image: -webkit-linear-gradient(top, #fbb450, #f89406);
+  background-image: -o-linear-gradient(top, #fbb450, #f89406);
+  background-image: linear-gradient(to bottom, #fbb450, #f89406);
+  background-image: -moz-linear-gradient(top, #fbb450, #f89406);
+  background-repeat: repeat-x;
+  border-color: #f89406 #f89406 #ad6704;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);
+  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+
+.btn-warning:hover,
+.btn-warning:active,
+.btn-warning.active,
+.btn-warning.disabled,
+.btn-warning[disabled] {
+  color: #ffffff;
+  background-color: #f89406;
+  *background-color: #df8505;
+}
+
+.btn-warning:active,
+.btn-warning.active {
+  background-color: #c67605 \9;
+}
+
+.btn-danger {
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  background-color: #da4f49;
+  *background-color: #bd362f;
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));
+  background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f);
+  background-image: -o-linear-gradient(top, #ee5f5b, #bd362f);
+  background-image: linear-gradient(to bottom, #ee5f5b, #bd362f);
+  background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f);
+  background-repeat: repeat-x;
+  border-color: #bd362f #bd362f #802420;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);
+  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+
+.btn-danger:hover,
+.btn-danger:active,
+.btn-danger.active,
+.btn-danger.disabled,
+.btn-danger[disabled] {
+  color: #ffffff;
+  background-color: #bd362f;
+  *background-color: #a9302a;
+}
+
+.btn-danger:active,
+.btn-danger.active {
+  background-color: #942a25 \9;
+}
+
+.btn-success {
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  background-color: #5bb75b;
+  *background-color: #51a351;
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));
+  background-image: -webkit-linear-gradient(top, #62c462, #51a351);
+  background-image: -o-linear-gradient(top, #62c462, #51a351);
+  background-image: linear-gradient(to bottom, #62c462, #51a351);
+  background-image: -moz-linear-gradient(top, #62c462, #51a351);
+  background-repeat: repeat-x;
+  border-color: #51a351 #51a351 #387038;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);
+  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+
+.btn-success:hover,
+.btn-success:active,
+.btn-success.active,
+.btn-success.disabled,
+.btn-success[disabled] {
+  color: #ffffff;
+  background-color: #51a351;
+  *background-color: #499249;
+}
+
+.btn-success:active,
+.btn-success.active {
+  background-color: #408140 \9;
+}
+
+.btn-info {
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  background-color: #49afcd;
+  *background-color: #2f96b4;
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));
+  background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4);
+  background-image: -o-linear-gradient(top, #5bc0de, #2f96b4);
+  background-image: linear-gradient(to bottom, #5bc0de, #2f96b4);
+  background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4);
+  background-repeat: repeat-x;
+  border-color: #2f96b4 #2f96b4 #1f6377;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);
+  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+
+.btn-info:hover,
+.btn-info:active,
+.btn-info.active,
+.btn-info.disabled,
+.btn-info[disabled] {
+  color: #ffffff;
+  background-color: #2f96b4;
+  *background-color: #2a85a0;
+}
+
+.btn-info:active,
+.btn-info.active {
+  background-color: #24748c \9;
+}
+
+.btn-inverse {
+  color: #ffffff;
+  text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
+  background-color: #363636;
+  *background-color: #222222;
+  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));
+  background-image: -webkit-linear-gradient(top, #444444, #222222);
+  background-image: -o-linear-gradient(top, #444444, #222222);
+  background-image: linear-gradient(to bottom, #444444, #222222);
+  background-image: -moz-linear-gradient(top, #444444, #222222);
+  background-repeat: repeat-x;
+  border-color: #222222 #222222 #000000;
+  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
+  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);
+  filter: progid:dximagetransform.microsoft.gradient(enabled=false);
+}
+
+.btn-inverse:hover,
+.btn-inverse:active,
+.btn-inverse.active,
+.btn-inverse.disabled,
+.btn-inverse[disabled] {
+  color: #ffffff;
+  background-color: #222222;
+  *background-color: #151515;
+}
+
+.btn-inverse:active,
+.btn-inverse.active {
+  background-color: #080808 \9;
+}
+
+button.btn,
+input[type="submit"].btn {
+  *padding-top: 3px;
+  *padding-bottom: 3px;
+}
+
+button.btn::-moz-focus-inner,
+input[type="submit"].btn::-moz-focus-inner {
+  padding: 0;
+  border: 0;
+}
+
+button.btn.btn-large,
+input[type="submit"].btn.btn-large {
+  *padding-top: 7px;
+  *padding-bottom: 7px;
+}
+
+button.btn.btn-small,
+input[type="submit"].btn.btn-small {
+  *padding-top: 3px;
+  *padding-bottom: 3px;
+}
+
+button.btn.btn-mini,
+input[type="submit"].btn.btn-mini {
+  *padding-top: 1px;
+  *padding-bottom: 1px;
+}
+
+button.btn.btn-xs{
+  padding: 1px 5px;
+  font-size: 12px;
+  line-height: 1.5;
+  border-radius: 3px;
+}
+.alert-info {
+  background-color: #E6F1F6;
+  border-color: #D2D9DD;
+  color: #4E575B;
+  text-shadow: none;
+}
+.alert-info .link {
+  padding: 0 15px;
+}
+.alert-info .link-left-pad {
+  padding-left: 15px;
+}
+.breadcrumb > .active {
+  color: #666;
+}
+
+.alert-container {
+  position: fixed;
+  top: 50px;
+  z-index: 1000;
+  width: 300px;
+  margin-left: -150px;
+  left: 50%;
+}
+.ambariAlert {
+  position: relative;
+  border: 1px solid #c4c4c4;
+  border-radius: 4px 0 0 4px;
+  box-shadow: 0 0px 4px #ebebeb;
+  width: 300px;
+  background: white;
+  margin-bottom: 20px;
+  z-index: 1000;
+  padding: 20px 20px 20px 60px;
+  max-height: 100%;
+  display: block;
+  clear: both;
+  text-align: left;
+  -webkit-box-sizing: border-box;
+  -moz-box-sizing: border-box;
+  box-sizing: border-box;
+}
+.ambariAlert .content {
+  display: inline-block;
+  padding-right: 10px;
+}
+.ambariAlert .icon-box {
+  display: inline-block;
+  font-size: 30px;
+  position: absolute;
+  left: 15px;
+  top: 10px;
+}
+.ambariAlert .more {
+  display: none;
+  margin-top: 10px;
+}
+.ambariAlert .more.visible {
+  display: block;
+}
+.ambariAlert.invisible {
+  -webkit-transform: translateX(1000px);
+  -ms-transform: translateX(1000px);
+  -o-transform: translateX(1000px);
+  transform: translateX(1000px);
+
+  padding: 0;
+  margin: 0;
+  max-height: 0;
+}
+.ambariAlert .close {
+  position: absolute;
+  right: 10px;
+  top: 10px;
+  outline: none;
+}
+.ambariAlert.error {
+  border-left: 3px solid #ef2427;
+}
+.ambariAlert.error .icon-box {
+  color: #ef2427;
+}
+
+.ambariAlert.success {
+  border-left: 3px solid #82c534;
+}
+.ambariAlert.success .icon-box {
+  color: #82c534;
+}
+
+.ambariAlert.info {
+  border-left: 3px solid #ffbc5b;
+}
+.ambariAlert.info .icon-box {
+  color: #ffbc5b;
+}
+
+.edit-cluster-name {
+  cursor: pointer;
+}
+
+.edit-cluster-name:hover {
+  color: #428bca;
+}
+
+.editClusterNameForm button.btn {
+  padding: 4px 8px;
+}
+
+.editClusterNameForm input {
+  width: 161px;
+  float: left;
+  margin-right: 5px;
+}
+
+.no-animation *{
+  -webkit-transition: none!important;
+  -o-transition: none!important;
+  transition: none!important;
+}
+
+
+.viewstatus{
+  display: inline-block;
+}
+.viewstatus.pending{
+  width: 12px;
+  height: 12px;
+  border: 2px solid black;
+  border-radius: 50%;
+  vertical-align: middle;
+  position: relative;
+  border-radius: 50%;
+}
+
+.viewstatus.pending:before, .viewstatus.pending:after{
+  content: '';
+  position: absolute;
+  left: 4px;
+  top: 3px;
+  width: 5px;
+  height: 2px;
+  background: black;
+}
+.viewstatus.pending:after{
+  top: -3px;
+  left: 3px;
+  width: 2px;
+  height: 2px;
+  border-radius: 100%;
+}
+.viewstatus.pending:before{
+  -webkit-transform-origin: 0% 50%;
+  -moz-transform-origin: 0% 50%;
+  -ms-transform-origin: 0% 50%;
+  -o-transform-origin: 0% 50%;
+  transform-origin: 0% 50%;
+
+  animation: rotate 2.0s infinite linear;
+  -webkit-animation: rotate 2.0s infinite linear;
+}
+
+@-webkit-keyframes rotate { 100% { -webkit-transform: rotate(360deg) }}
+@keyframes rotate { 100% { transform: rotate(360deg); -webkit-transform: rotate(360deg) }}
+
+
+.viewstatus.deploying{
+  width: 17px;
+  height: 12px;
+  text-align: center;
+  vertical-align: middle;
+}
+.viewstatus.deploying > div{
+  background: black;
+  height: 100%;
+  width: 3px;
+  display: inline-block;
+  -webkit-animation: stretchdelay 1.2s infinite ease-in-out;
+  animation: stretchdelay 1.2s infinite ease-in-out;
+}
+.viewstatus.deploying .rect2 {
+  -webkit-animation-delay: -1.1s;
+  animation-delay: -1.1s;
+}
+.viewstatus.deploying .rect3 {
+  -webkit-animation-delay: -1.0s;
+  animation-delay: -1.0s;
+}
+
+@-webkit-keyframes stretchdelay {
+  0%, 40%, 100% { -webkit-transform: scaleY(0.4) }
+  20% { -webkit-transform: scaleY(1.0) }
+}
+
+@keyframes stretchdelay {
+  0%, 40%, 100% {
+    transform: scaleY(0.4);
+    -webkit-transform: scaleY(0.4);
+  }  20% {
+    transform: scaleY(1.0);
+    -webkit-transform: scaleY(1.0);
+  }
+}
+
+accordion .panel-group .panel{
+  overflow: visible;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/9213dcca/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
new file mode 100644
index 0000000..1039316
--- /dev/null
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/ambariViews/create.html
@@ -0,0 +1,122 @@
+<!--
+* 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="#/views">Views</a></li>
+  <li class="active">Create Instance</li>
+</ol>
+<hr>
+<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">
+        <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">
+        <select ng-model="version" class="instanceversion-input form-control" ng-change="versionChanged()" ng-options="o as o for o in versions"></select>
+      </div>
+    </div>
+  </div>
+
+  <div class="panel panel-default">
+    <div class="panel-heading">
+      <h3 class="panel-title">Details</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">
+          <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'>
+            This field is required.
+          </div>
+          <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.instanceNameInput.$error.pattern && form.instanceCreateForm.submitted'>
+            Must not contain any special characters or spaces.
+          </div>
+          <div class="alert alert-danger no-margin-bottom top-margin" ng-show='instanceExists'>
+            Instance with this name already exists.
+          </div>
+        </div>
+      </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">
+          <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'>
+            This field is required.
+          </div>
+          <div class="alert alert-danger no-margin-bottom top-margin" ng-show='form.instanceCreateForm.displayLabel.$error.pattern && form.instanceCreateForm.submitted'>
+            Must not contain any special characters.
+          </div>
+        </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">
+          <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">
+        <div class="col-sm-10 col-sm-offset-2">
+          <div class="checkbox">
+            <label>
+              <input type="checkbox" ng-model='instance.visible' class="visibilityCheckbox"> Visible
+            </label>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+  <div class="panel panel-default">
+    <div class="panel-heading">
+      <h3 class="panel-title">Properties</h3>
+    </div>
+    <div class="panel-body property-form">
+      <div class="form-group" ng-repeat="parameter in instance.properties"
+        ng-class="{'has-error' : (form.instanceCreateForm[parameter.name].$error.required && form.instanceCreateForm.submitted)}" >
+        <label for="" class="col-sm-3 control-label" ng-class="{'not-required': !parameter.required}" tooltip="{{parameter.description}}">{{parameter.name}}{{parameter.required ? '*' : ''}}</label>
+        <div class="col-sm-9">
+          <input type="{{parameter.masked ? 'password' : 'text'}}" class="form-control viewproperty-input"  name="{{parameter.name}}" ng-required="parameter.required" ng-model="parameter.value" autocomplete="off" tooltip="{{parameter.description}}">
+          <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>
+      </div>
+      <div ng-show="!instance.properties.length">
+        <div class="alert alert-info">There are no properties defined for this view.</div>
+      </div>
+    </div>
+  </div>
+
+  <div class="col-sm-12 ">
+    <button class="btn btn-primary pull-right left-margin save-button" ng-click="save()" type="submit">Save</button>
+    <a href ng-click="cancel()" class="btn btn-default pull-right cancel-button">Cancel</a>
+  </div>
+
+</form>
\ No newline at end of file


Mime
View raw message