ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From atk...@apache.org
Subject [2/2] ambari git commit: AMBARI-22519 Admin View: add ability to change roles. (atkach)
Date Mon, 27 Nov 2017 13:41:17 GMT
AMBARI-22519 Admin View: add ability to change roles. (atkach)


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

Branch: refs/heads/trunk
Commit: 32e25b80c43158bd7114f11825eaa590c9b7e8b0
Parents: 3dca560
Author: Andrii Tkach <atkach@apache.org>
Authored: Mon Nov 27 14:18:59 2017 +0200
Committer: Andrii Tkach <atkach@apache.org>
Committed: Mon Nov 27 15:41:01 2017 +0200

----------------------------------------------------------------------
 .../main/resources/ui/admin-web/app/index.html  |   1 -
 .../userManagement/GroupCreateCtrl.js           |  32 +-
 .../controllers/userManagement/GroupEditCtrl.js | 162 +++++++---
 .../userManagement/GroupsListCtrl.js            |  17 +-
 .../userManagement/UserCreateCtrl.js            |  25 +-
 .../controllers/userManagement/UserEditCtrl.js  | 304 ++++++++++++-------
 .../userManagement/UserManagementCtrl.js        |   4 +-
 .../controllers/userManagement/UsersListCtrl.js |  69 +++--
 .../ui/admin-web/app/scripts/i18n.config.js     |   6 +-
 .../admin-web/app/scripts/services/Cluster.js   |  90 +++---
 .../ui/admin-web/app/scripts/services/Group.js  | 144 ++++-----
 .../app/scripts/services/GroupConstants.js      |  38 ---
 .../app/scripts/services/RoleDetailsModal.js    |   5 +-
 .../ui/admin-web/app/scripts/services/User.js   |  17 +-
 .../resources/ui/admin-web/app/styles/main.css  |   5 -
 .../ui/admin-web/app/styles/user-management.css |  13 +
 .../app/views/remoteClusters/list.html          |   5 +-
 .../admin-web/app/views/stackVersions/list.html |   7 +-
 .../app/views/userManagement/groupEdit.html     | 149 +++++----
 .../app/views/userManagement/main.html          |   4 +-
 .../userManagement/modals/groupCreate.html      |   8 +-
 .../views/userManagement/modals/userCreate.html |  10 +-
 .../app/views/userManagement/userEdit.html      |  48 ++-
 .../app/views/userManagement/usersList.html     |   2 +-
 24 files changed, 647 insertions(+), 518 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/index.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/index.html b/ambari-admin/src/main/resources/ui/admin-web/app/index.html
index e3b817e..bf033e6 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/index.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/index.html
@@ -153,7 +153,6 @@
 <script src="scripts/services/Utility.js"></script>
 <script src="scripts/services/UserConstants.js"></script>
 <script src="scripts/services/User.js"></script>
