clean up of ui rbac code

This commit is contained in:
John Mitchell
2016-03-07 11:19:43 -05:00
parent 433ba95add
commit 56364617fd
13 changed files with 145 additions and 223 deletions

View File

@@ -1,15 +1,39 @@
@import "../../shared/branding/colors.default.less"; @import "../../shared/branding/colors.default.less";
/** @define AddPermissions */ /** @define AddPermissions */
.AddPermissions {
position: absolute; .AddPermissions-backDrop {
width: 100vw;
height: 100vh;
position: fixed;
top: 0; top: 0;
width: 100%; left: 0;
height: 100%; z-index: 1041;
opacity: 0;
transition: 0.5s opacity;
background: @login-backdrop;
opacity: 0.2;
}
.AddPermissions-dialog {
margin: 30px auto;
margin-top: 95px;
} }
.AddPermissions-content { .AddPermissions-content {
max-width: 750px !important; max-width: 750px;
margin-left: auto;
margin-right: auto;
border: 0;
box-shadow: none;
background-color: @login-bg;
border-radius: 4px;
opacity: 0;
transition: opacity 0.5s;
z-index: 1042;
position: relative;
opacity: 1;
transition: opacity 0.5s;
} }
.AddPermissions-header { .AddPermissions-header {
@@ -19,13 +43,20 @@
} }
.AddPermissions-body { .AddPermissions-body {
padding-top: 0px !important; padding-left: 20px;
padding-right: 20px;
padding-top: 0px;
max-height: 70vh; max-height: 70vh;
overflow: scroll; overflow: scroll;
} }
.AddPermissions-footer { .AddPermissions-footer {
padding-top: 20px !important; display: flex;
flex-wrap: wrap-reverse;
align-items: center;
padding: 20px;
padding-bottom: 0px;
padding-top: 20px;
} }
.AddPermissions-list .List-searchRow { .AddPermissions-list .List-searchRow {
@@ -64,7 +95,7 @@
font-size: 14px; font-size: 14px;
font-weight: bold; font-weight: bold;
border-radius: 50%; border-radius: 50%;
background-color: #ebebeb; background-color: @default-list-header-bg;
padding-left: 6px; padding-left: 6px;
padding-right: 1px; padding-right: 1px;
padding-bottom: 3px; padding-bottom: 3px;
@@ -75,7 +106,7 @@
margin-top: 20px; margin-top: 20px;
margin-bottom: 20px; margin-bottom: 20px;
width: 100%; width: 100%;
border-bottom: 1px solid #e1e1e1; border-bottom: 1px solid @default-second-border;
} }
.AddPermissions-roleRow { .AddPermissions-roleRow {
@@ -102,11 +133,11 @@
.AddPermissions-roleType { .AddPermissions-roleType {
border-radius: 5px; border-radius: 5px;
padding: 0px 6px; padding: 0px 6px;
border: 1px solid #e1e1e1; border: 1px solid @default-second-border;
font-size: 10px; font-size: 10px;
color: #848992; color: @default-interface-txt;
text-transform: uppercase; text-transform: uppercase;
background-color: #fff; background-color: @default-bg;
margin-left: 6px; margin-left: 6px;
} }
@@ -125,14 +156,14 @@
line-height: 11px; line-height: 11px;
padding-left: 5px; padding-left: 5px;
padding-right: 5px; padding-right: 5px;
color: #b7b7b7; color: @default-icon;
background-color: #fafafa; background-color: @default-tertiary-bg;
border: 0; border: 0;
} }
.AddPermissions-roleRemove:hover { .AddPermissions-roleRemove:hover {
background-color: #ff5850; background-color: @default-err;
color: #fff; color: @default-bg;
} }
.AddPermissions-selectHide { .AddPermissions-selectHide {

View File

@@ -6,55 +6,22 @@
/** /**
* @ngdoc function * @ngdoc function
* @name controllers.function:Authentication * @name controllers.function:Access
* @description * @description
* Controller for handling /#/login and /#/logout routes. * Controller for handling permissions adding
*
* Tower (app.js) verifies the user is authenticated and that the user session is not expired. If either condition is not true,
* the user is redirected to /#/login and the Authentication controller.
*
* Methods for checking the session state are found in [js/shared/AuthService.js](/static/docs/api/shared.function:AuthService), which is referenced here as Authorization.
*
* #Login Modal Dialog
*
* The modal dialog prompting for username and password is found in templates/ui/index.html.
*```
* <!-- login modal -->
* <div id="login-modal" class="modal fade">
* <div class="modal-dialog">
* <div class="modal-content" id="login-modal-content">
* </div><!-- modal-content -->
* </div><!-- modal-dialog -->
* </div><!-- modal -->
*```
* HTML for the login form is generated, compiled and injected into <div id="login-modal-content"></div> by the controller. This is done to associate the form with the controller's scope. Because
* <div id="login-modal"></div> is outside of the ng-view container, it gets associated with $rootScope by default. In the controller we create a new scope using $rootScope.$new() and associate
* that with the login form. Doing this each time the controller is instantiated insures the form is clean and not pre-populated with a prior user's username and password.
*
* Just before the release of 2.0 a bug was discovered where clicking logout and then immediately clicking login without providing a username and password would successfully log
* the user back into Tower. Implementing the above approach fixed this, forcing a new username/password to be entered each time the login dialog appears.
*
* #Login Workflow
*
* When the the login button is clicked, the following occurs:
*
* - Call Authorization.retrieveToken(username, password) - sends a POST request to /api/v1/authtoken to get a new token value.
* - Call Authorization.setToken(token, expires) to store the token and exipration time in a session cookie.
* - Start the expiration timer by calling the init() method of [js/shared/Timer.js](/static/docs/api/shared.function:Timer)
* - Get user informaton by calling Authorization.getUser() - sends a GET request to /api/v1/me
* - Store user information in the session cookie by calling Authorization.setUser().
* - Get the Tower license by calling Authorization.getLicense() - sends a GET request to /api/vi/config
* - Stores the license object in local storage by calling Authorization.setLicense(). This adds the Tower version and a tested flag to the license object. The tested flag is initially set to false.
*
* Note that there is a session timer kept on the server side as well as the client side. Each time an API request is made, Tower (in app.js) calls
* Timer.isExpired(). This verifies the UI does not think the session is expired, and if not, moves the expiration time into the future. The number of
* seconds between API calls before a session is considered expired is set in config.js as session_timeout.
*
* @Usage
* This is usage information.
*/ */
export default ['$rootScope', '$scope', 'GetBasePath', 'Rest', '$q', function (rootScope, scope, GetBasePath, Rest, $q) { export default ['$rootScope', '$scope', 'GetBasePath', 'Rest', '$q', function (rootScope, scope, GetBasePath, Rest, $q) {
var manuallyUpdateChecklists = function(list, id, isSelected) {
var elemScope = angular
.element("#" +
list + "s_table #" + id + ".List-tableRow input")
.scope();
if (elemScope) {
elemScope.isSelected = !!isSelected;
}
};
scope.allSelected = []; scope.allSelected = [];
// the object permissions are being added to // the object permissions are being added to
@@ -72,6 +39,8 @@ export default ['$rootScope', '$scope', 'GetBasePath', 'Rest', '$q', function (r
.roles[key].name }; .roles[key].name };
}); });
// TODO: get working with api
// array w roles and descriptions for key
scope.roleKey = Object scope.roleKey = Object
.keys(scope.object.summary_fields.roles) .keys(scope.object.summary_fields.roles)
.map(function(key) { .map(function(key) {
@@ -82,35 +51,36 @@ export default ['$rootScope', '$scope', 'GetBasePath', 'Rest', '$q', function (r
.roles[key].description }; .roles[key].description };
}); });
// handle form tabs // handle form tab changes
scope.toggleFormTabs = function(list) { scope.toggleFormTabs = function(list) {
scope.usersSelected = (list === 'users'); scope.usersSelected = (list === 'users');
scope.teamsSelected = !scope.usersSelected; scope.teamsSelected = !scope.usersSelected;
}; };
// TODO: manually handle selection/deselection // manually handle selection/deselection of user/team checkboxes
// of user/team checkboxes
scope.$on("selectedOrDeselected", function(e, val) { scope.$on("selectedOrDeselected", function(e, val) {
val = val.value; val = val.value;
if (val.isSelected) { if (val.isSelected) {
// deselected, so remove from the allSelected list
scope.allSelected = scope.allSelected.filter(function(i) { scope.allSelected = scope.allSelected.filter(function(i) {
// return all but the object who has the id and type
// of the element to deselect
return (!(val.id === i.id && val.type === i.type)); return (!(val.id === i.id && val.type === i.type));
}); });
} else { } else {
var name; // selected, so add to the allSelected list
if (val.type === "user") {
name = (val.first_name &&
val.last_name) ?
val.first_name + " " +
val.last_name :
val.username;
} else {
name = val.name;
}
scope.allSelected.push({ scope.allSelected.push({
name: name, name: function() {
if (val.type === "user") {
return (val.first_name &&
val.last_name) ?
val.first_name + " " +
val.last_name :
val.username;
} else {
return val .name;
}
},
type: val.type, type: val.type,
roles: [], roles: [],
id: val.id id: val.id
@@ -118,10 +88,16 @@ export default ['$rootScope', '$scope', 'GetBasePath', 'Rest', '$q', function (r
} }
}); });
// used to handle changes to the itemsSelected scope var on "next page",
// "sorting etc."
scope.$on("itemsSelected", function(e, inList) { scope.$on("itemsSelected", function(e, inList) {
// compile a list of objects that needed to be checked in the lists
scope.updateLists = scope.allSelected.filter(function(inMemory) { scope.updateLists = scope.allSelected.filter(function(inMemory) {
var notInList = true; var notInList = true;
inList.forEach(function(val) { inList.forEach(function(val) {
// if the object is part of the allSelected list and is
// selected,
// you don't need to add it updateLists
if (inMemory.id === val.id && if (inMemory.id === val.id &&
inMemory.type === val.type) { inMemory.type === val.type) {
notInList = false; notInList = false;
@@ -131,61 +107,19 @@ export default ['$rootScope', '$scope', 'GetBasePath', 'Rest', '$q', function (r
}); });
}); });
// handle changes to the updatedLists by manually selected those values in
// the UI
scope.$watch("updateLists", function(toUpdate) { scope.$watch("updateLists", function(toUpdate) {
(toUpdate || []).forEach(function(obj) { (toUpdate || []).forEach(function(obj) {
var elemScope = angular manuallyUpdateChecklists(obj.type, obj.id, true);
.element("#" +
obj.type + "s_table #" + obj.id +
".List-tableRow input")
.scope()
if (elemScope) {
elemScope.isSelected = true;
}
}); });
delete scope.updateLists; delete scope.updateLists;
}); });
// create array of users/teams
// scope.$watchGroup(['selectedUsers', 'selectedTeams'],
// function(val) {
// scope.allSelected = (val[0] || [])
// .map(function(i) {
// var roles = i.roles || [];
// var name = (i.first_name &&
// i.last_name) ?
// i.first_name + " " +
// i.last_name :
// i.username;
//
// return {
// name: name,
// type: "user",
// roles: roles,
// id: i.id
// };
// }).concat((val[1] || [])
// .map(function(i) {
// var roles = i.roles || [];
//
// return {
// name: i.name,
// type: "team",
// roles: roles,
// id: i.id
// };
// }));
// });
// remove selected user/team // remove selected user/team
scope.removeObject = function(obj) { scope.removeObject = function(obj) {
var elemScope = angular manuallyUpdateChecklists(obj.type, obj.id, false);
.element("#" +
obj.type + "s_table #" + obj.id + ".List-tableRow input")
.scope()
if (elemScope) {
elemScope.isSelected = false;
}
scope.allSelected = scope.allSelected.filter(function(i) { scope.allSelected = scope.allSelected.filter(function(i) {
return (!(obj.id === i.id && obj.type === i.type)); return (!(obj.id === i.id && obj.type === i.type));
@@ -197,7 +131,7 @@ export default ['$rootScope', '$scope', 'GetBasePath', 'Rest', '$q', function (r
scope.posts = _ scope.posts = _
.flatten((val || []) .flatten((val || [])
.map(function (owner) { .map(function (owner) {
var url = GetBasePath(owner.type + "s") + "/" + owner.id + var url = GetBasePath(owner.type + "s") + owner.id +
"/roles/"; "/roles/";
return (owner.roles || []) return (owner.roles || [])
@@ -217,7 +151,7 @@ export default ['$rootScope', '$scope', 'GetBasePath', 'Rest', '$q', function (r
}); });
$q.all(requests) $q.all(requests)
.then(function (responses) { .then(function () {
rootScope.$broadcast("refreshList", "permission"); rootScope.$broadcast("refreshList", "permission");
scope.closeModal(); scope.closeModal();
}, function (error) { }, function (error) {

View File

@@ -17,7 +17,7 @@ export default
templateUrl: templateUrl('access/addPermissions/addPermissions'), templateUrl: templateUrl('access/addPermissions/addPermissions'),
link: function(scope, element, attrs, ctrl) { link: function(scope, element, attrs, ctrl) {
scope.toggleFormTabs('users'); scope.toggleFormTabs('users');
$("body").append(element); $("body").append(element);
Wait('start'); Wait('start');

View File

@@ -1,7 +1,7 @@
<div id="add-permissions-modal" class="LoginModal modal fade"> <div id="add-permissions-modal" class="AddPermissions modal fade">
<div class="LoginModal-backDrop is-loggedOut"></div> <div class="AddPermissions-backDrop is-loggedOut"></div>
<div class="LoginModal-dialog"> <div class="AddPermissions-dialog">
<div class="LoginModal-content is-loggedOut AddPermissions-content"> <div class="AddPermissions-content is-loggedOut">
<div class="AddPermissions-header"> <div class="AddPermissions-header">
<div class="List-header"> <div class="List-header">
<div class="List-title"> <div class="List-title">
@@ -18,7 +18,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="LoginModal-body AddPermissions-body"> <div class="AddPermissions-body">
<div class="AddPermissions-directions"> <div class="AddPermissions-directions">
<span class="AddPermissions-directionNumber"> <span class="AddPermissions-directionNumber">
1. 1.
@@ -41,14 +41,12 @@
</div> </div>
<div class="AddPermissions-list" ng-show="usersSelected"> <div class="AddPermissions-list" ng-show="usersSelected">
<add-permissions-users <add-permissions-list type="users">
selected="selectedUsers"> </add-permissions-list>
</add-permissions-users>
</div> </div>
<div class="AddPermissions-list" ng-show="teamsSelected"> <div class="AddPermissions-list" ng-show="teamsSelected">
<add-permissions-teams <add-permissions-list type="teams">
selected="selectedTeams"> </add-permissions-list>
</add-permissions-teams>
</div> </div>
<div class="AddPermissions-separator" <div class="AddPermissions-separator"
@@ -83,7 +81,7 @@
</ng-form> </ng-form>
</form> </form>
</div> </div>
<div class="LoginModal-footer AddPermissions-footer"> <div class="AddPermissions-footer">
{{ post }} {{ post }}
<div class="buttons Form-buttons AddPermissions-buttons"> <div class="buttons Form-buttons AddPermissions-buttons">
<button type="button" <button type="button"

View File

@@ -6,16 +6,17 @@
/* jshint unused: vars */ /* jshint unused: vars */
export default export default
['addPermissionsTeamsList', 'generateList', 'GetBasePath', 'SelectionInit', 'SearchInit', ['addPermissionsTeamsList', 'addPermissionsUsersList', 'generateList', 'GetBasePath', 'SelectionInit', 'SearchInit',
'PaginateInit', function(addPermissionsTeamsList, generateList, 'PaginateInit', function(addPermissionsTeamsList,
addPermissionsUsersList, generateList,
GetBasePath, SelectionInit, SearchInit, PaginateInit) { GetBasePath, SelectionInit, SearchInit, PaginateInit) {
return { return {
restrict: 'E', restrict: 'E',
scope: { scope: {
}, },
template: "<div id='addPermissionsTeamsList'></div>", template: "<div class='addPermissionsList-inner'></div>",
link: function(scope, element, attrs, ctrl) { link: function(scope, element, attrs, ctrl) {
scope.$on("linkLists", function() { scope.$on("linkLists", function(e) {
var generator = generateList, var generator = generateList,
list = addPermissionsTeamsList, list = addPermissionsTeamsList,
url = GetBasePath("teams"), url = GetBasePath("teams"),
@@ -23,10 +24,23 @@ export default
id = "addPermissionsTeamsList", id = "addPermissionsTeamsList",
mode = "edit"; mode = "edit";
if (attrs.type === 'users') {
list = addPermissionsUsersList;
url = GetBasePath("users") + "?is_superuser=false";
set = "users";
id = "addPermissionsUsersList";
mode = "edit";
}
scope.id = id;
scope.$watch("selectedItems", function() { scope.$watch("selectedItems", function() {
scope.$emit("itemsSelected", scope.selectedItems); scope.$emit("itemsSelected", scope.selectedItems);
}); });
element.find(".addPermissionsList-inner")
.attr("id", id);
generator.inject(list, { id: id, generator.inject(list, { id: id,
title: false, mode: mode, scope: scope }); title: false, mode: mode, scope: scope });

View File

@@ -0,0 +1,15 @@
/*************************************************
* Copyright (c) 2015 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
import addPermissionsListDirective from './addPermissionsList.directive';
import teamsList from './permissionsTeams.list';
import usersList from './permissionsUsers.list';
export default
angular.module('addPermissionsListModule', [])
.directive('addPermissionsList', addPermissionsListDirective)
.factory('addPermissionsTeamsList', teamsList)
.factory('addPermissionsUsersList', usersList);

View File

@@ -6,10 +6,9 @@
import addPermissionsDirective from './addPermissions.directive'; import addPermissionsDirective from './addPermissions.directive';
import roleSelect from './roleSelect.directive'; import roleSelect from './roleSelect.directive';
import teamsPermissions from './teams/main'; import addPermissionsList from './addPermissionsList/main';
import usersPermissions from './users/main';
export default export default
angular.module('AddPermissions', [teamsPermissions.name, usersPermissions.name]) angular.module('AddPermissions', [addPermissionsList.name])
.directive('addPermissions', addPermissionsDirective) .directive('addPermissions', addPermissionsDirective)
.directive('roleSelect', roleSelect); .directive('roleSelect', roleSelect);

View File

@@ -1,13 +0,0 @@
/*************************************************
* Copyright (c) 2015 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
import teamsDirective from './permissionsTeams.directive';
import teamsList from './permissionsTeams.list';
export default
angular.module('PermissionsTeams', [])
.directive('addPermissionsTeams', teamsDirective)
.factory('addPermissionsTeamsList', teamsList);

View File

@@ -1,13 +0,0 @@
/*************************************************
* Copyright (c) 2015 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
import usersDirective from './permissionsUsers.directive';
import usersList from './permissionsUsers.list';
export default
angular.module('PermissionsUsers', [])
.directive('addPermissionsUsers', usersDirective)
.factory('addPermissionsUsersList', usersList);

View File

@@ -1,44 +0,0 @@
/*************************************************
* Copyright (c) 2015 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
/* jshint unused: vars */
export default
['addPermissionsUsersList', 'generateList', 'GetBasePath', 'SelectionInit', 'SearchInit',
'PaginateInit', function(addPermissionsUsersList, generateList,
GetBasePath, SelectionInit, SearchInit, PaginateInit) {
return {
restrict: 'E',
scope: {
},
template: "<div id='addPermissionsUsersList'></div>",
link: function(scope, element, attrs, ctrl) {
scope.$on("linkLists", function() {
var generator = generateList,
list = addPermissionsUsersList,
url = GetBasePath("users") + "?is_superuser=false",
set = "users",
id = "addPermissionsUsersList",
mode = "edit";
scope.$watch("selectedItems", function() {
scope.$emit("itemsSelected", scope.selectedItems);
});
generator.inject(list, { id: id,
title: false, mode: mode, scope: scope });
SearchInit({ scope: scope, set: set,
list: list, url: url });
PaginateInit({ scope: scope,
list: list, url: url, pageSize: 5 });
scope.search(list.iterator);
});
}
};
}
];

View File

@@ -1,4 +1,5 @@
/** @define RoleList */ /** @define RoleList */
@import "../shared/branding/colors.default.less";
.RoleList { .RoleList {
display: flex; display: flex;
@@ -15,11 +16,11 @@
border-radius: 5px; border-radius: 5px;
padding: 2px 10px; padding: 2px 10px;
margin: 4px 0px; margin: 4px 0px;
border: 1px solid #e1e1e1; border: 1px solid @default-second-border;
font-size: 12px; font-size: 12px;
color: #848992; color: @default-interface-txt;
text-transform: uppercase; text-transform: uppercase;
background-color: #fff; background-color: @default-bg;
margin-right: 5px; margin-right: 5px;
max-width: 100%; max-width: 100%;
white-space: nowrap; white-space: nowrap;
@@ -36,7 +37,7 @@
} }
.RoleList-deleteContainer { .RoleList-deleteContainer {
border: 1px solid #e1e1e1; border: 1px solid @default-second-border;
border-top-right-radius: 5px; border-top-right-radius: 5px;
border-bottom-right-radius: 5px; border-bottom-right-radius: 5px;
padding: 0 5px; padding: 0 5px;
@@ -49,7 +50,7 @@
.RoleList-tagDelete { .RoleList-tagDelete {
font-size: 13px; font-size: 13px;
color: #b7b7b7; color: @default-icon;
} }
.RoleList-name { .RoleList-name {
@@ -62,10 +63,10 @@
} }
.RoleList-deleteContainer:hover, { .RoleList-deleteContainer:hover, {
border-color: #ff5850; border-color: @default-err;
background-color: #ff5850; background-color: @default-err;
} }
.RoleList-deleteContainer:hover > .RoleList-tagDelete { .RoleList-deleteContainer:hover > .RoleList-tagDelete {
color: #fff; color: @default-bg;
} }