1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-05 13:55:21 +02:00

feat(global): introduce user teams and new UAC system (#868)

This commit is contained in:
Anthony Lapenna 2017-05-23 20:56:10 +02:00 committed by GitHub
parent a380fd9adc
commit 5523fc9023
160 changed files with 7112 additions and 3166 deletions

View file

@ -0,0 +1,176 @@
<rd-header>
<rd-header-title title="Team details">
<i id="loadingViewSpinner" class="fa fa-cog fa-spin"></i>
</rd-header-title>
<rd-header-content>
<a ui-sref="teams">Teams</a> > <a ui-sref="team({id: team.Id})">{{ team.Name }}</a>
</rd-header-content>
</rd-header>
<div class="row">
<div class="col-lg-12 col-md-12 col-xs-12">
<rd-widget>
<rd-widget-header icon="fa-users" title="Team details"></rd-widget-header>
<rd-widget-body classes="no-padding">
<table class="table">
<tbody>
<tr>
<td>Name</td>
<td>
{{ team.Name }}
<button class="btn btn-xs btn-danger" ng-if="isAdmin" ng-click="deleteTeam()"><i class="fa fa-trash space-right" aria-hidden="true"></i>Delete this team</button>
</td>
</tr>
<tr>
<td>Leaders</td>
<td>{{ leaderCount }}</td>
</tr>
<tr>
<td>Total users in team</td>
<td>{{ teamMembers.length }}</td>
</tr>
</tbody>
</table>
</rd-widget-body>
</rd-widget>
</div>
</div>
<div class="row" ng-if="team">
<div class="col-sm-6">
<rd-widget>
<rd-widget-header classes="col-sm-12 col-md-6 nopadding" icon="fa-users" title="Users">
<div class="pull-md-right pull-lg-right">
Items per page:
<select ng-model="state.pagination_count_users" ng-change="changePaginationCountUsers()">
<option value="0">All</option>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
</div>
</rd-widget-header>
<rd-widget-taskbar classes="col-sm-12 nopadding">
<div class="col-sm-12 col-md-6 nopadding">
<button class="btn btn-primary btn-sm" ng-click="addAllUsers()" ng-if="isAdmin" ng-disabled="users.length === 0 || filteredUsers.length === 0"><i class="fa fa-user-plus space-right" aria-hidden="true"></i>Add all users</button>
</div>
<div class="col-sm-12 col-md-6 nopadding">
<input type="text" id="filter" ng-model="state.filterUsers" placeholder="Filter..." class="form-control input-sm" />
</div>
</rd-widget-taskbar>
<rd-widget-body classes="no-padding">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>
<a ui-sref="endpoint.access({id: endpoint.Id})" ng-click="orderUsers('Username')">
Name
<span ng-show="sortTypeUsers == 'Username' && !sortReverseUsers" class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="sortTypeUsers == 'Username' && sortReverseUsers" class="glyphicon glyphicon-chevron-up"></span>
</a>
</th>
</tr>
</thead>
<tbody>
<tr pagination-id="table1" dir-paginate="user in users | filter:state.filterUsers | orderBy:sortTypeUsers:sortReverseUsers | itemsPerPage: state.pagination_count_users">
<td>
{{ user.Username }}
<span style="margin-left: 5px;">
<a class="btn-outline-secondary" ng-click="addUser(user)"><i class="fa fa-plus-circle space-right" aria-hidden="true"></i>Add</a>
</span>
</td>
</tr>
<tr ng-if="!users">
<td colspan="2" class="text-center text-muted">Loading...</td>
</tr>
<tr ng-if="users.length === 0 || (users | filter:state.filterUsers).length === 0">
<td colspan="2" class="text-center text-muted">No users.</td>
</tr>
</tbody>
</table>
<div ng-if="users" class="pull-left pagination-controls">
<dir-pagination-controls pagination-id="table1"></dir-pagination-controls>
</div>
</div>
</rd-widget-body>
</rd-widget>
</div>
<div class="col-sm-6">
<rd-widget>
<rd-widget-header classes="col-sm-12 col-md-6 nopadding" icon="fa-users" title="Team members">
<div class="pull-md-right pull-lg-right">
Items per page:
<select ng-model="state.pagination_count_members" ng-change="changePaginationCountGroupMembers()">
<option value="0">All</option>
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
</div>
</rd-widget-header>
<rd-widget-taskbar classes="col-sm-12 nopadding">
<div class="col-sm-12 col-md-6 nopadding">
<button class="btn btn-primary btn-sm" ng-click="removeAllUsers()" ng-if="isAdmin" ng-disabled="teamMembers.length === 0 || filteredGroupMembers.length === 0"><i class="fa fa-user-times space-right" aria-hidden="true"></i>Remove all users</button>
</div>
<div class="col-sm-12 col-md-6 nopadding">
<input type="text" id="filter" ng-model="state.filterGroupMembers" placeholder="Filter..." class="form-control input-sm" />
</div>
</rd-widget-taskbar>
<rd-widget-body classes="no-padding">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>
<a ui-sref="team({id: team.Id})" ng-click="orderGroupMembers('Username')">
Name
<span ng-show="sortTypeGroupMembers == 'Username' && !sortReverseGroupMembers" class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="sortTypeGroupMembers == 'Username' && sortReverseGroupMembers" class="glyphicon glyphicon-chevron-up"></span>
</a>
</th>
<th>
<a ui-sref="team({id: team.Id})" ng-click="orderGroupMembers('TeamRole')">
Team Role
<span ng-show="sortTypeGroupMembers == 'TeamRole' && !sortReverseGroupMembers" class="glyphicon glyphicon-chevron-down"></span>
<span ng-show="sortTypeGroupMembers == 'TeamRole' && sortReverseGroupMembers" class="glyphicon glyphicon-chevron-up"></span>
</a>
</th>
</tr>
</thead>
<tbody>
<tr pagination-id="table2" dir-paginate="user in teamMembers | filter:state.filterGroupMembers | orderBy:sortTypeGroupMembers:sortReverseGroupMembers | itemsPerPage: state.pagination_count_groupMembers">
<td>
{{ user.Username }}
<span style="margin-left: 5px;" ng-if="isAdmin || user.TeamRole === 'Member'")>
<a class="btn-outline-secondary" ng-click="removeUser(user)"><i class="fa fa-minus-circle space-right" aria-hidden="true"></i>Remove</a>
</span>
</td>
<td>
<i ng-if="user.TeamRole === 'Leader'" class="fa fa-user-plus" aria-hidden="true" style="margin-right: 2px;"></i>
<i ng-if="user.TeamRole === 'Member'" class="fa fa-user" aria-hidden="true" style="margin-right: 2px;"></i>
{{ user.TeamRole }}
<span style="margin-left: 5px;" ng-if="isAdmin">
<a class="btn-outline-secondary" style="margin-left: 5px;" ng-click="promoteToLeader(user)" ng-if="user.TeamRole === 'Member'"><i class="fa fa-user-plus space-right" aria-hidden="true"></i>Leader</a>
<a class="btn-outline-secondary" style="margin-left: 5px;" ng-click="demoteToMember(user)" ng-if="user.TeamRole === 'Leader'"><i class="fa fa-user-times space-right" aria-hidden="true"></i>Member</a>
</span>
</td>
</tr>
<tr ng-if="!teamMembers">
<td colspan="2" class="text-center text-muted">Loading...</td>
</tr>
<tr ng-if="teamMembers.length === 0 || (teamMembers | filter:state.filterGroupMembers).length === 0">
<td colspan="2" class="text-center text-muted">No team members.</td>
</tr>
</tbody>
</table>
<div ng-if="teamMembers" class="pull-left pagination-controls">
<dir-pagination-controls pagination-id="table2"></dir-pagination-controls>
</div>
</div>
</rd-widget-body>
</rd-widget>
</div>
</div>

