Redesign the teams page to use a table
Allows for faster loading and easier viewing of important information about teams
This commit is contained in:
parent
98206310bd
commit
6ebb417923
11 changed files with 194 additions and 168 deletions
|
@ -1,7 +1,9 @@
|
|||
from data.database import Team, TeamMember, TeamRole, User, TeamMemberInvite
|
||||
from data.database import Team, TeamMember, TeamRole, User, TeamMemberInvite, RepositoryPermission
|
||||
from data.model import (DataModelException, InvalidTeamException, UserAlreadyInTeam,
|
||||
InvalidTeamMemberException, user, _basequery)
|
||||
from util.validation import validate_username
|
||||
from peewee import fn, JOIN_LEFT_OUTER
|
||||
from util.morecollections import AttrDict
|
||||
|
||||
|
||||
def create_team(name, org_obj, team_role_name, description=''):
|
||||
|
@ -186,7 +188,32 @@ def get_matching_teams(team_prefix, organization):
|
|||
|
||||
|
||||
def get_teams_within_org(organization):
|
||||
return Team.select().where(Team.organization == organization)
|
||||
""" Returns a AttrDict of team info (id, name, description), its role under the org,
|
||||
the number of repositories on which it has permission, and the number of members.
|
||||
"""
|
||||
query = (Team.select(Team.id, Team.name, Team.description, TeamRole.name,
|
||||
fn.Count(RepositoryPermission.id), fn.Count(TeamMember.id))
|
||||
.where(Team.organization == organization)
|
||||
.join(TeamRole)
|
||||
.switch(Team)
|
||||
.join(RepositoryPermission, JOIN_LEFT_OUTER)
|
||||
.switch(Team)
|
||||
.join(TeamMember, JOIN_LEFT_OUTER)
|
||||
.group_by(Team.id)
|
||||
.tuples())
|
||||
|
||||
def _team_view(team_tuple):
|
||||
return AttrDict({
|
||||
'id': team_tuple[0],
|
||||
'name': team_tuple[1],
|
||||
'description': team_tuple[2],
|
||||
'role_name': team_tuple[3],
|
||||
|
||||
'repo_count': team_tuple[4],
|
||||
'member_count': team_tuple[5],
|
||||
})
|
||||
|
||||
return [_team_view(team_tuple) for team_tuple in query]
|
||||
|
||||
|
||||
def get_user_teams_within_org(username, organization):
|
||||
|
|
|
@ -8,13 +8,12 @@ import features
|
|||
|
||||
from app import billing as stripe, avatar
|
||||
from endpoints.api import (resource, nickname, ApiResource, validate_json_request, request_error,
|
||||
related_user_resource, internal_only, require_user_admin, log_action,
|
||||
related_user_resource, internal_only, require_user_admin, log_action,
|
||||
show_if, path_param, require_scope)
|
||||
from endpoints.exception import Unauthorized, NotFound
|
||||
from endpoints.api.team import team_view
|
||||
from endpoints.api.user import User, PrivateRepositories
|
||||
from auth.permissions import (AdministerOrganizationPermission, OrganizationMemberPermission,
|
||||
CreateRepositoryPermission)
|
||||
CreateRepositoryPermission, ViewTeamPermission)
|
||||
from auth.auth_context import get_authenticated_user
|
||||
from auth import scopes
|
||||
from data import model
|
||||
|
@ -24,6 +23,18 @@ from data.billing import get_plan
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def team_view(orgname, team):
|
||||
return {
|
||||
'name': team.name,
|
||||
'description': team.description,
|
||||
'role': team.role_name,
|
||||
'avatar': avatar.get_data_for_team(team),
|
||||
'can_view': ViewTeamPermission(orgname, team.name).can(),
|
||||
|
||||
'repo_count': team.repo_count,
|
||||
'member_count': team.member_count,
|
||||
}
|
||||
|
||||
|
||||
def org_view(o, teams):
|
||||
is_admin = AdministerOrganizationPermission(o.username).can()
|
||||
|
|
|
@ -15,39 +15,3 @@
|
|||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.create-entity-dialog-element label {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.create-entity-dialog-element .co-table {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.create-entity-dialog-element .fa-hdd-o {
|
||||
margin-right: 4px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.create-entity-dialog-element .co-filter-box {
|
||||
display: block;
|
||||
float: right;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.create-entity-dialog-element .co-filter-box .filter-message {
|
||||
left: -180px;
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
.create-entity-dialog-element .co-filter-box input {
|
||||
width: 100%;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.create-entity-dialog-element label .avatar {
|
||||
vertical-align: text-bottom;
|
||||
margin-left: 4px;
|
||||
}
|
|
@ -1,5 +1,19 @@
|
|||
.teams-manager .popup-input-button {
|
||||
.teams-manager .co-filter-box {
|
||||
display: block;
|
||||
float: right;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.teams-manager.co-filter-box .filter-message {
|
||||
left: -180px;
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
.teams-manager .co-filter-box input {
|
||||
width: 100%;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.teams-manager .manager-header {
|
||||
|
@ -20,6 +34,10 @@
|
|||
color: #ccc;
|
||||
}
|
||||
|
||||
.teams-manager .co-table .avatar {
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
.teams-manager .cor-confirm-dialog .entity-reference .avatar {
|
||||
margin-left: 4px;
|
||||
margin-right: 0px;
|
||||
|
@ -36,14 +54,20 @@
|
|||
}
|
||||
|
||||
@media (max-width: 767px) {
|
||||
.teams-manager .control-col {
|
||||
padding-left: 55px;
|
||||
padding-bottom: 10px;
|
||||
.teams-manager .co-filter-box {
|
||||
display: block;
|
||||
float: none;
|
||||
}
|
||||
}
|
||||
|
||||
.teams-manager .header-col .info-icon {
|
||||
.teams-manager .info-icon {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.teams-manager .popover-content {
|
||||
color: black;
|
||||
font-size: 16px;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
.teams-manager .header-col .header-text {
|
||||
|
|
|
@ -634,13 +634,6 @@ i.toggle-icon:hover {
|
|||
padding: 6px;
|
||||
}
|
||||
|
||||
.info-icon {
|
||||
display: inline-block;
|
||||
float: right;
|
||||
vertical-align: middle;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.accordion-toggle {
|
||||
cursor: pointer;
|
||||
text-decoration: none !important;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<div class="add-repo-permissions-entity">
|
||||
<div class="add-repo-permissions-element">
|
||||
<span class="co-filter-box">
|
||||
<span class="filter-message" ng-if="options.filter">
|
||||
Showing {{ orderedRepositories.entries.length }} of {{ repositories.length }} repositories
|
||||
|
@ -8,11 +8,11 @@
|
|||
|
||||
<label>
|
||||
Select repositories in
|
||||
<span class="avatar" size="16" data="namespace.avatar"></span>
|
||||
<span class="avatar" size="16" data="namespaceInfo.avatar"></span>
|
||||
{{ namespace }}:
|
||||
</label>
|
||||
|
||||
<table class="co-table" style="margin-bottom: 210px;">
|
||||
<table class="co-table">
|
||||
<thead>
|
||||
<td class="checkbox-col checkbox-menu-col">
|
||||
<span class="cor-checkable-menu" controller="checkedRepos">
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
has-checked-repositories="context.hasCheckedRepositories"
|
||||
repositories-loaded="repositoriesLoaded(repositories)"
|
||||
adding-permissions="addingPermissions()"
|
||||
permissions-added="permissionsAdded()"
|
||||
permissions-added="permissionsAdded(repositories)"
|
||||
add-permissions="context.addPermissionsCounter"
|
||||
ng-if="entity"></div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
<div class="teams-manager-element">
|
||||
<div class="feedback-bar" feedback="feedback"></div>
|
||||
<div class="manager-header" header-title="Teams and Membership">
|
||||
<div class="tab-header-controls visible-xs">
|
||||
<button class="btn btn-primary"
|
||||
ng-show="organization.is_admin"
|
||||
ng-click="askCreateTeam()">
|
||||
<i class="fa fa-plus" style="margin-right: 4px;"></i> Create New Team
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="tab-header-controls hidden-xs">
|
||||
<div class="btn-group btn-group-sm" ng-show="organization.is_admin">
|
||||
<button class="btn"
|
||||
|
@ -17,66 +25,69 @@
|
|||
|
||||
<!-- Teams List -->
|
||||
<div ng-show="!showingMembers">
|
||||
<div class="row" style="margin-left: 0px; margin-right: 0px;">
|
||||
<button class="btn btn-primary hidden-xs"
|
||||
ng-show="organization.is_admin"
|
||||
style="margin-bottom: 10px; float: right;"
|
||||
ng-click="askCreateTeam()">
|
||||
<i class="fa fa-plus" style="margin-right: 4px;"></i> Create New Team
|
||||
</button>
|
||||
</div>
|
||||
<button class="btn btn-primary hidden-xs"
|
||||
ng-show="organization.is_admin"
|
||||
style="margin-bottom: 10px; "
|
||||
ng-click="askCreateTeam()">
|
||||
<i class="fa fa-plus" style="margin-right: 4px;"></i> Create New Team
|
||||
</button>
|
||||
|
||||
<div class="row hidden-xs">
|
||||
<div class="col-sm-7 col-md-8 header-col">
|
||||
<span class="header-text">Team Summary</span>
|
||||
</div>
|
||||
<div class="col-md-4 col-sm-5 header-col" ng-show="organization.is_admin">
|
||||
<span class="header-text">Team Permissions</span>
|
||||
<i class="info-icon fa fa-info-circle" data-placement="bottom" data-original-title="" data-title=""
|
||||
data-content="Global permissions for the team and its members<br><br><dl><dt>Member</dt><dd>Permissions are assigned on a per repository basis</dd><dt>Creator</dt><dd>A team can create its own repositories</dd><dt>Admin</dt><dd>A team has full control of the organization</dd></dl>"
|
||||
data-html="true"
|
||||
data-trigger="hover"
|
||||
bs-popover></i>
|
||||
</div>
|
||||
</div>
|
||||
<span class="co-filter-box">
|
||||
<span class="filter-message" ng-if="options.filter">
|
||||
Showing {{ orderedTeams.entries.length }} of {{ teams.length }} teams
|
||||
</span>
|
||||
<input class="form-control" type="text" ng-model="options.filter" placeholder="Filter Teams...">
|
||||
</span>
|
||||
|
||||
<div class="team-listing" ng-repeat="team in orderedTeams">
|
||||
<div id="team-{{team.name}}" class="row">
|
||||
<div class="col-sm-7 col-md-8">
|
||||
<div class="team-title">
|
||||
<span class="avatar" data="team.avatar" size="30"></span>
|
||||
<span ng-show="team.can_view">
|
||||
<a href="/organization/{{ organization.name }}/teams/{{ team.name }}">{{ team.name }}</a>
|
||||
</span>
|
||||
<span ng-show="!team.can_view">
|
||||
{{ team.name }}
|
||||
</span>
|
||||
</div>
|
||||
<table class="co-table" style="margin-top: 10px;">
|
||||
<thead>
|
||||
<td ng-class="TableService.tablePredicateClass('name', options.predicate, options.reverse)">
|
||||
<a ng-click="TableService.orderBy('name', options)">Team Name</a>
|
||||
</td>
|
||||
<td ng-class="TableService.tablePredicateClass('member_count', options.predicate, options.reverse)">
|
||||
<a ng-click="TableService.orderBy('member_count', options)">Members</a>
|
||||
</td>
|
||||
<td class="hidden-xs" ng-class="TableService.tablePredicateClass('repo_count', options.predicate, options.reverse)">
|
||||
<a ng-click="TableService.orderBy('repo_count', options)">Repositories</a>
|
||||
</td>
|
||||
<td ng-class="TableService.tablePredicateClass('role_index', options.predicate, options.reverse)">
|
||||
<a ng-click="TableService.orderBy('role_index', options)">Team Role</a>
|
||||
|
||||
<div class="team-description markdown-view" content="team.description" first-line-only="true"></div>
|
||||
<i class="info-icon fa fa-info-circle" data-placement="bottom" data-original-title="" data-title=""
|
||||
data-content="Global permissions for the team and its members<br><br><dl><dt>Member</dt><dd>Permissions are assigned on a per repository basis</dd><dt>Creator</dt><dd>A team can create its own repositories</dd><dt>Admin</dt><dd>A team has full control of the organization</dd></dl>"
|
||||
data-html="true"
|
||||
data-trigger="hover"
|
||||
bs-popover></i>
|
||||
</td>
|
||||
<td class="options-col"></td>
|
||||
</thead>
|
||||
|
||||
<div class="team-member-list hidden-xs" ng-if="members[team.name]">
|
||||
<div class="cor-loader" ng-if="!members[team.name].members"></div>
|
||||
<span class="team-member"
|
||||
ng-repeat="member in members[team.name].members | orderBy:'is_robot' | limitTo: 20">
|
||||
<span data-title="{{ member.name }}" bs-tooltip>
|
||||
<a href="/user/{{ member.name }}" ng-if="!member.is_robot">
|
||||
<span class="avatar" data="member.avatar" size="26"></span>
|
||||
</a>
|
||||
<i class="fa ci-robot fa-lg" ng-if="member.is_robot"></i>
|
||||
</span>
|
||||
</span>
|
||||
<span class="team-member-more"
|
||||
ng-if="members[team.name].members.length > 20">+ {{ members[team.name].members.length - 20 }} more team members.</span>
|
||||
<span class="team-member-more"
|
||||
ng-if="members[team.name].members && !members[team.name].members.length">(Empty Team)</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-5 col-md-4 control-col" ng-show="organization.is_admin">
|
||||
<tr class="co-checkable-row"
|
||||
ng-repeat="team in orderedTeams.visibleEntries"
|
||||
bindonce>
|
||||
<td style="white-space: nowrap;">
|
||||
<span class="avatar" data="team.avatar" size="24"></span>
|
||||
<span bo-show="team.can_view">
|
||||
<a href="/organization/{{ organization.name }}/teams/{{ team.name }}"><span bo-text="team.name"></span></a>
|
||||
</span>
|
||||
<span bo-show="!team.can_view" bo-text="team.name"></span>
|
||||
</td>
|
||||
<td>
|
||||
<span bo-show="team.can_view">
|
||||
<a href="/organization/{{ organization.name }}/teams/{{ team.name }}"><span bo-text="team.member_count"></span> <span class="hidden-xs">member<span bo-if="team.member_count != 1">s</span></span></a>
|
||||
</span>
|
||||
<span bo-show="!team.can_view">
|
||||
<span bo-text="team.member_count"></span> <span class="hidden-xs">member<span bo-if="team.member_count != 1">s</span></span>
|
||||
</span>
|
||||
</td>
|
||||
<td class="hidden-xs">
|
||||
<span bo-text="team.repo_count"></span> repositories
|
||||
</td>
|
||||
<td>
|
||||
<span class="role-group" current-role="team.role" pull-left="true"
|
||||
role-changed="setRole(role, team.name)" roles="teamRoles"></span>
|
||||
|
||||
</td>
|
||||
<td>
|
||||
<span class="cor-options-menu">
|
||||
<span class="cor-option" option-click="viewTeam(team.name)">
|
||||
<i class="fa fa-user"></i> Manage Team Members
|
||||
|
@ -85,8 +96,14 @@
|
|||
<i class="fa fa-times"></i> Delete Team {{ team.name }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="empty" ng-if="!orderedTeams.entries.length"
|
||||
style="margin-top: 20px;">
|
||||
<div class="empty-primary-msg">No matching teams found.</div>
|
||||
<div class="empty-secondary-msg">Try expanding your filtering terms.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ angular.module('quay').directive('addRepoPermissions', function () {
|
|||
'permissionsAdded': '&permissionsAdded',
|
||||
},
|
||||
|
||||
controller: function($scope, $element, ApiService, UIService, TableService, RolesService) {
|
||||
controller: function($scope, $element, ApiService, UIService, TableService, RolesService, UserService) {
|
||||
$scope.TableService = TableService;
|
||||
|
||||
$scope.options = {
|
||||
|
@ -71,6 +71,8 @@ angular.module('quay').directive('addRepoPermissions', function () {
|
|||
return;
|
||||
}
|
||||
|
||||
$scope.namespaceInfo = UserService.getNamespace($scope.namespace);
|
||||
|
||||
// Load the repositories under the entity's namespace.
|
||||
var params = {
|
||||
'namespace': $scope.namespace,
|
||||
|
@ -127,7 +129,7 @@ angular.module('quay').directive('addRepoPermissions', function () {
|
|||
|
||||
var addPerm = function() {
|
||||
if (counter >= repos.length) {
|
||||
$scope.permissionsAdded();
|
||||
$scope.permissionsAdded({'repositories': repos});
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,8 @@ angular.module('quay').directive('createEntityDialog', function () {
|
|||
});
|
||||
};
|
||||
|
||||
$scope.permissionsAdded = function() {
|
||||
$scope.permissionsAdded = function(repositories) {
|
||||
$scope.entity['repo_count'] = repositories.length;
|
||||
$scope.hide();
|
||||
};
|
||||
|
||||
|
|
|
@ -12,7 +12,15 @@ angular.module('quay').directive('teamsManager', function () {
|
|||
'organization': '=organization',
|
||||
'isEnabled': '=isEnabled'
|
||||
},
|
||||
controller: function($scope, $element, ApiService, $timeout, UserService) {
|
||||
controller: function($scope, $element, ApiService, $timeout, UserService, TableService, UIService) {
|
||||
$scope.TableService = TableService;
|
||||
|
||||
$scope.options = {
|
||||
'predicate': 'ordered_team_index',
|
||||
'reverse': false,
|
||||
'filter': ''
|
||||
};
|
||||
|
||||
$scope.teamRoles = [
|
||||
{ 'id': 'member', 'title': 'Member', 'kind': 'default' },
|
||||
{ 'id': 'creator', 'title': 'Creator', 'kind': 'success' },
|
||||
|
@ -21,65 +29,42 @@ angular.module('quay').directive('teamsManager', function () {
|
|||
|
||||
UserService.updateUserIn($scope);
|
||||
|
||||
$scope.members = {};
|
||||
$scope.orderedTeams = [];
|
||||
$scope.teams = null;
|
||||
$scope.orderedTeams = null;
|
||||
$scope.showingMembers = false;
|
||||
$scope.fullMemberList = null;
|
||||
$scope.feedback = null;
|
||||
$scope.createTeamInfo = null;
|
||||
|
||||
var loadTeamMembers = function() {
|
||||
if (!$scope.organization || !$scope.isEnabled) { return; }
|
||||
|
||||
// Skip loading team members on mobile.
|
||||
if (!window.matchMedia('(min-width: 768px)').matches) {
|
||||
return;
|
||||
var getRoleIndex = function(name) {
|
||||
for (var i = 0; i < $scope.teamRoles.length; ++i) {
|
||||
if ($scope.teamRoles[i]['id'] == name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
for (var name in $scope.organization.teams) {
|
||||
if (!$scope.organization.teams.hasOwnProperty(name) || $scope.members[name]) { continue; }
|
||||
|
||||
// Load fully async to prevent it from blocking the UI.
|
||||
(function(teamname) {
|
||||
$timeout(function() {
|
||||
loadMembersOfTeam(teamname);
|
||||
}, 1);
|
||||
})(name);
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
var loadMembersOfTeam = function(name) {
|
||||
var params = {
|
||||
'orgname': $scope.organization.name,
|
||||
'teamname': name
|
||||
};
|
||||
|
||||
$scope.members[name] = {};
|
||||
|
||||
ApiService.getOrganizationTeamMembers(null, params).then(function(resp) {
|
||||
$scope.members[name].members = resp.members;
|
||||
}, function() {
|
||||
delete $scope.members[name];
|
||||
});
|
||||
};
|
||||
|
||||
var loadOrderedTeams = function() {
|
||||
var setTeamsState = function() {
|
||||
if (!$scope.organization || !$scope.organization.ordered_teams || !$scope.isEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.orderedTeams = [];
|
||||
$scope.organization.ordered_teams.map(function(name) {
|
||||
$scope.orderedTeams.push($scope.organization.teams[name]);
|
||||
$scope.teams = [];
|
||||
$scope.organization.ordered_teams.map(function(name, index) {
|
||||
var team = $scope.organization.teams[name];
|
||||
team['ordered_team_index'] = $scope.organization.ordered_teams.length - index;
|
||||
team['role_index'] = getRoleIndex(team['role']);
|
||||
$scope.teams.push(team);
|
||||
});
|
||||
|
||||
$scope.orderedTeams = TableService.buildOrderedItems(
|
||||
$scope.teams, $scope.options,
|
||||
['name'],
|
||||
['ordered_team_index', 'member_count', 'repo_count', 'role_index']);
|
||||
};
|
||||
|
||||
$scope.$watch('organization', loadOrderedTeams);
|
||||
$scope.$watch('organization', loadTeamMembers);
|
||||
|
||||
$scope.$watch('isEnabled', loadOrderedTeams);
|
||||
$scope.$watch('isEnabled', loadTeamMembers);
|
||||
|
||||
$scope.setRole = function(role, teamname) {
|
||||
var previousRole = $scope.organization.teams[teamname].role;
|
||||
$scope.organization.teams[teamname].role = role;
|
||||
|
@ -115,9 +100,9 @@ angular.module('quay').directive('teamsManager', function () {
|
|||
|
||||
$scope.handleTeamCreated = function(created) {
|
||||
var teamname = created.name;
|
||||
created['member_count'] = 0;
|
||||
|
||||
$scope.organization.teams[teamname] = created;
|
||||
$scope.members[teamname] = {};
|
||||
$scope.members[teamname].members = [];
|
||||
$scope.organization.ordered_teams.push(teamname);
|
||||
$scope.orderedTeams.push(created);
|
||||
|
||||
|
@ -150,8 +135,8 @@ angular.module('quay').directive('teamsManager', function () {
|
|||
$scope.organization.ordered_teams.splice(index, 1);
|
||||
}
|
||||
|
||||
loadOrderedTeams();
|
||||
delete $scope.organization.teams[teamname];
|
||||
setTeamsState();
|
||||
|
||||
$scope.feedback = {
|
||||
'kind': 'success',
|
||||
|
@ -192,12 +177,7 @@ angular.module('quay').directive('teamsManager', function () {
|
|||
|
||||
ApiService.removeOrganizationMember(null, params).then(function(resp) {
|
||||
// Reset the state of the directive.
|
||||
$scope.members = {};
|
||||
$scope.orderedTeams = [];
|
||||
$scope.fullMemberList = null;
|
||||
|
||||
loadOrderedTeams();
|
||||
loadTeamMembers();
|
||||
$scope.showMembers(true);
|
||||
|
||||
callback(true);
|
||||
|
@ -215,6 +195,13 @@ angular.module('quay').directive('teamsManager', function () {
|
|||
$scope.askRemoveMember = function(memberInfo) {
|
||||
$scope.removeMemberInfo = $.extend({}, memberInfo);
|
||||
};
|
||||
|
||||
$scope.$watch('organization', setTeamsState);
|
||||
$scope.$watch('isEnabled', setTeamsState);
|
||||
|
||||
$scope.$watch('options.predicate', setTeamsState);
|
||||
$scope.$watch('options.reverse', setTeamsState);
|
||||
$scope.$watch('options.filter', setTeamsState);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Reference in a new issue