-<script src="scripts/services/GroupConstants.js"></script>
 <script src="scripts/services/Group.js"></script>
 <script src="scripts/services/RemoteCluster.js"></script>
 <script src="scripts/services/View.js"></script>

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupCreateCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupCreateCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupCreateCtrl.js
index 94a2c9f..a34033b 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupCreateCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupCreateCtrl.js
@@ -19,8 +19,8 @@
 
 angular.module('ambariAdminConsole')
 .controller('GroupCreateCtrl',
-['$scope', '$rootScope', 'Group', '$location', 'Alert', 'UnsavedDialog', '$translate', '$modalInstance', 'Cluster',
-function($scope, $rootScope, Group, $location, Alert, UnsavedDialog, $translate, $modalInstance, Cluster) {
+['$scope', '$rootScope', 'Group', '$location', 'Alert', 'UnsavedDialog', '$translate', '$modalInstance', 'Cluster', 'RoleDetailsModal',
+function($scope, $rootScope, Group, $location, Alert, UnsavedDialog, $translate, $modalInstance, Cluster, RoleDetailsModal) {
   var $t = $translate.instant;
 
   $scope.form = {};
@@ -33,10 +33,8 @@ function($scope, $rootScope, Group, $location, Alert, UnsavedDialog, $translate,
 
 
   function loadRoles() {
-    Cluster.getPermissions().then(function(data) {
-      $scope.roleOptions = data.map(function(item) {
-        return item.PermissionInfo;
-      });
+    return Cluster.getRoleOptions().then(function (data) {
+      $scope.roleOptions = data;
     });
   }
 
@@ -60,6 +58,9 @@ function($scope, $rootScope, Group, $location, Alert, UnsavedDialog, $translate,
   }
 
   function saveMembers(group, members) {
+    if (!members.length) {
+      return;
+    }
     group.members = members.filter(function(item) {
       return item.trim();
     }).map(function(item) {
@@ -70,6 +71,12 @@ function($scope, $rootScope, Group, $location, Alert, UnsavedDialog, $translate,
     });
   }
 
+  $scope.showHelpPage = function() {
+    Cluster.getRolesWithAuthorizations().then(function(roles) {
+      RoleDetailsModal.show(roles);
+    });
+  };
+
   $scope.save = function () {
     $scope.form.groupCreateForm.submitted = true;
     if ($scope.form.groupCreateForm.$valid) {
@@ -87,21 +94,22 @@ function($scope, $rootScope, Group, $location, Alert, UnsavedDialog, $translate,
   };
 
   function saveRole() {
+    if (!$scope.formData.role || $scope.formData.role === 'NONE') {
+      return;
+    }
     Cluster.createPrivileges(
       {
         clusterId: $rootScope.cluster.Clusters.cluster_name
       },
       [{PrivilegeInfo: {
-        permission_name: $scope.roleOptions.filter(function(role) {
-          return role.permission_id == Number($scope.formData.role);
-        })[0].permission_name,
+        permission_name: $scope.formData.role,
         principal_name: $scope.formData.groupName,
         principal_type: 'GROUP'
       }}]
     )
-      .catch(function(data) {
-        Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message);
-      });
+    .catch(function(data) {
+      Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message);
+    });
   }
 
   $scope.cancel = function () {

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupEditCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupEditCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupEditCtrl.js
index ff705eb..8855317 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupEditCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupEditCtrl.js
@@ -19,9 +19,14 @@
 
 angular.module('ambariAdminConsole')
 .controller('GroupEditCtrl',
-['$scope', 'Group', '$routeParams', 'Cluster', 'View', 'Alert', 'ConfirmationModal', '$location', 'GroupConstants', '$translate',
-function($scope, Group, $routeParams, Cluster, View, Alert, ConfirmationModal, $location, GroupConstants, $translate) {
+['$scope', '$rootScope', 'Group', '$routeParams', 'Cluster', 'View', 'Alert', 'ConfirmationModal', '$location', '$translate', 'RoleDetailsModal',
+function($scope, $rootScope, Group, $routeParams, Cluster, View, Alert, ConfirmationModal, $location,  $translate, RoleDetailsModal) {
   var $t = $translate.instant;
+  var nonRole = {
+    permission_name: 'NONE',
+    permission_label: $t('users.roles.none')
+  };
+
   $scope.constants = {
     group: $t('common.group'),
     view: $t('common.view').toLowerCase(),
@@ -32,7 +37,6 @@ function($scope, Group, $routeParams, Cluster, View, Alert, ConfirmationModal, $
   $scope.group.editingUsers = [];
   $scope.groupMembers = [];
   $scope.dataLoaded = false;
-  
   $scope.isMembersEditing = false;
 
   $scope.$watch(function() {
@@ -62,30 +66,11 @@ function($scope, Group, $routeParams, Cluster, View, Alert, ConfirmationModal, $
     $scope.group.saveMembers().catch(function(data) {
         Alert.error($t('groups.alerts.cannotUpdateGroupMembers'), "<div class='break-word'>" + data.message + "</div>");
       }).finally(function() {
-        loadMembers();
+        loadGroup();
       });
     $scope.isMembersEditing = false;
   };
 
-
-  function loadMembers(){
-    $scope.group.getMembers().then(function(members) {
-      $scope.group.groupTypeName = $t(GroupConstants.TYPES[$scope.group.group_type].LABEL_KEY);
-      $scope.groupMembers = members;
-      $scope.group.editingUsers = angular.copy($scope.groupMembers);
-    });
-  }    
-  
-  $scope.group.isLDAP().then(function(isLDAP) {
-    $scope.group.ldap_group = isLDAP;
-    $scope.group.getGroupType().then(function() {
-      $scope.group.groupTypeName = $t(GroupConstants.TYPES[$scope.group.group_type].LABEL_KEY);
-    });
-    loadMembers();
-  });
-
-  $scope.group.getGroupType();
-
   $scope.deleteGroup = function(group) {
     ConfirmationModal.show(
       $t('common.delete', {
@@ -119,12 +104,9 @@ function($scope, Group, $routeParams, Cluster, View, Alert, ConfirmationModal, $
           });
         }
         group.destroy().then(function() {
-          $location.path('/userManagement');
+          $location.path('/userManagement?tab=groups');
           if (clusterPrivilegesIds.length) {
-            Cluster.getAllClusters().then(function (clusters) {
-              var clusterName = clusters[0].Clusters.cluster_name;
-              Cluster.deleteMultiplePrivileges(clusterName, clusterPrivilegesIds);
-            });
+            Cluster.deleteMultiplePrivileges($rootScope.cluster.Clusters.cluster_name, clusterPrivilegesIds);
           }
           angular.forEach(viewsPrivileges, function(privilege) {
             View.deletePrivilege(privilege);
@@ -135,7 +117,7 @@ function($scope, Group, $routeParams, Cluster, View, Alert, ConfirmationModal, $
   };
 
 
-  $scope.removePrivilege = function(name, privilege) {
+  $scope.removeViewPrivilege = function(name, privilege) {
     var privilegeObject = {
         id: privilege.privilege_id,
         view_name: privilege.view_name,
@@ -143,40 +125,124 @@ function($scope, Group, $routeParams, Cluster, View, Alert, ConfirmationModal, $
         instance_name: name
     };
     View.deletePrivilege(privilegeObject).then(function() {
-      loadPrivileges();
+      loadGroup();
     });
   };
 
-function loadPrivileges() {
-  // Load privileges
-  Group.getPrivileges($routeParams.id).then(function(data) {
+  $scope.showHelpPage = function() {
+    Cluster.getRolesWithAuthorizations().then(function(roles) {
+      RoleDetailsModal.show(roles);
+    });
+  };
+
+  $scope.updateRole = function () {
+    var clusterName = $rootScope.cluster.Clusters.cluster_name;
+    if ($scope.originalRole.permission_name !== $scope.currentRole.permission_name) {
+      if ($scope.currentRole.permission_name === 'NONE') {
+        deleteGroupRoles(clusterName, $scope.group).finally(loadGroup);
+      } else {
+        if ($scope.group.roles.length) {
+          deleteGroupRoles(clusterName, $scope.group, true).finally(function() {
+            addGroupRoles(clusterName, $scope.currentRole, $scope.group).finally(loadGroup);
+          });
+        } else {
+          addGroupRoles(clusterName, $scope.currentRole, $scope.group).finally(loadGroup);
+        }
+      }
+    }
+  };
+
+  function deleteGroupRoles(clusterName, group, ignoreAlert) {
+    return Cluster.deleteMultiplePrivileges(
+      clusterName,
+      group.roles.map(function(item) {
+        return item.privilege_id;
+      })
+    ).then(function () {
+      if (!ignoreAlert) {
+        Alert.success($t('users.alerts.roleChangedToNone', {
+          user_name: group.group_name
+        }));
+      }
+    }).catch(function (data) {
+      Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message);
+    });
+  }
+
+  function addGroupRoles(clusterName, newRole, group) {
+    return Cluster.createPrivileges(
+      {
+        clusterId: clusterName
+      },
+      [{
+        PrivilegeInfo: {
+          permission_name: newRole.permission_name,
+          principal_name: group.group_name,
+          principal_type: 'GROUP'
+        }
+      }]
+    ).then(function () {
+      Alert.success($t('users.alerts.roleChanged', {
+        name: group.group_name,
+        role: newRole.permission_label
+      }));
+    }).catch(function (data) {
+      Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message);
+    });
+  }
+
+  function parsePrivileges(rawPrivileges) {
     var privileges = {
       clusters: {},
       views: {}
     };
-    angular.forEach(data.data.items, function(privilege) {
+    angular.forEach(rawPrivileges, function (privilege) {
       privilege = privilege.PrivilegeInfo;
-      if(privilege.type === 'CLUSTER'){
+      if (privilege.type === 'CLUSTER') {
         // This is cluster
         privileges.clusters[privilege.cluster_name] = privileges.clusters[privilege.cluster_name] || [];
         privileges.clusters[privilege.cluster_name].push(privilege.permission_label);
-      } else if ( privilege.type === 'VIEW'){
-        privileges.views[privilege.instance_name] = privileges.views[privilege.instance_name] || { privileges:[]};
-        privileges.views[privilege.instance_name].version = privilege.version;
-        privileges.views[privilege.instance_name].view_name = privilege.view_name;
-        privileges.views[privilege.instance_name].privilege_id = privilege.privilege_id;
-        privileges.views[privilege.instance_name].privileges.push(privilege.permission_label);
+      } else if (privilege.type === 'VIEW') {
+        privileges.views[privilege.instance_name] = privileges.views[privilege.instance_name] || {
+          privileges: [],
+          version: privilege.version,
+          view_name: privilege.view_name,
+          privilege_id: privilege.privilege_id
+        };
+        if (privileges.views[privilege.instance_name].privileges.indexOf(privilege.permission_label) === -1) {
+          privileges.views[privilege.instance_name].privileges.push(privilege.permission_label);
+        }
       }
     });
 
-    $scope.privileges = data.data.items.length ? privileges : null;
+    $scope.privileges = privileges;
     $scope.noClusterPriv = $.isEmptyObject(privileges.clusters);
     $scope.noViewPriv = $.isEmptyObject(privileges.views);
     $scope.hidePrivileges = $scope.noClusterPriv && $scope.noViewPriv;
-    $scope.dataLoaded = true;
-  }).catch(function(data) {
-    Alert.error($t('common.alerts.cannotLoadPrivileges'), data.data.message);
-  });
-}
-loadPrivileges();
+  }
+
+  function loadGroup() {
+    Group.get($routeParams.id).then(function(group) {
+      $scope.group = group;
+      parsePrivileges(group.privileges);
+      var clusterRole = $scope.group.roles[0];
+      $scope.currentRole = clusterRole || nonRole;
+      $scope.originalRole = clusterRole || nonRole;
+      $scope.groupMembers = group.members.map(function(item) {
+        return item.MemberInfo.user_name;
+      });
+      $scope.group.editingUsers = angular.copy($scope.groupMembers);
+    }).finally(function() {
+      $scope.dataLoaded = true;
+    });
+  }
+
+  function loadRoles() {
+    return Cluster.getRoleOptions().then(function(data) {
+      $scope.roleOptions = data;
+    });
+  }
+
+  loadRoles().finally(loadGroup);
+
 }]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupsListCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupsListCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupsListCtrl.js
index af77ba9..61b5282 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupsListCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/GroupsListCtrl.js
@@ -19,8 +19,8 @@
 
 angular.module('ambariAdminConsole')
 .controller('GroupsListCtrl',
-['$scope', 'Group', '$modal', 'ConfirmationModal', '$rootScope', 'GroupConstants', '$translate', 'Settings', 'Cluster', 'View', '$location',
-function($scope, Group, $modal, ConfirmationModal, $rootScope, GroupConstants, $translate, Settings, Cluster, View, $location) {
+['$scope', 'Group', '$modal', 'ConfirmationModal', '$rootScope', '$translate', 'Settings', 'Cluster', 'View', 'Alert',
+function($scope, Group, $modal, ConfirmationModal, $rootScope, $translate, Settings, Cluster, View, Alert) {
   var $t = $translate.instant;
   $scope.constants = {
     groups: $t('common.groups').toLowerCase()
@@ -70,15 +70,15 @@ function($scope, Group, $modal, ConfirmationModal, $rootScope, GroupConstants, $
       $scope.tableInfo.showed = groups.length;
     })
     .catch(function(data) {
-      console.error($t('groups.alerts.getGroupsListError'));
+      Alert.error($t('groups.alerts.getGroupsListError'), data.data.message);
     });
   }
 
   $scope.typeFilterOptions = [{ label: $t('common.all'), value: '*'}]
-    .concat(Object.keys(GroupConstants.TYPES).map(function(key) {
+    .concat(Object.keys(Group.getTypes()).map(function(key) {
       return {
-        label: $t(GroupConstants.TYPES[key].LABEL_KEY),
-        value: GroupConstants.TYPES[key].VALUE
+        label: $t(Group.getTypes()[key].LABEL_KEY),
+        value: Group.getTypes()[key].VALUE
       };
   }));
   $scope.filter.type = $scope.typeFilterOptions[0];
@@ -153,10 +153,7 @@ function($scope, Group, $modal, ConfirmationModal, $rootScope, GroupConstants, $
         }
         group.destroy().then(function() {
           if (clusterPrivilegesIds.length) {
-            Cluster.getAllClusters().then(function (clusters) {
-              var clusterName = clusters[0].Clusters.cluster_name;
-              Cluster.deleteMultiplePrivileges(clusterName, clusterPrivilegesIds);
-            });
+            Cluster.deleteMultiplePrivileges($rootScope.cluster.Clusters.cluster_name, clusterPrivilegesIds);
           }
           angular.forEach(viewsPrivileges, function(privilege) {
             View.deletePrivilege(privilege);

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserCreateCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserCreateCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserCreateCtrl.js
index 34637ae..3b29b90 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserCreateCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserCreateCtrl.js
@@ -19,8 +19,8 @@
 
 angular.module('ambariAdminConsole')
 .controller('UserCreateCtrl',
-['$scope', '$rootScope', 'User', '$location', 'Alert', 'UnsavedDialog', '$translate', 'Cluster', '$modalInstance',
-function($scope, $rootScope, User, $location, Alert, UnsavedDialog, $translate, Cluster, $modalInstance) {
+['$scope', '$rootScope', 'User', '$location', 'Alert', 'UnsavedDialog', '$translate', 'Cluster', '$modalInstance', 'RoleDetailsModal',
+function($scope, $rootScope, User, $location, Alert, UnsavedDialog, $translate, Cluster, $modalInstance, RoleDetailsModal) {
   var $t = $translate.instant;
 
   $scope.form = {};
@@ -28,17 +28,15 @@ function($scope, $rootScope, User, $location, Alert, UnsavedDialog, $translate,
     userName: '',
     password: '',
     confirmPassword: '',
-    role: null,
+    role: '',
     isAdmin: false,
     isActive: true
   };
   $scope.roleOptions = [];
 
   function loadRoles() {
-    Cluster.getPermissions().then(function(data) {
-      $scope.roleOptions = data.map(function(item) {
-        return item.PermissionInfo;
-      });
+    return Cluster.getRoleOptions().then(function (data) {
+      $scope.roleOptions = data;
     });
   }
 
@@ -61,6 +59,12 @@ function($scope, $rootScope, User, $location, Alert, UnsavedDialog, $translate,
     }
   }
 
+  $scope.showHelpPage = function() {
+    Cluster.getRolesWithAuthorizations().then(function(roles) {
+      RoleDetailsModal.show(roles);
+    });
+  };
+
   $scope.save = function () {
     $scope.form.userCreateForm.submitted = true;
     if ($scope.form.userCreateForm.$valid) {
@@ -83,14 +87,15 @@ function($scope, $rootScope, User, $location, Alert, UnsavedDialog, $translate,
   };
 
   function saveRole() {
+    if (!$scope.formData.role || $scope.formData.role === 'NONE') {
+      return;
+    }
     Cluster.createPrivileges(
       {
         clusterId: $rootScope.cluster.Clusters.cluster_name
       },
       [{PrivilegeInfo: {
-        permission_name: $scope.roleOptions.filter(function(role) {
-          return role.permission_id == Number($scope.formData.role);
-        })[0].permission_name,
+        permission_name: $scope.formData.role,
         principal_name: $scope.formData.userName,
         principal_type: 'USER'
       }}]

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserEditCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserEditCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserEditCtrl.js
index 001bb1b..a3c96cd 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserEditCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserEditCtrl.js
@@ -18,9 +18,15 @@
 'use strict';
 
 angular.module('ambariAdminConsole')
-.controller('UserEditCtrl', ['$scope', '$routeParams', 'Cluster', 'User', 'View', '$modal', '$location', 'ConfirmationModal', 'Alert', 'Auth', 'getDifference', 'Group', '$q', 'UserConstants', '$translate', function($scope, $routeParams, Cluster, User, View, $modal, $location, ConfirmationModal, Alert, Auth, getDifference, Group, $q, UserConstants, $translate) {
+.controller('UserEditCtrl',
+['$scope', '$rootScope', '$routeParams', 'Cluster', 'User', 'View', '$modal', '$location', 'ConfirmationModal', 'Alert', 'Auth', 'getDifference', 'Group', '$q', 'UserConstants', '$translate', 'RoleDetailsModal',
+function($scope, $rootScope, $routeParams, Cluster, User, View, $modal, $location, ConfirmationModal, Alert, Auth, getDifference, Group, $q, UserConstants, $translate, RoleDetailsModal) {
 
   var $t = $translate.instant;
+  var nonRole = {
+    permission_name: 'NONE',
+    permission_label: $t('users.roles.none')
+  };
 
   $scope.constants = {
     user: $t('common.user'),
@@ -31,77 +37,95 @@ angular.module('ambariAdminConsole')
     cluster: $t('common.cluster').toLowerCase()
   };
 
-  function loadUserInfo(){
-    User.get($routeParams.id).then(function(data) {
-      $scope.user = User.makeUser(data).Users;
-      $scope.isCurrentUser = $scope.user.user_name === Auth.getCurrentUser();
-      $scope.editingGroupsList = angular.copy($scope.user.groups);
-    });
-  }
-
-  loadUserInfo();
-  $scope.user;
+  $scope.user = null;
   $scope.isCurrentUser = true;
   $scope.dataLoaded = false;
-
   $scope.isGroupEditing = false;
-  $scope.enableGroupEditing = function() {
+
+  $scope.enableGroupEditing = function () {
     $scope.isGroupEditing = true;
     $scope.editingGroupsList = angular.copy($scope.user.groups);
   };
 
-  $scope.$watch(function() {
+  $scope.$watch(function () {
     return $scope.editingGroupsList;
-  }, function(newValue) {
-    if(newValue){
-      if( !angular.equals(newValue, $scope.user.groups) ){
+  }, function (newValue) {
+    if (newValue) {
+      if (!angular.equals(newValue, $scope.user.groups)) {
         $scope.updateGroups();
       }
     }
   }, true);
 
-  $scope.updateGroups = function() {
-    var groups = $scope.editingGroupsList.toString().split(',').filter(function(item) {return item.trim();}).map(function(item) {return item.trim()});
+  $scope.showHelpPage = function() {
+    Cluster.getRolesWithAuthorizations().then(function(roles) {
+      RoleDetailsModal.show(roles);
+    });
+  };
+
+  $scope.updateRole = function () {
+    var clusterName = $rootScope.cluster.Clusters.cluster_name;
+    if ($scope.originalRole.permission_name !== $scope.currentRole.permission_name) {
+      if ($scope.currentRole.permission_name === 'NONE') {
+        deleteUserRoles(clusterName, $scope.user).finally(loadUserInfo);
+      } else {
+        if ($scope.user.roles.length) {
+          deleteUserRoles(clusterName, $scope.user, true).finally(function() {
+            addUserRoles(clusterName, $scope.currentRole, $scope.user).finally(loadUserInfo);
+          });
+        } else {
+          addUserRoles(clusterName, $scope.currentRole, $scope.user).finally(loadUserInfo);
+        }
+      }
+    }
+  };
+
+  $scope.updateGroups = function () {
+    var groups = $scope.editingGroupsList.filter(function (item) {
+      return item.trim();
+    }).map(function (item) {
+      return item.trim();
+    });
     var diff = getDifference($scope.user.groups, groups);
     var promises = [];
     // Remove user from groups
-    angular.forEach(diff.del, function(groupName) {
-      promises.push(Group.removeMemberFromGroup(groupName, $scope.user.user_name).catch(function(data) {
+    angular.forEach(diff.del, function (groupName) {
+      promises.push(Group.removeMemberFromGroup(groupName, $scope.user.user_name).catch(function (data) {
         Alert.error($t('users.alerts.removeUserError'), data.data.message);
       }));
     });
     // Add user to groups
-    angular.forEach(diff.add, function(groupName) {
-      promises.push(Group.addMemberToGroup(groupName, $scope.user.user_name).catch(function(data) {
+    angular.forEach(diff.add, function (groupName) {
+      promises.push(Group.addMemberToGroup(groupName, $scope.user.user_name).catch(function (data) {
         Alert.error($t('users.alerts.cannotAddUser'), data.data.message);
       }));
     });
-    $q.all(promises).then(function() {
+    $q.all(promises).then(function () {
       loadUserInfo();
     });
     $scope.isGroupEditing = false;
   };
 
-  $scope.getUserMembership = function(userType) {
-    if(userType) {
-	return $t(UserConstants.TYPES[userType].LABEL_KEY) + " " + $t('users.groupMembership');
+  $scope.getUserMembership = function (userType) {
+    if (userType) {
+      return $t(UserConstants.TYPES[userType].LABEL_KEY) + " " + $t('users.groupMembership');
     }
   };
 
-  $scope.cancelUpdate = function() {
+  $scope.cancelUpdate = function () {
     $scope.isGroupEditing = false;
     $scope.editingGroupsList = '';
   };
 
-  $scope.openChangePwdDialog = function() {
+  $scope.openChangePwdDialog = function () {
     var modalInstance = $modal.open({
       templateUrl: 'views/userManagement/modals/changePassword.html',
       resolve: {
-        userName: function() {
+        userName: function () {
           return $scope.user.user_name;
         }
       },
-      controller: ['$scope', 'userName', function($scope, userName) {
+      controller: ['$scope', 'userName', function ($scope, userName) {
         $scope.passwordData = {
           password: '',
           currentUserPassword: ''
@@ -110,55 +134,54 @@ angular.module('ambariAdminConsole')
         $scope.form = {};
         $scope.userName = userName;
 
-        $scope.ok = function() {
+        $scope.ok = function () {
           $scope.form.passwordChangeForm.submitted = true;
-          if($scope.form.passwordChangeForm.$valid){
-
+          if ($scope.form.passwordChangeForm.$valid) {
             modalInstance.close({
-              password: $scope.passwordData.password, 
+              password: $scope.passwordData.password,
               currentUserPassword: $scope.passwordData.currentUserPassword
             });
           }
         };
-        $scope.cancel = function() {
+        $scope.cancel = function () {
           modalInstance.dismiss('cancel');
         };
       }]
     });
 
-    modalInstance.result.then(function(data) {
-      User.setPassword($scope.user, data.password, data.currentUserPassword).then(function() {
+    modalInstance.result.then(function (data) {
+      User.setPassword($scope.user, data.password, data.currentUserPassword).then(function () {
         Alert.success($t('users.alerts.passwordChanged'));
-      }).catch(function(data) {
+      }).catch(function (data) {
         Alert.error($t('users.alerts.cannotChangePassword'), data.data.message);
       });
-    }); 
+    });
   };
 
-  $scope.toggleUserActive = function() {
-    if(!$scope.isCurrentUser){
-      var newStatusKey = $scope.user.active ? 'inactive' : 'active',
-        newStatus = $t('users.' + newStatusKey).toLowerCase();
+  $scope.toggleUserActive = function () {
+    if (!$scope.isCurrentUser) {
+      var newStatusKey = $scope.user.active ? 'inactive' : 'active';
       ConfirmationModal.show(
         $t('users.changeStatusConfirmation.title'),
         $t('users.changeStatusConfirmation.message', {
           userName: $scope.user.user_name,
-          status: newStatus
+          status: $t('users.' + newStatusKey).toLowerCase()
         })
-      ).then(function() {
+      ).then(function () {
         User.setActive($scope.user.user_name, $scope.user.active)
-          .catch(function(data) {
-            Alert.error($t('common.alerts.cannotUpdateStatus'), data.data.message);
-            $scope.user.active = !$scope.user.active;
-          });
+        .catch(function (data) {
+          Alert.error($t('common.alerts.cannotUpdateStatus'), data.data.message);
+          $scope.user.active = !$scope.user.active;
+        });
       })
-      .catch(function() {
+      .catch(function () {
         $scope.user.active = !$scope.user.active;
       });
     }
-  };    
-  $scope.toggleUserAdmin = function() {
-    if(!$scope.isCurrentUser){
+  };
+
+  $scope.toggleUserAdmin = function () {
+    if (!$scope.isCurrentUser) {
       var action = $scope.user.admin ?
         $t('users.changePrivilegeConfirmation.revoke') : $t('users.changePrivilegeConfirmation.grant');
       ConfirmationModal.show(
@@ -167,36 +190,35 @@ angular.module('ambariAdminConsole')
           action: action,
           userName: $scope.user.user_name
         })
-      ).then(function() {
+      ).then(function () {
         User.setAdmin($scope.user.user_name, $scope.user.admin)
-        .then(function() {
-          loadPrivileges();
+        .then(function () {
+          loadUserInfo();
         })
         .catch(function (data) {
           Alert.error($t('common.alerts.cannotUpdateAdminStatus'), data.data.message);
           $scope.user.admin = !$scope.user.admin;
         });
       })
-      .catch(function() {
+      .catch(function () {
         $scope.user.admin = !$scope.user.admin;
       });
-
     }
   };
 
-  $scope.removePrivilege = function(name, privilege) {
+  $scope.removeViewPrivilege = function (name, privilege) {
     var privilegeObject = {
-        id: privilege.privilege_id,
-        view_name: privilege.view_name,
-        version: privilege.version,
-        instance_name: name
+      id: privilege.privilege_id,
+      view_name: privilege.view_name,
+      version: privilege.version,
+      instance_name: name
     };
-    View.deletePrivilege(privilegeObject).then(function() {
-      loadPrivileges();
+    View.deletePrivilege(privilegeObject).then(function () {
+      loadUserInfo();
     });
   };
 
-  $scope.deleteUser = function() {
+  $scope.deleteUser = function () {
     ConfirmationModal.show(
       $t('common.delete', {
         term: $t('common.user')
@@ -205,15 +227,15 @@ angular.module('ambariAdminConsole')
         instanceType: $t('common.user').toLowerCase(),
         instanceName: '"' + $scope.user.user_name + '"'
       })
-    ).then(function() {
+    ).then(function () {
       Cluster.getPrivilegesForResource({
-        nameFilter : $scope.user.user_name,
-        typeFilter : {value: 'USER'}
-      }).then(function(data) {
+        nameFilter: $scope.user.user_name,
+        typeFilter: {value: 'USER'}
+      }).then(function (data) {
         var clusterPrivilegesIds = [];
         var viewsPrivileges = [];
         if (data.items && data.items.length) {
-          angular.forEach(data.items[0].privileges, function(privilege) {
+          angular.forEach(data.items[0].privileges, function (privilege) {
             if (privilege.PrivilegeInfo.principal_type === 'USER') {
               if (privilege.PrivilegeInfo.type === 'VIEW') {
                 viewsPrivileges.push({
@@ -228,15 +250,12 @@ angular.module('ambariAdminConsole')
             }
           });
         }
-        User.delete($scope.user.user_name).then(function() {
-          $location.path('/userManagement');
+        User.delete($scope.user.user_name).then(function () {
+          $location.path('/userManagement?tab=users');
           if (clusterPrivilegesIds.length) {
-            Cluster.getAllClusters().then(function (clusters) {
-              var clusterName = clusters[0].Clusters.cluster_name;
-              Cluster.deleteMultiplePrivileges(clusterName, clusterPrivilegesIds);
-            });
+            Cluster.deleteMultiplePrivileges($rootScope.cluster.Clusters.cluster_name, clusterPrivilegesIds);
           }
-          angular.forEach(viewsPrivileges, function(privilege) {
+          angular.forEach(viewsPrivileges, function (privilege) {
             View.deletePrivilege(privilege);
           });
         });
@@ -244,47 +263,102 @@ angular.module('ambariAdminConsole')
     });
   };
 
-  // Load privileges
-  function loadPrivileges(){
-    User.getPrivileges($routeParams.id).then(function(data) {
-      var privileges = {
-        clusters: {},
-        views: {}
-      };
-      angular.forEach(data.data.items, function(privilege) {
-        privilege = privilege.PrivilegeInfo;
-        if(privilege.type === 'CLUSTER'){
-          // This is cluster
-          if (privileges.clusters[privilege.cluster_name]) {
-            var preIndex = Cluster.orderedRoles.indexOf(privileges.clusters[privilege.cluster_name].permission_name);
-            var curIndex = Cluster.orderedRoles.indexOf(privilege.permission_name);
-            // replace when cur is a more powerful role
-            if (curIndex < preIndex) {
-              privileges.clusters[privilege.cluster_name] = privilege;
-            }
-          } else {
+  function deleteUserRoles(clusterName, user, ignoreAlert) {
+    return Cluster.deleteMultiplePrivileges(
+      clusterName,
+      user.roles.map(function(item) {
+        return item.privilege_id;
+      })
+    ).then(function () {
+      if (!ignoreAlert) {
+        Alert.success($t('users.alerts.roleChangedToNone', {
+          user_name: user.user_name
+        }));
+      }
+    }).catch(function (data) {
+      Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message);
+    });
+  }
+
+  function addUserRoles(clusterName, newRole, user) {
+    return Cluster.createPrivileges(
+      {
+        clusterId: clusterName
+      },
+      [{
+        PrivilegeInfo: {
+          permission_name: newRole.permission_name,
+          principal_name: user.user_name,
+          principal_type: 'USER'
+        }
+      }]
+    ).then(function () {
+      Alert.success($t('users.alerts.roleChanged', {
+        name: user.user_name,
+        role: newRole.permission_label
+      }));
+    }).catch(function (data) {
+      Alert.error($t('common.alerts.cannotSavePermissions'), data.data.message);
+    });
+  }
+
+  function loadUserInfo() {
+    return User.getWithRoles($routeParams.id).then(function (data) {
+      $scope.user = User.makeUser(data.data).Users;
+      $scope.isCurrentUser = $scope.user.user_name === Auth.getCurrentUser();
+      $scope.editingGroupsList = angular.copy($scope.user.groups);
+      parsePrivileges(data.data.privileges);
+      var clusterRole = $scope.user.roles[0];
+      $scope.currentRole = clusterRole || nonRole;
+      $scope.originalRole = clusterRole || nonRole;
+      $scope.dataLoaded = true;
+    });
+  }
+
+  function parsePrivileges(rawPrivileges) {
+    var privileges = {
+      clusters: {},
+      views: {}
+    };
+    angular.forEach(rawPrivileges, function (privilege) {
+      privilege = privilege.PrivilegeInfo;
+      if (privilege.type === 'CLUSTER') {
+        // This is cluster
+        if (privileges.clusters[privilege.cluster_name]) {
+          var preIndex = Cluster.orderedRoles.indexOf(privileges.clusters[privilege.cluster_name].permission_name);
+          var curIndex = Cluster.orderedRoles.indexOf(privilege.permission_name);
+          // set more powerful role
+          if (curIndex < preIndex) {
             privileges.clusters[privilege.cluster_name] = privilege;
           }
-        } else if ( privilege.type === 'VIEW'){
-          privileges.views[privilege.instance_name] = privileges.views[privilege.instance_name] || { privileges:[]};
-          privileges.views[privilege.instance_name].version = privilege.version;
-          privileges.views[privilege.instance_name].view_name = privilege.view_name;
-          privileges.views[privilege.instance_name].privilege_id = privilege.privilege_id;
-          if (privileges.views[privilege.instance_name].privileges.indexOf(privilege.permission_label) == -1) {
-            privileges.views[privilege.instance_name].privileges.push(privilege.permission_label);
-          }
+        } else {
+          privileges.clusters[privilege.cluster_name] = privilege;
         }
-      });
+      } else if (privilege.type === 'VIEW') {
+        privileges.views[privilege.instance_name] = privileges.views[privilege.instance_name] || {
+          privileges: [],
+          version: privilege.version,
+          view_name: privilege.view_name,
+          privilege_id: privilege.privilege_id
+        };
+        if (privileges.views[privilege.instance_name].privileges.indexOf(privilege.permission_label) === -1) {
+          privileges.views[privilege.instance_name].privileges.push(privilege.permission_label);
+        }
+      }
+    });
 
-      $scope.privileges = data.data.items.length ? privileges : null;
-      $scope.noClusterPriv = $.isEmptyObject(privileges.clusters);
-      $scope.noViewPriv = $.isEmptyObject(privileges.views);
-      $scope.hidePrivileges = $scope.noClusterPriv && $scope.noViewPriv;
-      $scope.dataLoaded = true;
+    $scope.privilegesView = privileges;
+    $scope.noClusterPriv = $.isEmptyObject(privileges.clusters);
+    $scope.noViewPriv = $.isEmptyObject(privileges.views);
+    $scope.hidePrivileges = $scope.noClusterPriv && $scope.noViewPriv;
+  }
 
-    }).catch(function(data) {
-      Alert.error($t('common.alerts.cannotLoadPrivileges'), data.data.message);
+  function loadRoles() {
+    return Cluster.getRoleOptions().then(function (data) {
+      $scope.roleOptions = data;
     });
   }
-  loadPrivileges();
+
+  loadRoles().finally(loadUserInfo);
+
 }]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserManagementCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserManagementCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserManagementCtrl.js
index e9ec6ab..cb25606 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserManagementCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UserManagementCtrl.js
@@ -18,6 +18,6 @@
 'use strict';
 
 angular.module('ambariAdminConsole')
-.controller('UserManagementCtrl', ['$scope', function($scope) {
-  $scope.activeTab = 'USERS';
+.controller('UserManagementCtrl', ['$scope', '$routeParams', function($scope, $routeParams) {
+  $scope.activeTab = $routeParams.tab === 'groups' ? 'GROUPS' : 'USERS';
 }]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UsersListCtrl.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UsersListCtrl.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UsersListCtrl.js
index abe1780..00bf9c3 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UsersListCtrl.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/controllers/userManagement/UsersListCtrl.js
@@ -44,14 +44,7 @@ function($scope, User, $modal, $rootScope, UserConstants, $translate, Cluster, V
   };
   $scope.isNotEmptyFilter = true;
 
-  $scope.pageChanged = function() {
-    $scope.loadUsers();
-  };
-  $scope.usersPerPageChanges = function() {
-    $scope.resetPagination();
-  };
-
-  $scope.loadUsers = function(){
+  function loadUsers() {
     $scope.isLoading = true;
     User.list({
       currentPage: $scope.currentPage,
@@ -59,29 +52,37 @@ function($scope, User, $modal, $rootScope, UserConstants, $translate, Cluster, V
       searchString: $scope.filters.name,
       user_type: $scope.filters.type.value,
       active: $scope.filters.status.value
-    }).then(function(data) {
-      $scope.isLoading = false;
+    }).then(function (data) {
       $scope.totalUsers = data.data.itemTotal;
       $scope.users = data.data.items.map(User.makeUser);
       $scope.tableInfo.showed = data.data.items.length;
       $scope.tableInfo.total = data.data.itemTotal;
+    }).finally(function () {
+      $scope.isLoading = false;
     });
+  }
+
+  $scope.pageChanged = function () {
+    loadUsers();
+  };
+  $scope.usersPerPageChanges = function () {
+    $scope.resetPagination();
   };
 
-  $scope.resetPagination = function() {
+  $scope.resetPagination = function () {
     $scope.currentPage = 1;
-    $scope.loadUsers();
+    loadUsers();
   };
 
   $scope.activeFilterOptions = [
     {label: $t('common.all'), value: '*'},
     {label: $t('users.active'), value: true},
-    {label: $t('users.inactive'), value:false}
+    {label: $t('users.inactive'), value: false}
   ];
   $scope.filters.status = $scope.activeFilterOptions[0];
 
-  $scope.typeFilterOptions = [{ label: $t('common.all'), value: '*'}]
-    .concat(Object.keys(UserConstants.TYPES).map(function(key) {
+  $scope.typeFilterOptions = [{label: $t('common.all'), value: '*'}]
+    .concat(Object.keys(UserConstants.TYPES).map(function (key) {
       return {
         label: $t(UserConstants.TYPES[key].LABEL_KEY),
         value: UserConstants.TYPES[key].VALUE
@@ -97,8 +98,6 @@ function($scope, User, $modal, $rootScope, UserConstants, $translate, Cluster, V
     $scope.resetPagination();
   };
 
-  $scope.loadUsers();
-
   $scope.$watch(
     function (scope) {
       return Boolean(scope.filters.name || (scope.filters.status && scope.filters.status.value !== '*')
@@ -109,12 +108,12 @@ function($scope, User, $modal, $rootScope, UserConstants, $translate, Cluster, V
     }
   );
 
-  $rootScope.$watch(function(scope) {
+  $rootScope.$watch(function (scope) {
     return scope.LDAPSynced;
-  }, function(LDAPSynced) {
-    if(LDAPSynced === true){
+  }, function (LDAPSynced) {
+    if (LDAPSynced === true) {
       $rootScope.LDAPSynced = false;
-      $scope.loadUsers();
+      loadUsers();
     }
   });
 
@@ -125,10 +124,10 @@ function($scope, User, $modal, $rootScope, UserConstants, $translate, Cluster, V
       backdrop: 'static'
     });
 
-    modalInstance.result.finally($scope.loadUsers);
+    modalInstance.result.finally(loadUsers);
   };
 
-  $scope.deleteUser = function(user) {
+  $scope.deleteUser = function (user) {
     ConfirmationModal.show(
       $t('common.delete', {
         term: $t('common.user')
@@ -137,15 +136,15 @@ function($scope, User, $modal, $rootScope, UserConstants, $translate, Cluster, V
         instanceType: $t('common.user').toLowerCase(),
         instanceName: '"' + user.user_name + '"'
       })
-    ).then(function() {
+    ).then(function () {
       Cluster.getPrivilegesForResource({
-        nameFilter : user.user_name,
-        typeFilter : {value: 'USER'}
-      }).then(function(data) {
+        nameFilter: user.user_name,
+        typeFilter: {value: 'USER'}
+      }).then(function (data) {
         var clusterPrivilegesIds = [];
         var viewsPrivileges = [];
         if (data.items && data.items.length) {
-          angular.forEach(data.items[0].privileges, function(privilege) {
+          angular.forEach(data.items[0].privileges, function (privilege) {
             if (privilege.PrivilegeInfo.principal_type === 'USER') {
               if (privilege.PrivilegeInfo.type === 'VIEW') {
                 viewsPrivileges.push({
@@ -160,19 +159,19 @@ function($scope, User, $modal, $rootScope, UserConstants, $translate, Cluster, V
             }
           });
         }
-        User.delete(user.user_name).then(function() {
+        User.delete(user.user_name).then(function () {
           if (clusterPrivilegesIds.length) {
-            Cluster.getAllClusters().then(function (clusters) {
-              var clusterName = clusters[0].Clusters.cluster_name;
-              Cluster.deleteMultiplePrivileges(clusterName, clusterPrivilegesIds);
-            });
+            Cluster.deleteMultiplePrivileges($rootScope.cluster.Clusters.cluster_name, clusterPrivilegesIds);
           }
-          angular.forEach(viewsPrivileges, function(privilege) {
+          angular.forEach(viewsPrivileges, function (privilege) {
             View.deletePrivilege(privilege);
           });
-          $scope.loadUsers();
+          loadUsers();
         });
       });
     });
   };
+
+  loadUsers();
+
 }]);

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
index de3968d..4a13e02 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/i18n.config.js
@@ -303,7 +303,7 @@ angular.module('ambariAdminConsole')
     'users.inactive': 'Inactive',
     'users.status': 'Status',
     'users.password': 'Password',
-    'users.role': 'Add roles for this user (Cluster Operator/Service Admin)',
+    'users.role': 'Add roles for this user',
     'users.confirmPassword': 'Confirm Password',
     'users.passwordConfirmation': 'Password —Āonfirmation',
     'users.isAmbariAdmin': 'Is this user an Ambari Admin?',
@@ -337,7 +337,7 @@ angular.module('ambariAdminConsole')
     'users.alerts.wrongPassword': 'Password must match!',
     'users.alerts.usernameRequired': 'Username Required',
     'users.alerts.cannotChange': 'Cannot Change {{term}}',
-    'users.alerts.userCreated': 'Created user <a href="#/users/{{encUserName}}">{{userName}}</a>',
+    'users.alerts.userCreated': 'Created user <a href="#/users/{{encUserName}}/edit">{{userName}}</a>',
     'users.alerts.userCreationError': 'User creation error',
     'users.alerts.removeUserError': 'Removing from group error',
     'users.alerts.cannotAddUser': 'Cannot add user to group',
@@ -373,8 +373,6 @@ angular.module('ambariAdminConsole')
     'versions.installOn': 'Install on...',
 
     'versions.register.title': 'Register Version',
-    'versions.add.title': 'Add Version',
-
     'versions.register.error.header': 'Unable to Register',
     'versions.register.error.body': 'You are attempting to register a version with a Base URL that is already in use with an existing registered version. You *must* review your Base URLs and confirm they are unique for the version you are trying to register.',
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/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
index 0f9b582..30ef91a 100644
--- 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
@@ -18,7 +18,11 @@
 'use strict';
 
 angular.module('ambariAdminConsole')
-.factory('Cluster', ['$http', '$q', 'Settings', function($http, $q, Settings) {
+.factory('Cluster', ['$http', '$q', 'Settings', '$translate', function($http, $q, Settings, $translate) {
+  var $t = $translate.instant;
+  var permissions = null;
+  var rolesWithAuthorizations = null;
+
   return {
     repoStatusCache : {},
 
@@ -34,6 +38,13 @@ angular.module('ambariAdminConsole')
 
     ineditableRoles : ['VIEW.USER', 'AMBARI.ADMINISTRATOR'],
 
+    sortRoles: function(roles) {
+      var orderedRoles = ['AMBARI.ADMINISTRATOR'].concat(this.orderedRoles);
+      return roles.sort(function(a, b) {
+        return orderedRoles.indexOf(a.permission_name) - orderedRoles.indexOf(b.permission_name);
+      });
+    },
+
     getAllClusters: function() {
       var deferred = $q.defer();
       $http.get(Settings.baseUrl + '/clusters?fields=Clusters/cluster_id', {mock: 'cluster/clusters.json'})
@@ -120,22 +131,48 @@ angular.module('ambariAdminConsole')
 
       return deferred.promise;
     },
+    getRoleOptions: function () {
+      var roleOptions = [];
+      var deferred = $q.defer();
+      var localDeferred = $q.defer();
+      var promise = permissions ? localDeferred.promise : this.getPermissions();
+
+      localDeferred.resolve(permissions);
+      promise.then(function(data) {
+        permissions = data;
+        roleOptions = data.map(function(item) {
+          return item.PermissionInfo;
+        });
+        roleOptions.unshift({
+          permission_name: 'NONE',
+          permission_label: $t('users.roles.none')
+        });
+      }).finally(function() {
+        deferred.resolve(roleOptions);
+      });
+      return deferred.promise;
+    },
     getRolesWithAuthorizations: function() {
-      var self = this;
       var deferred = $q.defer();
-      $http({
-        method: 'GET',
-        url: Settings.baseUrl + '/permissions?PermissionInfo/resource_name.in(CLUSTER,AMBARI)',
-        mock: 'permission/permissions.json',
-        params: {
-          fields: 'PermissionInfo/*,authorizations/AuthorizationInfo/*'
-        }
-      })
-        .success(function(data) {
-          deferred.resolve(data.items);
+      if (rolesWithAuthorizations) {
+        deferred.resolve(rolesWithAuthorizations);
+      } else {
+        $http({
+          method: 'GET',
+          url: Settings.baseUrl + '/permissions?PermissionInfo/resource_name.in(CLUSTER,AMBARI)',
+          mock: 'permission/permissions.json',
+          params: {
+            fields: 'PermissionInfo/*,authorizations/AuthorizationInfo/*'
+          }
         })
-        .catch(function(data) {
-          deferred.reject(data); });
+          .success(function (data) {
+            rolesWithAuthorizations = data.items;
+            deferred.resolve(data.items);
+          })
+          .catch(function (data) {
+            deferred.reject(data);
+          });
+      }
 
       return deferred.promise;
     },
@@ -159,31 +196,6 @@ angular.module('ambariAdminConsole')
 
       return deferred.promise;
     },
-    getPrivilegesWithFilters: function(params) {
-      var deferred = $q.defer();
-      var isUser = params.typeFilter.value == 'USER';
-      var endpoint = isUser? '/users' : '/groups';
-      var nameURL = isUser? '&Users/user_name.matches(.*' : '&Groups/group_name.matches(.*';
-      var nameFilter = params.nameFilter? nameURL + params.nameFilter + '.*)' : '';
-      var roleFilter = params.roleFilter.value? '&privileges/PrivilegeInfo/permission_name.matches(.*' + params.roleFilter.value + '.*)' : '';
-      $http({
-        method: 'GET',
-        url: Settings.baseUrl + endpoint + '?'
-        + 'fields=privileges/PrivilegeInfo/*'
-        + nameFilter
-        + roleFilter
-        + '&from=' + (params.currentPage - 1) * params.usersPerPage
-        + '&page_size=' + params.usersPerPage
-      })
-      .success(function(data) {
-        deferred.resolve(data);
-      })
-      .catch(function(data) {
-        deferred.reject(data);
-      });
-
-      return deferred.promise;
-    },
     getPrivilegesForResource: function(params) {
       var deferred = $q.defer();
       var isUser = (params.typeFilter.value == 'USER');

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/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
index f52a7e5..0509e11 100644
--- 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
@@ -18,49 +18,29 @@
 'use strict';
 
 angular.module('ambariAdminConsole')
-.factory('Group', ['$http', '$q', 'Settings', 'GroupConstants', '$translate', function($http, $q, Settings, GroupConstants, $translate) {
+.factory('Group', ['$http', '$q', 'Settings', '$translate', 'Cluster', function($http, $q, Settings, $translate, Cluster) {
   var $t = $translate.instant;
-  function Group(item){
-    if(typeof item === 'string'){
-      this.group_name = item;
-    } else if(typeof item === 'object'){
-      angular.extend(this, item.Groups);
-      this.getMembers();
+  var types = {
+    LOCAL: {
+      VALUE: 'LOCAL',
+      LABEL_KEY: 'common.local'
+    },
+    PAM: {
+      VALUE: 'PAM',
+      LABEL_KEY: 'common.pam'
+    },
+    LDAP: {
+      VALUE: 'LDAP',
+      LABEL_KEY: 'common.ldap'
     }
-  }
+  };
 
-  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);
-      });
+  function Group(item) {
+    if (typeof item === 'string') {
+      this.group_name = item;
+    } else if (typeof item === 'object') {
+      angular.extend(this, item.Groups);
     }
-
-    return deferred.promise;
-  }
-
-  Group.prototype.getGroupType = function() {
-    var deferred = $q.defer();
-    var self = this;
-    $http({
-      method: 'GET',
-      url: Settings.baseUrl + '/groups/'+this.group_name
-    }).
-    success(function(data) {
-      self.group_type = data.Groups.group_type;
-      deferred.resolve(self.group_type);
-    });
-
-    return deferred.promise;
   }
 
   Group.prototype.save = function() {
@@ -86,28 +66,6 @@ angular.module('ambariAdminConsole')
     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();
@@ -132,27 +90,6 @@ angular.module('ambariAdminConsole')
       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' + '/'+ encodeURIComponent(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) {
@@ -174,14 +111,8 @@ angular.module('ambariAdminConsole')
       + (params.group_type === '*' ? '' : '&Groups/group_type=' + params.group_type)
     )
     .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);
+      data.items.itemTotal = data.itemTotal;
+      deferred.resolve(data.items);
     })
     .error(function(data) {
       deferred.reject(data);
@@ -204,6 +135,23 @@ angular.module('ambariAdminConsole')
     });
   };
 
+  Group.get = function (group_name) {
+    var deferred = $q.defer();
+    $http({
+      method: 'GET',
+      url: Settings.baseUrl + '/groups/' + group_name +
+      '?fields=Groups,privileges/PrivilegeInfo/*,members/MemberInfo'
+    }).success(function (data) {
+      deferred.resolve(Group.makeGroup(data));
+    });
+
+    return deferred.promise;
+  };
+
+  Group.getTypes = function () {
+    return types;
+  };
+
   /**
      * Generate group info to display by response data from API.
      * Generally this is a single point to manage all required and useful data
@@ -212,9 +160,19 @@ angular.module('ambariAdminConsole')
      * @param {Object} group - object from API response
      * @returns {Object}
      */
-   Group.makeGroup = function(group) {
-      group.groupTypeName = $t(GroupConstants.TYPES[group.group_type].LABEL_KEY);
-      return group;
+  Group.makeGroup = function(data) {
+    var group = new Group(data.Groups.group_name);
+    group.groupTypeName = $t(types[data.Groups.group_type].LABEL_KEY);
+    group.group_type = data.Groups.group_type;
+    group.ldap_group = data.Groups.ldap_group;
+    group.privileges = data.privileges;
+    group.members = data.members;
+    group.roles = Cluster.sortRoles(data.privileges.filter(function(item) {
+      return item.PrivilegeInfo.type === 'CLUSTER' || item.PrivilegeInfo.type === 'AMBARI';
+    }).map(function(item) {
+      return item.PrivilegeInfo;
+    }));
+    return group;
   };
 
   return Group;

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/GroupConstants.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/GroupConstants.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/GroupConstants.js
deleted file mode 100644
index 42e8d73..0000000
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/GroupConstants.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-'use strict';
-
-angular.module('ambariAdminConsole').constant('GroupConstants', {
-  /**
-   * Available group_types 'values' and 'labels' map.
-   */
-  TYPES: {
-    LOCAL: {
-      VALUE: 'LOCAL',
-      LABEL_KEY: 'common.local'
-    },
-    PAM: {
-      VALUE: 'PAM',
-      LABEL_KEY: 'common.pam'
-    },
-    LDAP: {
-      VALUE: 'LDAP',
-      LABEL_KEY: 'common.ldap'
-    }
-  }
-});

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RoleDetailsModal.js
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RoleDetailsModal.js b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RoleDetailsModal.js
index 06019c2..7b01116 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RoleDetailsModal.js
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/scripts/services/RoleDetailsModal.js
@@ -22,11 +22,10 @@ angular.module('ambariAdminConsole')
   return {
     show: function(roles) {
       roles = roles.map(function(role) {
-        role.authorizations = role.authorizations.map(function(authorization) {
+        var r = role.PermissionInfo;
+        r.authorizations = role.authorizations.map(function(authorization) {
           return authorization.AuthorizationInfo;
         });
-        var r = role.PermissionInfo;
-        r.authorizations = role.authorizations;
         return r;
       });
       var modalInstance = $modal.open({

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/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
index 47015d1..7932d9b 100644
--- 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
@@ -18,7 +18,7 @@
 'use strict';
 
 angular.module('ambariAdminConsole')
-  .factory('User', ['Restangular', '$http', 'Settings', 'UserConstants', '$translate', function(Restangular, $http, Settings, UserConstants, $translate) {
+.factory('User', ['Restangular', '$http', 'Settings', 'UserConstants', '$translate', 'Cluster', function(Restangular, $http, Settings, UserConstants, $translate, Cluster) {
   Restangular.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
     var extractedData;
     if(operation === 'getList'){
@@ -31,14 +31,13 @@ angular.module('ambariAdminConsole')
     return extractedData;
   });
   var $t = $translate.instant;
-  var Users = Restangular.all('users');
 
   return {
     list: function(params) {
       return $http.get(
         Settings.baseUrl + '/users/?'
         + 'Users/user_name.matches(.*'+params.searchString+'.*)'
-        + '&fields=*'
+        + '&fields=privileges/PrivilegeInfo/*,Users'
         + '&from=' + (params.currentPage-1)*params.usersPerPage
         + '&page_size=' + params.usersPerPage
         + (params.user_type === '*' ? '' : '&Users/user_type=' + params.user_type)
@@ -53,6 +52,12 @@ angular.module('ambariAdminConsole')
         + '&from=0&page_size=20'
       );
     },
+    getWithRoles: function(userId) {
+      return $http.get(
+        Settings.baseUrl + '/users/' + userId
+        + '?fields=privileges/PrivilegeInfo,Users'
+      );
+    },
     get: function(userId) {
       return Restangular.one('users', userId).get();
     },
@@ -97,7 +102,11 @@ angular.module('ambariAdminConsole')
       user.Users.encodedName = encodeURIComponent(user.Users.user_name);
       user.Users.userTypeName = $t(UserConstants.TYPES[user.Users.user_type].LABEL_KEY);
       user.Users.ldapUser = user.Users.user_type === UserConstants.TYPES.LDAP.VALUE;
-      user.Users.role = user.privileges.length ? user.privileges[0].PrivilegeInfo.privilege_id : null;
+      user.Users.roles = Cluster.sortRoles(user.privileges.filter(function(item) {
+        return item.PrivilegeInfo.type === 'CLUSTER' || item.PrivilegeInfo.type === 'AMBARI';
+      }).map(function(item) {
+        return item.PrivilegeInfo;
+      }));
 
       return user;
     }

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/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 91b2fb1..b4aa558 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
@@ -312,11 +312,6 @@ a.gotoinstance{
   font-size: 16px;
 }
 
-.user-edit-panel .ats-switch span.switch-right , .create-user-form .ats-switch span.switch-right, .enable-ldap .ats-switch span.switch-right {
-  background-color: #da4f49;
-  color: white;
-}
-
 .create-view-form, .register-version-form, .edit-version-form {
   padding-bottom: 50px;
 }

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/styles/user-management.css
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/styles/user-management.css b/ambari-admin/src/main/resources/ui/admin-web/app/styles/user-management.css
index 77c94ac..3c9756e 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/styles/user-management.css
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/styles/user-management.css
@@ -28,3 +28,16 @@
 #user-management .groups-pane {
   margin-top: -35px;
 }
+
+#group-edit .roles-label,
+#user-edit .roles-label {
+  line-height: 30px;
+}
+
+#create-user-form .roles-label i,
+#create-group-form .roles-label i,
+#group-edit .roles-label i,
+#user-edit .roles-label i {
+  margin-right: -10px;
+  cursor: pointer;
+}

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/list.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/list.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/list.html
index 8bb6632..59d8acb 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/list.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/remoteClusters/list.html
@@ -18,10 +18,7 @@
 
 <div class="users-pane">
   <div class="clearfix">
-    <ol class="breadcrumb pull-left">
-      <li class="active">{{'common.remoteClusters' | translate}}</li>
-    </ol>
-    <div class="pull-right top-margin-4">
+    <div class="pull-right">
       <a href="#/remoteClusters/create" class="btn btn-default">
         {{'views.registerRemoteCluster' | translate}}
       </a>

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/list.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/list.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/list.html
index a411640..cf5c516 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/list.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/stackVersions/list.html
@@ -18,12 +18,9 @@
 
 <div id="stack-versions">
   <div class="clearfix">
-    <ol class="breadcrumb pull-left">
-      <li class="active">{{'common.versions' | translate}}</li>
-    </ol>
-    <div class="pull-right top-margin-4">
+    <div class="pull-right">
       <a href="#/stackVersions/create" class="btn btn-default">
-        {{'versions.add.title' | translate}}
+        {{'versions.register.title' | translate}}
       </a>
     </div>
   </div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html
index 90a1907..5656417 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/groupEdit.html
@@ -16,84 +16,107 @@
 * limitations under the License.
 -->
 
-<div class="clearfix">
-  <div class="pull-right">
-    <div ng-switch="group.group_type != 'LOCAL'">
-      <button
-        ng-switch-when="true"
-        class="btn disabled deletegroup-btn"
-        tooltip="{{'common.cannotDelete' | translate: '{term: constants.group}'}}">
-        {{'common.delete' | translate: '{term: constants.group}'}}
-      </button>
-      <button ng-switch-when="false" class="btn btn-danger deletegroup-btn" ng-click="deleteGroup(group)">
-        {{'common.delete' | translate: '{term: constants.group}'}}
-      </button>
+<div id="group-edit">
+  <div class="clearfix">
+    <ol class="breadcrumb pull-left">
+      <li><a href="#/userManagement?tab=groups">{{'common.groups' | translate}}</a></li>
+      <li class="active">{{group.group_name}}</li>
+    </ol>
+    <div class="pull-right">
+      <div ng-switch="group.group_type != 'LOCAL'">
+        <button
+          ng-switch-when="true"
+          class="btn disabled deletegroup-btn"
+          tooltip="{{'common.cannotDelete' | translate: '{term: constants.group}'}}">
+          {{'common.delete' | translate: '{term: constants.group}'}}
+        </button>
+        <button ng-switch-when="false" class="btn btn-danger deletegroup-btn" ng-click="deleteGroup(group)">
+          {{'common.delete' | translate: '{term: constants.group}'}}
+        </button>
+      </div>
     </div>
   </div>
-</div>
-<form class="form-horizontal group-edit" role="form" novalidate name="form" >
-  <div class="form-group">
-    <label class="col-sm-2 control-label">{{'common.type' | translate}}</label>
-    <div class="col-sm-10">
-      <label class="control-label">{{group.groupTypeName | translate}}</label>
+
+  <form class="form-horizontal" role="form" novalidate name="form" >
+    <div class="form-group">
+      <label class="col-sm-2 control-label">{{'common.type' | translate}}</label>
+      <div class="col-sm-10">
+        <label class="control-label">{{group.groupTypeName | translate}}</label>
+      </div>
     </div>
-  </div>
-  <div class="form-group">
-    <label class="col-sm-2 control-label">{{group.groupTypeName | translate}} {{'groups.members' | translate}}</label>
-    <div class="col-sm-10">
-      <editable-list items-source="group.editingUsers" resource-type="User" editable="group.group_type == 'LOCAL'"></editable-list>
+    <div class="form-group">
+      <label class="col-sm-2 control-label">{{group.groupTypeName | translate}} {{'groups.members' | translate}}</label>
+      <div class="col-sm-10">
+        <editable-list items-source="group.editingUsers" resource-type="User" editable="group.group_type == 'LOCAL'"></editable-list>
+      </div>
     </div>
-  </div>
-
-  <div class="form-group">
+    <div class="form-group">
+      <label for="role" class="col-sm-2 roles-label">
+        {{'groups.role' | translate}}
+        <i class="fa fa-question-circle" aria-hidden="true" ng-click="showHelpPage()"></i>
+      </label>
+      <div class="col-sm-3">
+        <select class="form-control"
+                id="role"
+                name="role"
+                ng-change="updateRole()"
+                ng-options="item as item.permission_label for item in roleOptions track by item.permission_name"
+                ng-model="currentRole">
+        </select>
+      </div>
+    </div>
+    <div class="form-group">
       <label class="col-sm-2 control-label">{{'common.privileges' | translate}}</label>
       <div class="col-sm-10">
         <table class="table" ng-hide="hidePrivileges">
           <thead>
-            <tr>
-              <th>{{'common.cluster' | translate}}</th>
-              <th>{{'common.clusterRole' | translate}}</th>
-            </tr>
+          <tr>
+            <th>{{'common.cluster' | translate}}</th>
+            <th>{{'common.clusterRole' | translate}}</th>
+          </tr>
           </thead>
           <tbody>
-            <tr ng-repeat="(name, privilege) in privileges.clusters">
-              <td>
-                <span class="glyphicon glyphicon-cloud"></span> 
-                <a href="#/clusters/{{name}}/manageAccess">{{name}}</a>
-              </td>
-              <td>
-                <span tooltip="{{item}}" ng-repeat="item in privilege">{{item | translate}}{{$last ? '' : ', '}}</span>
-              </td>
-            </tr>
-            <tr>
-              <td ng-show="noClusterPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.cluster}'}}</td>
-            </tr>
+          <tr ng-repeat="(name, privilege) in privileges.clusters">
+            <td>
+              <span class="glyphicon glyphicon-cloud"></span>
+              <a href="#/clusters/{{name}}/manageAccess">{{name}}</a>
+            </td>
+            <td>
+              <span tooltip="{{item}}" ng-repeat="item in privilege">{{item | translate}}{{$last ? '' : ', '}}</span>
+            </td>
+          </tr>
+          <tr>
+            <td ng-show="noClusterPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.cluster}'}}</td>
+          </tr>
           </tbody>
           <thead class="view-permission-header">
-            <tr>
-              <th>{{'common.view' | translate}}</th>
-              <th>{{'common.viewPermissions' | translate}}</th>
-            </tr>
+          <tr>
+            <th>{{'common.view' | translate}}</th>
+            <th>{{'common.viewPermissions' | translate}}</th>
+          </tr>
           </thead>
           <tbody>
-            <tr ng-repeat="(name, privilege) in privileges.views">
-              <td>
-                <span class="glyphicon glyphicon-th"></span>
-                <a href="#/views/{{privilege.view_name}}/versions/{{privilege.version}}/instances/{{name}}/edit">{{name}}</a>
-              </td>
-              <td>
-                <span tooltip="{{item}}" ng-repeat="item in privilege.privileges">{{item | translate}}{{$last ? '' : ', '}}</span>
-              </td>
-              <td>
-                <i class="fa fa-trash-o" aria-hidden="true" ng-click="removePrivilege(name, privilege);"></i>
-              </td>
-            </tr>
-            <tr>
-              <td ng-show="noViewPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.view}'}}</td>
-            </tr>
+          <tr ng-repeat="(name, privilege) in privileges.views">
+            <td>
+              <span class="glyphicon glyphicon-th"></span>
+              <a href="#/views/{{privilege.view_name}}/versions/{{privilege.version}}/instances/{{name}}/edit">{{name}}</a>
+            </td>
+            <td>
+              <span tooltip="{{item}}" ng-repeat="item in privilege.privileges">{{item | translate}}{{$last ? '' : ', '}}</span>
+            </td>
+            <td>
+              <i class="fa fa-trash-o" aria-hidden="true" ng-click="removeViewPrivilege(name, privilege);"></i>
+            </td>
+          </tr>
+          <tr>
+            <td ng-show="noViewPriv">{{'common.alerts.noPrivileges' | translate: '{term: constants.view}'}}</td>
+          </tr>
           </tbody>
         </table>
-        <div class="alert alert-info hide-soft" ng-class="{'visible' : !privileges}">{{'common.alerts.noPrivilegesDescription' | translate: '{term: constants.group.toLowerCase()}'}}</div>
+        <div class="alert alert-info" ng-show="hidePrivileges">
+          {{'common.alerts.noPrivilegesDescription' | translate: '{term: constants.group.toLowerCase()}'}}
+        </div>
       </div>
     </div>
-</form>
+  </form>
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html
index 079eefb..8520fc2 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/main.html
@@ -19,10 +19,10 @@
 <div id="user-management">
   <ul class="nav nav-tabs">
     <li ng-class="{active: activeTab === 'USERS'}">
-      <a ng-click="activeTab = 'USERS'">{{'common.users' | translate}}</a>
+      <a href="#/userManagement?tab=users" >{{'common.users' | translate}}</a>
     </li>
     <li ng-class="{active: activeTab === 'GROUPS'}">
-      <a ng-click="activeTab = 'GROUPS'">{{'common.groups' | translate}}</a>
+      <a href="#/userManagement?tab=groups" >{{'common.groups' | translate}}</a>
     </li>
   </ul>
   <div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html
index e0c1144..e11b478 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/groupCreate.html
@@ -60,17 +60,17 @@
     <div class="row">
       <div class="form-group col-sm-6"
            ng-class="{ 'has-error': form.groupCreateForm.role.$error.required && form.groupCreateForm.submitted }">
-        <label for="role" class="nowrap">
+        <label for="role" class="nowrap roles-label">
           {{'groups.role' | translate}}
-          <i class="fa fa-question-circle" aria-hidden="true"></i>
+          <i class="fa fa-question-circle" aria-hidden="true" ng-click="showHelpPage()"></i>
         </label>
         <select
           class="form-control"
           id="role"
           name="role"
           ng-model="formData.role">
-          <option value="" disabled selected>{{'common.select' | translate}}</option>
-          <option ng-repeat="role in roleOptions" value="{{role.permission_id}}">{{role.permission_label}}</option>
+          <option value="" class="hide">{{'common.select' | translate}}</option>
+          <option ng-repeat="role in roleOptions" value="{{role.permission_name}}">{{role.permission_label}}</option>
         </select>
         <span class="help-block validation-block" ng-show='form.groupCreateForm.role.$error.required && form.groupCreateForm.submitted'>
           {{'common.alerts.fieldRequired' | translate}}

http://git-wip-us.apache.org/repos/asf/ambari/blob/32e25b80/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html
----------------------------------------------------------------------
diff --git a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html
index 0af26eb..2a71102 100644
--- a/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html
+++ b/ambari-admin/src/main/resources/ui/admin-web/app/views/userManagement/modals/userCreate.html
@@ -100,9 +100,9 @@
     <div class="row">
       <div class="form-group col-sm-6"
            ng-class="{ 'has-error': form.userCreateForm.role.$error.required && form.userCreateForm.submitted }">
-        <label for="role" class="nowrap">
-          {{'users.role' | translate}}<span>&nbsp;*</span>&nbsp;
-          <i class="fa fa-question-circle" aria-hidden="true"></i>
+        <label for="role" class="nowrap roles-label">
+          {{'users.role' | translate}}<span>&nbsp;*</span>
+          <i class="fa fa-question-circle" aria-hidden="true" ng-click="showHelpPage()"></i>
         </label>
         <select
           class="form-control"
@@ -110,8 +110,8 @@
           name="role"
           ng-model="formData.role"
           required>
-          <option value="" disabled selected>{{'common.select' | translate}}</option>
-          <option ng-repeat="role in roleOptions" value="{{role.permission_id}}">{{role.permission_label}}</option>
+          <option value="" class="hide">{{'common.select' | translate}}</option>
+          <option ng-repeat="role in roleOptions" value="{{role.permission_name}}">{{role.permission_label}}</option>
         </select>
         <span class="help-block validation-block" ng-show='form.userCreateForm.role.$error.required && form.userCreateForm.submitted'>
           {{'common.alerts.fieldRequired' | translate}}


Mime
View raw message