View file

@ -0,0 +1,229 @@
angular.module('team', [])
.controller('TeamController', ['$q', '$scope', '$state', '$stateParams', 'TeamService', 'UserService', 'TeamMembershipService', 'ModalService', 'Notifications', 'Pagination', 'Authentication',
function ($q, $scope, $state, $stateParams, TeamService, UserService, TeamMembershipService, ModalService, Notifications, Pagination, Authentication) {
$scope.state = {
pagination_count_users: Pagination.getPaginationCount('team_available_users'),
pagination_count_members: Pagination.getPaginationCount('team_members')
};
$scope.sortTypeUsers = 'Username';
$scope.sortReverseUsers = true;
$scope.users = [];
$scope.teamMembers = [];
$scope.leaderCount = 0;
$scope.orderUsers = function(sortType) {
$scope.sortReverseUsers = ($scope.sortTypeUsers === sortType) ? !$scope.sortReverseUsers : false;
$scope.sortTypeUsers = sortType;
};
$scope.changePaginationCountUsers = function() {
Pagination.setPaginationCount('team_available_users', $scope.state.pagination_count_users);
};
$scope.sortTypeGroupMembers = 'TeamRole';
$scope.sortReverseGroupMembers = false;
$scope.orderGroupMembers = function(sortType) {
$scope.sortReverseGroupMembers = ($scope.sortTypeGroupMembers === sortType) ? !$scope.sortReverseGroupMembers : false;
$scope.sortTypeGroupMembers = sortType;
};
$scope.changePaginationCountGroupMembers = function() {
Pagination.setPaginationCount('team_members', $scope.state.pagination_count_members);
};
$scope.deleteTeam = function() {
ModalService.confirmDeletion(
'Do you want to delete this team? Users in this team will not be deleted.',
function onConfirm(confirmed) {
if(!confirmed) { return; }
deleteTeam();
}
);
};
$scope.promoteToLeader = function(user) {
$('#loadingViewSpinner').show();
TeamMembershipService.updateMembership(user.MembershipId, user.Id, $scope.team.Id, 1)
.then(function success(data) {
$scope.leaderCount++;
user.TeamRole = 'Leader';
Notifications.success('User is now team leader', user.Username);
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to update user role');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
});
};
$scope.demoteToMember = function(user) {
$('#loadingViewSpinner').show();
TeamMembershipService.updateMembership(user.MembershipId, user.Id, $scope.team.Id, 2)
.then(function success(data) {
user.TeamRole = 'Member';
$scope.leaderCount--;
Notifications.success('User is now team member', user.Username);
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to update user role');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
});
};
$scope.addAllUsers = function() {
$('#loadingViewSpinner').show();
var teamMembershipQueries = [];
angular.forEach($scope.users, function (user) {
teamMembershipQueries.push(TeamMembershipService.createMembership(user.Id, $scope.team.Id, 2));
});
$q.all(teamMembershipQueries)
.then(function success(data) {
var users = $scope.users;
for (var i = 0; i < users.length; i++) {
var user = users[i];
user.MembershipId = data[i].Id;
user.TeamRole = 'Member';
}
$scope.teamMembers = $scope.teamMembers.concat(users);
$scope.users = [];
Notifications.success('All users successfully added');
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to update team members');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
});
};
$scope.addUser = function(user) {
$('#loadingViewSpinner').show();
TeamMembershipService.createMembership(user.Id, $scope.team.Id, 2)
.then(function success(data) {
removeUserFromArray(user.Id, $scope.users);
user.TeamRole = 'Member';
user.MembershipId = data.Id;
$scope.teamMembers.push(user);
Notifications.success('User added to team', user.Username);
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to update team members');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
});
};
$scope.removeAllUsers = function() {
$('#loadingViewSpinner').show();
var teamMembershipQueries = [];
angular.forEach($scope.teamMembers, function (user) {
teamMembershipQueries.push(TeamMembershipService.deleteMembership(user.MembershipId));
});
$q.all(teamMembershipQueries)
.then(function success(data) {
$scope.users = $scope.users.concat($scope.teamMembers);
$scope.teamMembers = [];
Notifications.success('All users successfully removed');
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to update team members');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
});
};
$scope.removeUser = function(user) {
$('#loadingViewSpinner').show();
TeamMembershipService.deleteMembership(user.MembershipId)
.then(function success() {
removeUserFromArray(user.Id, $scope.teamMembers);
$scope.users.push(user);
Notifications.success('User removed from team', user.Username);
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to update team members');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
});
};
function deleteTeam() {
$('#loadingViewSpinner').show();
TeamService.deleteTeam($scope.team.Id)
.then(function success(data) {
Notifications.success('Team successfully deleted', $scope.team.Name);
$state.go('teams');
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to remove team');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
});
}
function removeUserFromArray(id, users) {
for (var i = 0, l = users.length; i < l; i++) {
if (users[i].Id === id) {
users.splice(i, 1);
return;
}
}
}
function assignUsersAndMembers(users, memberships) {
for (var i = 0; i < users.length; i++) {
var user = users[i];
var member = false;
for (var j = 0; j < memberships.length; j++) {
var membership = memberships[j];
if (user.Id === membership.UserId) {
member = true;
if (membership.Role === 1) {
user.TeamRole = 'Leader';
$scope.leaderCount++;
} else {
user.TeamRole = 'Member';
}
user.MembershipId = membership.Id;
$scope.teamMembers.push(user);
break;
}
}
if (!member) {
$scope.users.push(user);
}
}
}
function initView() {
$('#loadingViewSpinner').show();
$scope.isAdmin = Authentication.getUserDetails().role === 1 ? true: false;
$q.all({
team: TeamService.team($stateParams.id),
users: UserService.users(false),
memberships: TeamService.userMemberships($stateParams.id)
})
.then(function success(data) {
var users = data.users;
$scope.team = data.team;
assignUsersAndMembers(users, data.memberships);
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve team details');
})
.finally(function final() {
$('#loadingViewSpinner').hide();
});
}
initView();
}]);