commit
ee557c944a
32 changed files with 702 additions and 233 deletions
|
@ -1527,13 +1527,13 @@ a:focus {
|
|||
-webkit-filter: grayscale(100%);
|
||||
}
|
||||
|
||||
|
||||
.co-dialog .co-tab-content {
|
||||
padding: 16px;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
|
||||
.co-dialog .co-tab-content h3 {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
|
@ -1574,3 +1574,9 @@ a:focus {
|
|||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.co-modal-body-scrollable {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
max-height: 400px;
|
||||
}
|
53
static/css/directives/ui/create-entity-dialog.css
Normal file
53
static/css/directives/ui/create-entity-dialog.css
Normal file
|
@ -0,0 +1,53 @@
|
|||
.create-entity-dialog-element .modal-body {
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.create-entity-dialog-element form {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.create-entity-dialog-element .help-text {
|
||||
color: #aaa;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.create-entity-dialog-element h4 .fa {
|
||||
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;
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
overflow: hidden;
|
||||
text-align: center;
|
||||
height: 42px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes flow-down-up {
|
||||
|
|
|
@ -2,14 +2,26 @@
|
|||
width: 90px;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
|
||||
padding: 4px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.role-group.small .btn {
|
||||
padding: 2px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.new-role-group .btn .caret {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
top: 13px;
|
||||
right: 7px;
|
||||
}
|
||||
|
||||
.role-group.small .btn .caret {
|
||||
top: 11px;
|
||||
}
|
||||
|
||||
.new-role-group .role-help-text {
|
||||
font-size: 12px;
|
||||
color: #ccc;
|
||||
|
|
98
static/directives/create-entity-dialog.html
Normal file
98
static/directives/create-entity-dialog.html
Normal file
|
@ -0,0 +1,98 @@
|
|||
<div class="create-entity-dialog-element">
|
||||
<div class="modal fade co-dialog wider">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" ng-click="hide()" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title" ng-show="view == 'enterName' || view == 'creating'">
|
||||
<i class="fa {{ entityIcon }}"></i>
|
||||
Create {{ entityTitle }}
|
||||
</h4>
|
||||
<h4 class="modal-title" ng-show="view == 'addperms' || view == 'addingperms'">
|
||||
Add permissions for <i class="fa {{ entityIcon }}"></i> {{ entity.name }}
|
||||
</h4>
|
||||
</div> <!-- /.model-header -->
|
||||
<div class="modal-body" ng-show="view == 'creating' || view == 'addingperms'">
|
||||
<div class="cor-loader"></div>
|
||||
</div>
|
||||
<div class="modal-body co-modal-body-scrollable" ng-show="view == 'addperms'">
|
||||
<span class="co-filter-box">
|
||||
<span class="filter-message" ng-if="options.filter">
|
||||
Showing {{ orderedRepositories.entries.length }} of {{ repositories.length }} repositories
|
||||
</span>
|
||||
<input class="form-control" type="text" ng-model="options.filter" placeholder="Filter Repositories...">
|
||||
</span>
|
||||
|
||||
<label>
|
||||
Select repositories in
|
||||
<span class="avatar" size="16" data="namespace.avatar"></span>
|
||||
{{ info.namespace }}:
|
||||
</label>
|
||||
|
||||
<table class="co-table" style="margin-bottom: 210px;">
|
||||
<thead>
|
||||
<td class="checkbox-col"></td>
|
||||
<td ng-class="TableService.tablePredicateClass('name', options.predicate, options.reverse)">
|
||||
<a ng-click="TableService.orderBy('name', options)">Repository Name</a>
|
||||
</td>
|
||||
<td>Permission</td>
|
||||
<td ng-class="TableService.tablePredicateClass('last_modified_datetime', options.predicate, options.reverse)">
|
||||
<a ng-click="TableService.orderBy('last_modified_datetime', options)">Last Updated</a>
|
||||
</td>
|
||||
</thead>
|
||||
|
||||
<tr class="co-checkable-row"
|
||||
ng-repeat="repo in orderedRepositories.visibleEntries"
|
||||
ng-class="checkedRepos.isChecked(repo, checkedRepos.checked) ? 'checked' : ''"
|
||||
bindonce>
|
||||
<td>
|
||||
<span class="cor-checkable-item" controller="checkedRepos" item="repo"></span>
|
||||
</td>
|
||||
<td>
|
||||
<i class="fa fa-hdd-o"></i>
|
||||
<span bo-text="repo.name"></span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="role-group small" current-role="repo.permission"
|
||||
roles="repoRolesOrNone"
|
||||
role-changed="setRole(role, repo)"></span>
|
||||
</td>
|
||||
<td>
|
||||
<span ng-if="repo.last_modified">
|
||||
{{ repo.last_modified * 1000 | amCalendar }}
|
||||
</span>
|
||||
<span class="empty" ng-if="!repo.last_modified">(Empty Repository)</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="empty" ng-if="!orderedRepositories.entries.length"
|
||||
style="margin-top: 20px;">
|
||||
<div class="empty-primary-msg">No matching repositories found.</div>
|
||||
<div class="empty-secondary-msg">Try expanding your filtering terms.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body" ng-show="view == 'enterName'">
|
||||
<form name="enterNameForm" ng-submit="createEntity()">
|
||||
<label>Provide a name for your new {{ entityTitle }}:</label>
|
||||
<input type="text" class="form-control" ng-model="entityName" ng-pattern="entityNameRegexObj" required>
|
||||
<div class="help-text">
|
||||
Choose a name to inform your teammates
|
||||
about this {{ entityTitle }}. Must match {{ entityNameRegex }}.
|
||||
</div>
|
||||
</form>
|
||||
</div> <!-- /.modal-body -->
|
||||
<div class="modal-footer" ng-show="view == 'addperms'">
|
||||
<button type="button" class="btn btn-primary" ng-click="addPermissions()"
|
||||
ng-show="checkedRepos.checked.length">Add permissions</button>
|
||||
<button type="button" class="btn btn-default" ng-click="hide()">Close</button>
|
||||
</div> <!-- /.footer-body -->
|
||||
<div class="modal-footer" ng-show="view == 'enterName'">
|
||||
<button type="button" class="btn btn-primary" ng-click="createEntity()"
|
||||
ng-disabled="enterNameForm.$invalid">Create {{ entityTitle }}</button>
|
||||
<button type="button" class="btn btn-default" ng-click="hide()">Cancel</button>
|
||||
</div> <!-- /.footer-body -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
9
static/directives/create-robot-dialog.html
Normal file
9
static/directives/create-robot-dialog.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
<div class="create-robot-dialog-element">
|
||||
<div ng-if="info">
|
||||
<div class="create-entity-dialog" info="info" entity-title="robot account"
|
||||
entity-kind="user"
|
||||
entity-icon="ci-robot" entity-name-regex="{{ ROBOT_PATTERN }}"
|
||||
entity-create-requested="createRobot(name, callback)"
|
||||
entity-create-completed="robotFinished(entity)"></div>
|
||||
</div>
|
||||
</div>
|
9
static/directives/create-team-dialog.html
Normal file
9
static/directives/create-team-dialog.html
Normal file
|
@ -0,0 +1,9 @@
|
|||
<div class="create-team-dialog-element">
|
||||
<div ng-if="info">
|
||||
<div class="create-entity-dialog" info="info" entity-title="team"
|
||||
entity-kind="team"
|
||||
entity-icon="fa-group" entity-name-regex="{{ TEAM_PATTERN }}"
|
||||
entity-create-requested="createTeam(name, callback)"
|
||||
entity-create-completed="teamFinished(entity)"></div>
|
||||
</div>
|
||||
</div>
|
|
@ -14,12 +14,12 @@
|
|||
</li>
|
||||
|
||||
<li role="presentation" ng-show="includeTeams && isOrganization && !lazyLoading && isAdmin">
|
||||
<a role="menuitem" class="new-action" tabindex="-1" ng-click="createTeam()">
|
||||
<a role="menuitem" class="new-action" tabindex="-1" ng-click="askCreateTeam()">
|
||||
<i class="fa fa-group"></i> Create team
|
||||
</a>
|
||||
</li>
|
||||
<li role="presentation" ng-show="includeRobots && !lazyLoading && isAdmin">
|
||||
<a role="menuitem" class="new-action" tabindex="-1" ng-click="createRobot()">
|
||||
<a role="menuitem" class="new-action" tabindex="-1" ng-click="askCreateRobot()">
|
||||
<i class="fa ci-robot"></i>
|
||||
Create robot account
|
||||
</a>
|
||||
|
@ -70,4 +70,8 @@
|
|||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="create-team-dialog" info="createTeamInfo"
|
||||
team-created="handleTeamCreated(team)"></div>
|
||||
<div class="create-robot-dialog" info="createRobotInfo"
|
||||
robot-created="handleRobotCreated(robot)"></div>
|
||||
</span>
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
<td class="first-col">Pull Credentials:</td>
|
||||
<td>
|
||||
<div class="entity-search" namespace="repository.namespace"
|
||||
for-repository="repository"
|
||||
placeholder="'Choose Pull Credentials'"
|
||||
allowed-entities="['robot']"
|
||||
clear-value="clearCounter"
|
||||
|
|
|
@ -85,12 +85,12 @@
|
|||
Namespace {{ getNamespace(currentPageContext) }}
|
||||
</li>
|
||||
<li ng-if="isOrganization(getNamespace(currentPageContext)) && canAdmin(getNamespace(currentPageContext))">
|
||||
<a ng-click="createTeam(currentPageContext)">
|
||||
<a ng-click="askCreateTeam(currentPageContext)">
|
||||
<i class="fa fa-group"></i> New Team
|
||||
</a>
|
||||
</li>
|
||||
<li ng-if="canAdmin(getNamespace(currentPageContext))">
|
||||
<a ng-click="createRobot(currentPageContext)">
|
||||
<a ng-click="askCreateRobot(currentPageContext)">
|
||||
<i class="fa ci-robot"></i> New Robot Account
|
||||
</a>
|
||||
</li>
|
||||
|
@ -207,6 +207,14 @@
|
|||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="create-robot-dialog" info="createRobotInfo"
|
||||
robot-created="handleRobotCreated(robot, currentPageContext)">
|
||||
</div>
|
||||
|
||||
<div class="create-team-dialog" info="createTeamInfo"
|
||||
team-created="handleTeamCreated(team, currentPageContext)">
|
||||
</div>
|
||||
|
||||
<div class="dockerfile-build-dialog"
|
||||
show-now="showBuildDialogCounter"
|
||||
repository="currentPageContext.repository"
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr ng-repeat="repository in orderedRepositories">
|
||||
<tr ng-repeat="repository in orderedRepositories.entries">
|
||||
<td class="repo-name-icon">
|
||||
<span class="avatar" size="24" data="getAvatarData(repository.namespace)"></span>
|
||||
<a href="/repository/{{ repository.namespace }}/{{ repository.name }}">
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
|
||||
<span class="co-filter-box">
|
||||
<span class="page-controls" total-count="tags.length" current-page="options.page" page-size="tagsPerPage"></span>
|
||||
<input class="form-control" type="text" ng-model="options.tagFilter" placeholder="Filter Tags...">
|
||||
<input class="form-control" type="text" ng-model="options.filter" placeholder="Filter Tags...">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -106,6 +106,8 @@
|
|||
<tr class="add-row" ng-if-media="'(min-width: 768px)'">
|
||||
<td id="add-entity-permission" class="admin-search">
|
||||
<span class="entity-search" namespace="repository.namespace"
|
||||
for-repository="repository"
|
||||
skip-permissions="true"
|
||||
placeholder="'Select a ' + (repository.is_organization ? 'team or ' : '') + 'user...'"
|
||||
current-entity="addPermissionInfo.entity"></span>
|
||||
</td>
|
||||
|
@ -125,6 +127,8 @@
|
|||
<!-- Mobile add permissions -->
|
||||
<div class="mobile-add-row" ng-if-media="'(max-width: 767px)'">
|
||||
<span class="entity-search" namespace="repository.namespace"
|
||||
for-repository="repository"
|
||||
skip-permissions="true"
|
||||
placeholder="'Select a ' + (repository.is_organization ? 'team or ' : '') + 'user...'"
|
||||
current-entity="addPermissionInfo.entity"
|
||||
pull-right="true"></span>
|
||||
|
|
|
@ -4,12 +4,9 @@
|
|||
|
||||
<div ng-show="!loading">
|
||||
<div class="manager-header" header-title="Robot Accounts">
|
||||
<span class="popup-input-button" pattern="ROBOT_PATTERN"
|
||||
placeholder="'Robot Account Name'"
|
||||
submitted="createRobot(value)"
|
||||
ng-show="isEnabled">
|
||||
<i class="fa fa-plus"></i> Create Robot Account
|
||||
</span>
|
||||
<button class="btn btn-primary" ng-click="askCreateRobot()" ng-show="isEnabled">
|
||||
<i class="fa fa-plus" style="margin-right: 4px;"></i> Create Robot Account
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="section-description-header">
|
||||
|
@ -134,5 +131,6 @@
|
|||
</table>
|
||||
</div>
|
||||
|
||||
<div class="create-robot-dialog" info="createRobotInfo" robot-created="robotCreated()"></div>
|
||||
<div class="robot-credentials-dialog" info="robotDisplayInfo"></div>
|
||||
</div>
|
||||
|
|
|
@ -13,23 +13,17 @@
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="popup-input-button visible-xs" ng-if="!showingMembers"
|
||||
pattern="TEAM_PATTERN" placeholder="'Team Name'"
|
||||
submitted="createTeam(value)" ng-show="organization.is_admin">
|
||||
<i class="fa fa-plus" style="margin-right: 6px;"></i> Create New Team
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Teams List -->
|
||||
<div ng-show="!showingMembers">
|
||||
<div class="row" style="margin-left: 0px; margin-right: 0px;">
|
||||
<span class="popup-input-button hidden-xs"
|
||||
pattern="TEAM_PATTERN" placeholder="'Team Name'"
|
||||
submitted="createTeam(value)" ng-show="organization.is_admin"
|
||||
style="margin-bottom: 10px;">
|
||||
<i class="fa fa-plus" style="margin-right: 6px;"></i> Create New Team
|
||||
</span>
|
||||
<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>
|
||||
|
||||
<div class="row hidden-xs">
|
||||
|
@ -155,6 +149,8 @@
|
|||
</table>
|
||||
</div>
|
||||
|
||||
<div class="create-team-dialog" info="createTeamInfo" team-created="handleTeamCreated(team)"></div>
|
||||
|
||||
<!-- Remove member confirm -->
|
||||
<div class="cor-confirm-dialog"
|
||||
dialog-context="removeMemberInfo"
|
||||
|
|
|
@ -18,9 +18,7 @@ angular.module('quay').directive('repoPanelTags', function () {
|
|||
|
||||
'getImages': '&getImages'
|
||||
},
|
||||
controller: function($scope, $element, $filter, $location, ApiService, UIService, VulnerabilityService) {
|
||||
var orderBy = $filter('orderBy');
|
||||
|
||||
controller: function($scope, $element, $filter, $location, ApiService, UIService, VulnerabilityService, TableService) {
|
||||
$scope.maxTrackCount = 5;
|
||||
|
||||
$scope.checkedTags = UIService.createCheckStateController([], 'name');
|
||||
|
@ -45,32 +43,26 @@ angular.module('quay').directive('repoPanelTags', function () {
|
|||
var setTagState = function() {
|
||||
if (!$scope.repository || !$scope.selectedTags) { return; }
|
||||
|
||||
var tags = [];
|
||||
// Build a list of all the tags, with extending information.
|
||||
var allTags = [];
|
||||
|
||||
// Build a list of tags and filtered tags.
|
||||
for (var tag in $scope.repository.tags) {
|
||||
if (!$scope.repository.tags.hasOwnProperty(tag)) { continue; }
|
||||
|
||||
var tagData = $scope.repository.tags[tag];
|
||||
var tagInfo = $.extend(tagData, {
|
||||
'name': tag,
|
||||
'last_modified_datetime': (new Date(tagData.last_modified || 0)).valueOf() * (-1)
|
||||
'last_modified_datetime': TableService.getReversedTimestamp(tagData.last_modified)
|
||||
});
|
||||
|
||||
allTags.push(tagInfo);
|
||||
|
||||
if (!$scope.options.tagFilter || tag.indexOf($scope.options.tagFilter) >= 0 ||
|
||||
tagInfo.image_id.indexOf($scope.options.tagFilter) >= 0) {
|
||||
tags.push(tagInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the tags by the predicate and the reverse, and map the information.
|
||||
var imageIDs = [];
|
||||
var ordered = orderBy(tags, $scope.options.predicate, $scope.options.reverse);
|
||||
var checked = [];
|
||||
var ordered = TableService.buildOrderedItems(allTags, $scope.options,
|
||||
['name'], ['last_modified_datetime', 'size']).entries;
|
||||
|
||||
var checked = [];
|
||||
var imageMap = {};
|
||||
var imageIndexMap = {};
|
||||
for (var i = 0; i < ordered.length; ++i) {
|
||||
|
@ -175,7 +167,7 @@ angular.module('quay').directive('repoPanelTags', function () {
|
|||
|
||||
$scope.$watch('options.predicate', setTagState);
|
||||
$scope.$watch('options.reverse', setTagState);
|
||||
$scope.$watch('options.tagFilter', setTagState);
|
||||
$scope.$watch('options.filter', setTagState);
|
||||
|
||||
$scope.$watch('options.page', function(page) {
|
||||
if (page != null && $scope.checkedTags) {
|
||||
|
|
202
static/js/directives/ui/create-entity-dialog.js
Normal file
202
static/js/directives/ui/create-entity-dialog.js
Normal file
|
@ -0,0 +1,202 @@
|
|||
/**
|
||||
* An element which displays a create entity dialog.
|
||||
*/
|
||||
angular.module('quay').directive('createEntityDialog', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/create-entity-dialog.html',
|
||||
replace: false,
|
||||
transclude: true,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'info': '=info',
|
||||
|
||||
'entityKind': '@entityKind',
|
||||
'entityTitle': '@entityTitle',
|
||||
'entityIcon': '@entityIcon',
|
||||
'entityNameRegex': '@entityNameRegex',
|
||||
|
||||
'entityCreateRequested': '&entityCreateRequested',
|
||||
'entityCreateCompleted': '&entityCreateCompleted'
|
||||
},
|
||||
|
||||
controller: function($scope, $element, ApiService, UIService, TableService, RolesService, UserService) {
|
||||
$scope.TableService = TableService;
|
||||
|
||||
$scope.options = {
|
||||
'predicate': 'last_modified_datetime',
|
||||
'reverse': false,
|
||||
'filter': ''
|
||||
};
|
||||
|
||||
var handleRepoCheckChange = function() {
|
||||
$scope.repositories.forEach(function(repo) {
|
||||
if ($scope.checkedRepos.isChecked(repo)) {
|
||||
if (repo['permission'] == 'none') {
|
||||
repo['permission'] = 'read';
|
||||
}
|
||||
} else {
|
||||
repo['permission'] = 'none';
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
if ($scope.inBody) {
|
||||
document.body.removeChild($element[0]);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.setRole = function(role, repo) {
|
||||
repo['permission'] = role;
|
||||
|
||||
if (role == 'none') {
|
||||
$scope.checkedRepos.uncheckItem(repo);
|
||||
} else {
|
||||
$scope.checkedRepos.checkItem(repo);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.hide = function() {
|
||||
$element.find('.modal').modal('hide');
|
||||
if ($scope.entity) {
|
||||
$scope.entityCreateCompleted({'entity': $scope.entity});
|
||||
$scope.entity = null;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.show = function() {
|
||||
$scope.entityName = null;
|
||||
$scope.entity = null;
|
||||
$scope.creating = false;
|
||||
$scope.view = 'enterName';
|
||||
$scope.enterNameForm.$setPristine(true);
|
||||
|
||||
// Move the dialog to the body to prevent it from nesting if called
|
||||
// from within another dialog.
|
||||
$element.find('.modal').modal({});
|
||||
$scope.inBody = true;
|
||||
document.body.appendChild($element[0]);
|
||||
};
|
||||
|
||||
var setRepoState = function() {
|
||||
if (!$scope.repositories) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.orderedRepositories = TableService.buildOrderedItems($scope.repositories, $scope.options,
|
||||
['name', 'permission'],
|
||||
['last_modified_datetime']);
|
||||
};
|
||||
|
||||
var entityCreateCallback = function(entity) {
|
||||
if (!entity || $scope.info.skip_permissions) {
|
||||
$scope.entity = entity;
|
||||
$scope.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
// Load the repositories under the entity's namespace.
|
||||
var params = {
|
||||
'namespace': $scope.info.namespace,
|
||||
'last_modified': true
|
||||
};
|
||||
|
||||
ApiService.listRepos(null, params).then(function(resp) {
|
||||
$scope.view = 'addperms';
|
||||
$scope.entity = entity;
|
||||
|
||||
var repos = [];
|
||||
resp['repositories'].forEach(function(repo) {
|
||||
repos.push({
|
||||
'namespace': repo.namespace,
|
||||
'name': repo.name,
|
||||
'last_modified': repo.last_modified,
|
||||
'last_modified_datetime': TableService.getReversedTimestamp(repo.last_modified),
|
||||
'permission': 'none'
|
||||
});
|
||||
});
|
||||
|
||||
if (repos.length == 0) {
|
||||
$scope.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.repositories = repos;
|
||||
$scope.checkedRepos = UIService.createCheckStateController($scope.repositories, 'name');
|
||||
$scope.checkedRepos.listen(handleRepoCheckChange);
|
||||
|
||||
if ($scope.info.repository) {
|
||||
repos.forEach(function(repo) {
|
||||
if (repo['namespace'] == $scope.info.repository.namespace &&
|
||||
repo['name'] == $scope.info.repository.name) {
|
||||
$scope.checkedRepos.checkItem(repo);
|
||||
$scope.options.filter = $scope.info.repository.name;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setRepoState();
|
||||
}, ApiService.errorDisplay('Could not load repositories'));
|
||||
};
|
||||
|
||||
$scope.addPermissions = function() {
|
||||
$scope.view = 'addingperms';
|
||||
|
||||
var repos = $scope.checkedRepos.checked;
|
||||
var counter = 0;
|
||||
|
||||
var addPerm = function() {
|
||||
if (counter >= repos.length) {
|
||||
$scope.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
var repo = repos[counter];
|
||||
RolesService.setRepositoryRole(repo, repo.permission, $scope.entityKind, $scope.entity.name,
|
||||
function(status) {
|
||||
if (status) {
|
||||
counter++;
|
||||
addPerm();
|
||||
} else {
|
||||
$scope.hide();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
addPerm();
|
||||
};
|
||||
|
||||
$scope.createEntity = function() {
|
||||
$scope.view = 'creating';
|
||||
$scope.entityCreateRequested({
|
||||
'name': $scope.entityName,
|
||||
'callback': entityCreateCallback
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$watch('options.predicate', setRepoState);
|
||||
$scope.$watch('options.reverse', setRepoState);
|
||||
$scope.$watch('options.filter', setRepoState);
|
||||
|
||||
$scope.$watch('entityNameRegex', function(r) {
|
||||
if (r) {
|
||||
$scope.entityNameRegexObj = new RegExp(r);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$watch('info', function(info) {
|
||||
if (!info || !info.namespace) {
|
||||
$scope.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.namespace = UserService.getNamespace(info.namespace);
|
||||
if ($scope.namespace) {
|
||||
$scope.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
});
|
43
static/js/directives/ui/create-robot-dialog.js
Normal file
43
static/js/directives/ui/create-robot-dialog.js
Normal file
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* An element which displays a dialog for creating a robot account.
|
||||
*/
|
||||
angular.module('quay').directive('createRobotDialog', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/create-robot-dialog.html',
|
||||
replace: false,
|
||||
transclude: true,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'info': '=info',
|
||||
'robotCreated': '&robotCreated'
|
||||
},
|
||||
controller: function($scope, $element, ApiService, UserService) {
|
||||
$scope.ROBOT_PATTERN = ROBOT_PATTERN;
|
||||
|
||||
$scope.robotFinished = function(robot) {
|
||||
$scope.robotCreated({'robot': robot});
|
||||
};
|
||||
|
||||
$scope.createRobot = function(name, callback) {
|
||||
var organization = $scope.info.namespace;
|
||||
if (!UserService.isOrganization(organization)) {
|
||||
organization = null;
|
||||
}
|
||||
|
||||
var params = {
|
||||
'robot_shortname': name
|
||||
};
|
||||
|
||||
var errorDisplay = ApiService.errorDisplay('Cannot create robot account', function() {
|
||||
callback(null);
|
||||
});
|
||||
|
||||
ApiService.createRobot(organization, null, params).then(function(resp) {
|
||||
callback(resp);
|
||||
}, errorDisplay);
|
||||
};
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
});
|
44
static/js/directives/ui/create-team-dialog.js
Normal file
44
static/js/directives/ui/create-team-dialog.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* An element which displays a dialog for creating a team.
|
||||
*/
|
||||
angular.module('quay').directive('createTeamDialog', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/create-team-dialog.html',
|
||||
replace: false,
|
||||
transclude: true,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'info': '=info',
|
||||
'teamCreated': '&teamCreated'
|
||||
},
|
||||
controller: function($scope, $element, ApiService, UserService) {
|
||||
$scope.TEAM_PATTERN = TEAM_PATTERN;
|
||||
|
||||
$scope.teamFinished = function(team) {
|
||||
$scope.teamCreated({'team': team});
|
||||
};
|
||||
|
||||
$scope.createTeam = function(name, callback) {
|
||||
var data = {
|
||||
'name': name,
|
||||
'role': 'member'
|
||||
};
|
||||
|
||||
var params = {
|
||||
'orgname': $scope.info.namespace,
|
||||
'teamname': name
|
||||
};
|
||||
|
||||
var errorDisplay = ApiService.errorDisplay('Cannot create team', function() {
|
||||
callback(null);
|
||||
});
|
||||
|
||||
ApiService.updateOrganizationTeam(data, params).then(function(resp) {
|
||||
callback(resp);
|
||||
}, errorDisplay);
|
||||
};
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
});
|
|
@ -22,6 +22,12 @@ angular.module('quay').directive('credentialsDialog', function () {
|
|||
$scope.rkt = {};
|
||||
$scope.docker = {};
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
if ($scope.inBody) {
|
||||
document.body.removeChild($element[0]);
|
||||
}
|
||||
});
|
||||
|
||||
// Generate a unique ID for the dialog.
|
||||
if (!$rootScope.credentialsDialogCounter) {
|
||||
$rootScope.credentialsDialogCounter = 0;
|
||||
|
@ -36,6 +42,11 @@ angular.module('quay').directive('credentialsDialog', function () {
|
|||
|
||||
$scope.show = function() {
|
||||
$element.find('.modal').modal({});
|
||||
|
||||
// Move the dialog to the body to prevent it from being affected
|
||||
// by being placed inside other tables.
|
||||
$scope.inBody = true;
|
||||
document.body.appendChild($element[0]);
|
||||
};
|
||||
|
||||
$scope.$watch('credentials', function(credentials) {
|
||||
|
|
|
@ -18,6 +18,8 @@ angular.module('quay').directive('entitySearch', function () {
|
|||
scope: {
|
||||
'namespace': '=namespace',
|
||||
'placeholder': '=placeholder',
|
||||
'forRepository': '=forRepository',
|
||||
'skipPermissions': '=skipPermissions',
|
||||
|
||||
// Default: ['user', 'team', 'robot']
|
||||
'allowedEntities': '=allowedEntities',
|
||||
|
@ -41,7 +43,7 @@ angular.module('quay').directive('entitySearch', function () {
|
|||
// True if the menu should pull right.
|
||||
'pullRight': '@pullRight'
|
||||
},
|
||||
controller: function($rootScope, $scope, $element, Restangular, UserService, ApiService, UtilService, Config, CreateService) {
|
||||
controller: function($rootScope, $scope, $element, Restangular, UserService, ApiService, UtilService, Config) {
|
||||
$scope.lazyLoading = true;
|
||||
|
||||
$scope.teams = null;
|
||||
|
@ -55,6 +57,8 @@ angular.module('quay').directive('entitySearch', function () {
|
|||
$scope.includeOrgs = false;
|
||||
|
||||
$scope.currentEntityInternal = $scope.currentEntity;
|
||||
$scope.createRobotInfo = null;
|
||||
$scope.createTeamInfo = null;
|
||||
|
||||
$scope.Config = Config;
|
||||
|
||||
|
@ -91,18 +95,30 @@ angular.module('quay').directive('entitySearch', function () {
|
|||
}
|
||||
};
|
||||
|
||||
$scope.createTeam = function() {
|
||||
CreateService.askCreateTeam($scope.namespace, function(created) {
|
||||
$scope.setEntity(created.name, 'team', false, created.avatar);
|
||||
$scope.teams[created.name] = created;
|
||||
});
|
||||
$scope.askCreateTeam = function() {
|
||||
$scope.createTeamInfo = {
|
||||
'namespace': $scope.namespace,
|
||||
'repository': $scope.forRepository,
|
||||
'skip_permissions': $scope.skipPermissions
|
||||
};
|
||||
};
|
||||
|
||||
$scope.createRobot = function() {
|
||||
CreateService.askCreateRobot($scope.namespace, function(created) {
|
||||
$scope.setEntity(created.name, 'user', true, created.avatar);
|
||||
$scope.robots.push(created);
|
||||
});
|
||||
$scope.askCreateRobot = function() {
|
||||
$scope.createRobotInfo = {
|
||||
'namespace': $scope.namespace,
|
||||
'repository': $scope.forRepository,
|
||||
'skip_permissions': $scope.skipPermissions
|
||||
};
|
||||
};
|
||||
|
||||
$scope.handleTeamCreated = function(created) {
|
||||
$scope.setEntity(created.name, 'team', false, created.avatar);
|
||||
$scope.teams[created.name] = created;
|
||||
};
|
||||
|
||||
$scope.handleRobotCreated = function(created) {
|
||||
$scope.setEntity(created.name, 'user', true, created.avatar);
|
||||
$scope.robots.push(created);
|
||||
};
|
||||
|
||||
$scope.setEntity = function(name, kind, is_robot, avatar) {
|
||||
|
|
|
@ -13,7 +13,7 @@ angular.module('quay').directive('headerBar', function () {
|
|||
scope: {
|
||||
},
|
||||
controller: function($rootScope, $scope, $element, $location, $timeout, hotkeys, UserService,
|
||||
PlanService, ApiService, NotificationService, Config, CreateService, Features,
|
||||
PlanService, ApiService, NotificationService, Config, Features,
|
||||
DocumentationService, ExternalLoginService) {
|
||||
|
||||
$scope.externalSigninUrl = ExternalLoginService.getSingleSigninUrl();
|
||||
|
@ -268,24 +268,36 @@ angular.module('quay').directive('headerBar', function () {
|
|||
$location.url('/repository/' + context.repository.namespace + '/' + context.repository.name + '/build/' + build.id);
|
||||
};
|
||||
|
||||
$scope.createRobot = function(context) {
|
||||
$scope.handleRobotCreated = function(created, context) {
|
||||
var namespace = $scope.getNamespace(context);
|
||||
CreateService.askCreateRobot(namespace, function(created) {
|
||||
if (UserService.isOrganization(namespace)) {
|
||||
$location.url('/organization/' + namespace + '?tab=robots&showRobot=' + created.name);
|
||||
} else {
|
||||
$location.url('/user/' + namespace + '?tab=robots&showRobot=' + created.name);
|
||||
}
|
||||
});
|
||||
if (UserService.isOrganization(namespace)) {
|
||||
$location.url('/organization/' + namespace + '?tab=robots&showRobot=' + created.name);
|
||||
} else {
|
||||
$location.url('/user/' + namespace + '?tab=robots&showRobot=' + created.name);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.createTeam = function(context) {
|
||||
$scope.handleTeamCreated = function(created, context) {
|
||||
var namespace = $scope.getNamespace(context);
|
||||
$location.url('/organization/' + namespace + '/teams/' + created.name);
|
||||
};
|
||||
|
||||
$scope.askCreateRobot = function(context) {
|
||||
var namespace = $scope.getNamespace(context);
|
||||
if (!namespace || !UserService.isNamespaceAdmin(namespace)) { return; }
|
||||
|
||||
CreateService.askCreateTeam(namespace, function(created) {
|
||||
$location.url('/organization/' + namespace + '/teams/' + created.name);
|
||||
});
|
||||
$scope.createRobotInfo = {
|
||||
'namespace': namespace
|
||||
};
|
||||
};
|
||||
|
||||
$scope.askCreateTeam = function(context) {
|
||||
var namespace = $scope.getNamespace(context);
|
||||
if (!namespace || !UserService.isNamespaceAdmin(namespace)) { return; }
|
||||
|
||||
$scope.createTeamInfo = {
|
||||
'namespace': namespace
|
||||
};
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -13,30 +13,22 @@ angular.module('quay').directive('repoListTable', function () {
|
|||
'namespaces': '=namespaces',
|
||||
'starToggled': '&starToggled'
|
||||
},
|
||||
controller: function($scope, $element, $filter) {
|
||||
var orderBy = $filter('orderBy');
|
||||
|
||||
controller: function($scope, $element, $filter, TableService) {
|
||||
$scope.repositories = null;
|
||||
$scope.orderedRepositories = [];
|
||||
|
||||
$scope.maxPopularity = 0;
|
||||
$scope.options = {
|
||||
'predicate': 'popularity',
|
||||
'reverse': true
|
||||
'reverse': false,
|
||||
'filter': null
|
||||
};
|
||||
|
||||
var buildOrderedRepositories = function() {
|
||||
if (!$scope.repositories) { return; }
|
||||
var modifier = $scope.options.reverse ? '-' : '';
|
||||
var fields = [modifier + $scope.options.predicate];
|
||||
|
||||
// Secondary ordering by full name.
|
||||
if ($scope.options.predicate != 'full_name') {
|
||||
fields.push('full_name');
|
||||
}
|
||||
|
||||
var ordered = orderBy($scope.repositories, fields, false);
|
||||
$scope.orderedRepositories = ordered;
|
||||
$scope.orderedRepositories = TableService.buildOrderedItems($scope.repositories, $scope.options,
|
||||
[], ['last_modified_datetime', 'popularity'])
|
||||
};
|
||||
|
||||
$scope.tablePredicateClass = function(name, predicate, reverse) {
|
||||
|
@ -92,7 +84,7 @@ angular.module('quay').directive('repoListTable', function () {
|
|||
(resource.value || []).forEach(function(repository) {
|
||||
var repositoryInfo = $.extend(repository, {
|
||||
'full_name': repository.namespace + '/' + repository.name,
|
||||
'last_modified_datetime': (new Date(repository.last_modified || 0)).valueOf() * (-1)
|
||||
'last_modified_datetime': TableService.getReversedTimestamp(repository.last_modified),
|
||||
});
|
||||
|
||||
$scope.repositories.push(repositoryInfo);
|
||||
|
|
|
@ -28,7 +28,7 @@ angular.module('quay').directive('repositoryPermissionsTable', function () {
|
|||
'repository': '=repository',
|
||||
'isEnabled': '=isEnabled'
|
||||
},
|
||||
controller: function($scope, $element, ApiService, Restangular, UtilService, RolesService) {
|
||||
controller: function($scope, $element, ApiService, RolesService) {
|
||||
$scope.permissionResources = {'team': {}, 'user': {}};
|
||||
$scope.permissionCache = {};
|
||||
$scope.permissions = {};
|
||||
|
@ -69,13 +69,6 @@ angular.module('quay').directive('repositoryPermissionsTable', function () {
|
|||
|
||||
loadAllPermissions();
|
||||
|
||||
var getPermissionEndpoint = function(entityName, kind) {
|
||||
var namespace = $scope.repository.namespace;
|
||||
var name = $scope.repository.name;
|
||||
var url = UtilService.getRestUrl('repository', namespace, name, 'permissions', kind, entityName);
|
||||
return Restangular.one(url);
|
||||
};
|
||||
|
||||
$scope.buildEntityForPermission = function(permission, kind) {
|
||||
var key = permission.name + ':' + kind;
|
||||
if ($scope.permissionCache[key]) {
|
||||
|
@ -146,51 +139,36 @@ angular.module('quay').directive('repositoryPermissionsTable', function () {
|
|||
};
|
||||
|
||||
$scope.deleteRole = function(entityName, kind) {
|
||||
var errorHandler = ApiService.errorDisplay('Cannot change permission', function(resp) {
|
||||
if (resp.status == 409) {
|
||||
return 'Cannot change permission as you do not have the authority';
|
||||
RolesService.deleteRepositoryRole($scope.repository, kind, entityName, function(status) {
|
||||
if (status) {
|
||||
delete $scope.permissions[kind][entityName];
|
||||
}
|
||||
});
|
||||
|
||||
var endpoint = getPermissionEndpoint(entityName, kind);
|
||||
endpoint.customDELETE().then(function() {
|
||||
delete $scope.permissions[kind][entityName];
|
||||
}, errorHandler);
|
||||
};
|
||||
|
||||
$scope.addRole = function(entityName, role, kind, opt_callback) {
|
||||
var permission = {
|
||||
'role': role,
|
||||
};
|
||||
|
||||
var errorHandler = ApiService.errorDisplay('Cannot change permission', function() {
|
||||
opt_callback && opt_callback(false);
|
||||
RolesService.setRepositoryRole($scope.repository, role, kind, entityName, function(status, result) {
|
||||
$scope.addPermissionInfo = {
|
||||
'role': readRole
|
||||
};
|
||||
|
||||
if (status) {
|
||||
$scope.permissions[kind][entityName] = result;
|
||||
}
|
||||
|
||||
opt_callback && opt_callback(status);
|
||||
});
|
||||
|
||||
var endpoint = getPermissionEndpoint(entityName, kind);
|
||||
endpoint.customPUT(permission).then(function(result) {
|
||||
$scope.permissions[kind][entityName] = result;
|
||||
$scope.addPermissionInfo = {
|
||||
'role': readRole
|
||||
};
|
||||
opt_callback && opt_callback(true)
|
||||
}, errorHandler);
|
||||
};
|
||||
|
||||
$scope.setRole = function(role, entityName, kind) {
|
||||
var errorDisplay = ApiService.errorDisplay(function(resp) {
|
||||
$scope.permissions[kind][entityName] = {'role': currentRole};
|
||||
var currentRole = $scope.permissions[kind][entityName].role;
|
||||
RolesService.setRepositoryRole($scope.repository, role, kind, entityName, function(status) {
|
||||
if (status) {
|
||||
$scope.permissions[kind][entityName]['role'] = role;
|
||||
} else {
|
||||
$scope.permissions[kind][entityName]['role'] = currentRole;
|
||||
}
|
||||
});
|
||||
|
||||
var permission = $scope.permissions[kind][entityName];
|
||||
var currentRole = permission.role;
|
||||
permission.role = role;
|
||||
|
||||
var endpoint = getPermissionEndpoint(entityName, kind);
|
||||
endpoint.customPUT(permission).then(function() {}, errorDisplay);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -13,15 +13,14 @@ angular.module('quay').directive('robotsManager', function () {
|
|||
'user': '=user',
|
||||
'isEnabled': '=isEnabled'
|
||||
},
|
||||
controller: function($scope, $element, ApiService, $routeParams, $location, CreateService,
|
||||
Config, $rootScope) {
|
||||
$scope.ROBOT_PATTERN = ROBOT_PATTERN;
|
||||
|
||||
controller: function($scope, $element, ApiService, $routeParams, $location, Config, $rootScope) {
|
||||
$scope.robots = null;
|
||||
$scope.loading = false;
|
||||
$scope.Config = Config;
|
||||
$scope.feedback = null;
|
||||
|
||||
$scope.robotDisplayInfo = null;
|
||||
$scope.createRobotInfo = null;
|
||||
|
||||
// Listen for route changes and update the tabs accordingly.
|
||||
var locationListener = $rootScope.$on('$routeUpdate', function(){
|
||||
|
@ -96,22 +95,10 @@ angular.module('quay').directive('robotsManager', function () {
|
|||
return name.substr(0, plus);
|
||||
};
|
||||
|
||||
$scope.createRobot = function(name) {
|
||||
if (!name) { return; }
|
||||
|
||||
CreateService.createRobotAccount(ApiService, !!$scope.organization, $scope.organization ? $scope.organization.name : '', name,
|
||||
function(created) {
|
||||
created.teams = [];
|
||||
created.repositories = [];
|
||||
$scope.robots.push(created);
|
||||
$scope.feedback = {
|
||||
'kind': 'success',
|
||||
'message': 'Robot account {robot} was created',
|
||||
'data': {
|
||||
'robot': name
|
||||
}
|
||||
};
|
||||
});
|
||||
$scope.askCreateRobot = function() {
|
||||
$scope.createRobotInfo = {
|
||||
'namespace': $scope.organization ? $scope.organization.name : $scope.user.username
|
||||
};
|
||||
};
|
||||
|
||||
$scope.deleteRobot = function(info) {
|
||||
|
@ -131,7 +118,6 @@ angular.module('quay').directive('robotsManager', function () {
|
|||
}, ApiService.errorDisplay('Cannot delete robot account'));
|
||||
};
|
||||
|
||||
|
||||
$scope.askDeleteRobot = function(info) {
|
||||
bootbox.confirm('Are you sure you want to delete robot ' + info.name + '?', function(resp) {
|
||||
if (resp) {
|
||||
|
@ -140,6 +126,10 @@ angular.module('quay').directive('robotsManager', function () {
|
|||
});
|
||||
};
|
||||
|
||||
$scope.robotCreated = function() {
|
||||
update();
|
||||
};
|
||||
|
||||
var update = function() {
|
||||
if (!$scope.user && !$scope.organization) { return; }
|
||||
if ($scope.loading || !$scope.isEnabled) { return; }
|
||||
|
|
|
@ -12,8 +12,7 @@ angular.module('quay').directive('teamsManager', function () {
|
|||
'organization': '=organization',
|
||||
'isEnabled': '=isEnabled'
|
||||
},
|
||||
controller: function($scope, $element, ApiService, CreateService, $timeout, UserService) {
|
||||
$scope.TEAM_PATTERN = TEAM_PATTERN;
|
||||
controller: function($scope, $element, ApiService, $timeout, UserService) {
|
||||
$scope.teamRoles = [
|
||||
{ 'id': 'member', 'title': 'Member', 'kind': 'default' },
|
||||
{ 'id': 'creator', 'title': 'Creator', 'kind': 'success' },
|
||||
|
@ -27,6 +26,7 @@ angular.module('quay').directive('teamsManager', function () {
|
|||
$scope.showingMembers = false;
|
||||
$scope.fullMemberList = null;
|
||||
$scope.feedback = null;
|
||||
$scope.createTeamInfo = null;
|
||||
|
||||
var loadTeamMembers = function() {
|
||||
if (!$scope.organization || !$scope.isEnabled) { return; }
|
||||
|
@ -107,35 +107,27 @@ angular.module('quay').directive('teamsManager', function () {
|
|||
}, errorHandler);
|
||||
};
|
||||
|
||||
$scope.createTeam = function(teamname) {
|
||||
if (!teamname) {
|
||||
return;
|
||||
}
|
||||
$scope.askCreateTeam = function(teamname) {
|
||||
$scope.createTeamInfo = {
|
||||
'namespace': $scope.organization.name
|
||||
};
|
||||
};
|
||||
|
||||
if ($scope.organization.teams[teamname]) {
|
||||
$('#team-' + teamname).removeClass('highlight');
|
||||
setTimeout(function() {
|
||||
$('#team-' + teamname).addClass('highlight');
|
||||
}, 10);
|
||||
return;
|
||||
}
|
||||
$scope.handleTeamCreated = function(created) {
|
||||
var teamname = created.name;
|
||||
$scope.organization.teams[teamname] = created;
|
||||
$scope.members[teamname] = {};
|
||||
$scope.members[teamname].members = [];
|
||||
$scope.organization.ordered_teams.push(teamname);
|
||||
$scope.orderedTeams.push(created);
|
||||
|
||||
var orgname = $scope.organization.name;
|
||||
CreateService.createOrganizationTeam(ApiService, orgname, teamname, function(created) {
|
||||
$scope.organization.teams[teamname] = created;
|
||||
$scope.members[teamname] = {};
|
||||
$scope.members[teamname].members = [];
|
||||
$scope.organization.ordered_teams.push(teamname);
|
||||
$scope.orderedTeams.push(created);
|
||||
|
||||
$scope.feedback = {
|
||||
'kind': 'success',
|
||||
'message': 'Team {team} created',
|
||||
'data': {
|
||||
'team': teamname
|
||||
}
|
||||
};
|
||||
});
|
||||
$scope.feedback = {
|
||||
'kind': 'success',
|
||||
'message': 'Team {team} created',
|
||||
'data': {
|
||||
'team': teamname
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
$scope.askDeleteTeam = function(teamname) {
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
var loadUser = function() {
|
||||
$scope.userResource = ApiService.getUserInformationAsResource({'username': username}).get(function(user) {
|
||||
$scope.context.viewuser = user;
|
||||
$scope.viewuser = user;
|
||||
|
||||
// Load the repositories.
|
||||
$timeout(function() {
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
/**
|
||||
* Service which exposes various methods for creating entities on the backend.
|
||||
*/
|
||||
angular.module('quay').factory('CreateService', ['ApiService', 'UserService', function(ApiService, UserService) {
|
||||
var createService = {};
|
||||
|
||||
createService.createRobotAccount = function(ApiService, is_org, orgname, name, callback) {
|
||||
ApiService.createRobot(is_org ? orgname : null, null, {'robot_shortname': name})
|
||||
.then(callback, ApiService.errorDisplay('Cannot create robot account'));
|
||||
};
|
||||
|
||||
createService.createOrganizationTeam = function(ApiService, orgname, teamname, callback) {
|
||||
var data = {
|
||||
'name': teamname,
|
||||
'role': 'member'
|
||||
};
|
||||
|
||||
var params = {
|
||||
'orgname': orgname,
|
||||
'teamname': teamname
|
||||
};
|
||||
|
||||
ApiService.updateOrganizationTeam(data, params)
|
||||
.then(callback, ApiService.errorDisplay('Cannot create team'));
|
||||
};
|
||||
|
||||
createService.askCreateRobot = function(namespace, callback) {
|
||||
if (!namespace || !UserService.isNamespaceAdmin(namespace)) { return; }
|
||||
|
||||
var isorg = UserService.isOrganization(namespace);
|
||||
bootbox.prompt('Enter the name of the new robot account', function(robotname) {
|
||||
if (!robotname) { return; }
|
||||
|
||||
var regex = new RegExp(ROBOT_PATTERN);
|
||||
if (!regex.test(robotname)) {
|
||||
bootbox.alert('Invalid robot account name');
|
||||
return;
|
||||
}
|
||||
|
||||
createService.createRobotAccount(ApiService, isorg, namespace, robotname, callback);
|
||||
});
|
||||
};
|
||||
|
||||
createService.askCreateTeam = function(namespace, callback) {
|
||||
if (!namespace || !UserService.isNamespaceAdmin(namespace)) { return; }
|
||||
|
||||
bootbox.prompt('Enter the name of the new team', function(teamname) {
|
||||
if (!teamname) { return; }
|
||||
|
||||
var regex = new RegExp(TEAM_PATTERN);
|
||||
if (!regex.test(teamname)) {
|
||||
bootbox.alert('Invalid team name');
|
||||
return;
|
||||
}
|
||||
|
||||
createService.createOrganizationTeam(ApiService, namespace, teamname, callback);
|
||||
});
|
||||
};
|
||||
|
||||
return createService;
|
||||
}]);
|
|
@ -1,20 +1,57 @@
|
|||
/**
|
||||
* Service which defines the various role groups.
|
||||
*/
|
||||
angular.module('quay').factory('RolesService', [function() {
|
||||
angular.module('quay').factory('RolesService', ['UtilService', 'Restangular', 'ApiService', function(UtilService, Restangular, ApiService) {
|
||||
var roleService = {};
|
||||
|
||||
roleService.repoRoles = [
|
||||
roleService.repoRolesOrNone = [
|
||||
{ 'id': 'none', 'title': 'None', 'kind': 'default', 'description': 'No permissions on the repository' },
|
||||
|
||||
{ 'id': 'read', 'title': 'Read', 'kind': 'success', 'description': 'Can view and pull from the repository' },
|
||||
{ 'id': 'write', 'title': 'Write', 'kind': 'success', 'description': 'Can view, pull and push to the repository' },
|
||||
{ 'id': 'admin', 'title': 'Admin', 'kind': 'primary', 'description': 'Full admin access, pull and push on the repository' }
|
||||
];
|
||||
|
||||
roleService.repoRoles = roleService.repoRolesOrNone.slice(1);
|
||||
|
||||
roleService.teamRoles = [
|
||||
{ 'id': 'member', 'title': 'Member', 'kind': 'default', 'description': 'Inherits all permissions of the team' },
|
||||
{ 'id': 'creator', 'title': 'Creator', 'kind': 'success', 'description': 'Member and can create new repositories' },
|
||||
{ 'id': 'admin', 'title': 'Admin', 'kind': 'primary', 'description': 'Full admin access to the organization' }
|
||||
];
|
||||
|
||||
var getPermissionEndpoint = function(repository, entityName, kind) {
|
||||
var namespace = repository.namespace;
|
||||
var name = repository.name;
|
||||
var url = UtilService.getRestUrl('repository', namespace, name, 'permissions', kind, entityName);
|
||||
return Restangular.one(url);
|
||||
};
|
||||
|
||||
roleService.deleteRepositoryRole = function(repository, entityKind, entityName, callback) {
|
||||
var errorDisplay = ApiService.errorDisplay('Cannot change permission', function(resp) {
|
||||
callback(false);
|
||||
});
|
||||
|
||||
var endpoint = getPermissionEndpoint(repository, entityName, kind);
|
||||
endpoint.customDELETE().then(function() {
|
||||
callback(true);
|
||||
}, errorHandler);
|
||||
};
|
||||
|
||||
roleService.setRepositoryRole = function(repository, role, entityKind, entityName, callback) {
|
||||
var errorDisplay = ApiService.errorDisplay('Cannot change permission', function(resp) {
|
||||
callback(false);
|
||||
});
|
||||
|
||||
var permission = {
|
||||
'role': role
|
||||
};
|
||||
|
||||
var endpoint = getPermissionEndpoint(repository, entityName, entityKind);
|
||||
endpoint.customPUT(permission).then(function(resp) {
|
||||
callback(true, resp);
|
||||
}, errorDisplay);
|
||||
};
|
||||
|
||||
return roleService;
|
||||
}]);
|
||||
|
|
|
@ -22,6 +22,14 @@ angular.module('quay').factory('TableService', ['AngularViewArray', function(Ang
|
|||
options.predicate = predicate;
|
||||
};
|
||||
|
||||
tableService.getReversedTimestamp = function(datetime) {
|
||||
if (!datetime) {
|
||||
return -Number.MAX_VALUE;
|
||||
}
|
||||
|
||||
return (new Date(datetime)).valueOf() * (-1);
|
||||
};
|
||||
|
||||
tableService.buildOrderedItems = function(items, options, filterFields, numericFields, opt_extrafilter) {
|
||||
var orderedItems = AngularViewArray.create();
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ angular.module('quay').factory('UIService', ['$timeout', '$rootScope', '$locatio
|
|||
CheckStateController.prototype.rebuildCheckedList_ = function() {
|
||||
var that = this;
|
||||
this.checked = [];
|
||||
this.items.forEach(function(item) {
|
||||
this.allItems_.forEach(function(item) {
|
||||
if (that.allCheckedMap_[item[that.itemKey_]]) {
|
||||
that.checked.push(item);
|
||||
}
|
||||
|
|
|
@ -134,6 +134,19 @@ function(ApiService, CookieService, $rootScope, Config) {
|
|||
return !!org;
|
||||
};
|
||||
|
||||
userService.getNamespace = function(namespace) {
|
||||
var org = userService.getOrganization(namespace);
|
||||
if (org) {
|
||||
return org;
|
||||
}
|
||||
|
||||
if (namespace == userResponse.username) {
|
||||
return userResponse;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
userService.currentUser = function() {
|
||||
return userResponse;
|
||||
};
|
||||
|
|
Reference in a new issue