Merge branch 'master' into touchdown
This commit is contained in:
commit
4480d2d8e2
129 changed files with 4653 additions and 30933 deletions
714
static/js/app.js
714
static/js/app.js
File diff suppressed because it is too large
Load diff
13
static/js/bootstrap.js
vendored
13
static/js/bootstrap.js
vendored
|
@ -1,13 +0,0 @@
|
|||
$.ajax({
|
||||
type: 'GET',
|
||||
async: false,
|
||||
url: '/api/discovery',
|
||||
success: function(data) {
|
||||
window.__endpoints = data.endpoints;
|
||||
},
|
||||
error: function() {
|
||||
setTimeout(function() {
|
||||
$('#couldnotloadModal').modal({});
|
||||
}, 250);
|
||||
}
|
||||
});
|
|
@ -48,14 +48,15 @@ function PlansCtrl($scope, $location, UserService, PlanService) {
|
|||
};
|
||||
}
|
||||
|
||||
function TutorialCtrl($scope, AngularTour, AngularTourSignals, UserService) {
|
||||
function TutorialCtrl($scope, AngularTour, AngularTourSignals, UserService, Config) {
|
||||
// Default to showing sudo on all commands if on linux.
|
||||
var showSudo = navigator.appVersion.indexOf("Linux") != -1;
|
||||
|
||||
$scope.tour = {
|
||||
'title': 'Quay.io Tutorial',
|
||||
'initialScope': {
|
||||
'showSudo': showSudo
|
||||
'showSudo': showSudo,
|
||||
'domainName': Config.getDomain()
|
||||
},
|
||||
'steps': [
|
||||
{
|
||||
|
@ -262,9 +263,7 @@ function RepoListCtrl($scope, $sanitize, Restangular, UserService, ApiService) {
|
|||
loadPublicRepos();
|
||||
}
|
||||
|
||||
function LandingCtrl($scope, UserService, ApiService, $rootScope) {
|
||||
$rootScope.customClass = 'landing-page';
|
||||
|
||||
function LandingCtrl($scope, UserService, ApiService, Features, Config) {
|
||||
$scope.namespace = null;
|
||||
|
||||
$scope.$watch('namespace', function(namespace) {
|
||||
|
@ -305,10 +304,22 @@ function LandingCtrl($scope, UserService, ApiService, $rootScope) {
|
|||
});
|
||||
};
|
||||
|
||||
browserchrome.update();
|
||||
$scope.chromify = function() {
|
||||
browserchrome.update();
|
||||
};
|
||||
|
||||
$scope.getEnterpriseLogo = function() {
|
||||
if (!Config.ENTERPRISE_LOGO_URL) {
|
||||
return '/static/img/quay-logo.png';
|
||||
}
|
||||
|
||||
return Config.ENTERPRISE_LOGO_URL;
|
||||
};
|
||||
}
|
||||
|
||||
function RepoCtrl($scope, $sanitize, Restangular, ImageMetadataService, ApiService, $routeParams, $rootScope, $location, $timeout) {
|
||||
function RepoCtrl($scope, $sanitize, Restangular, ImageMetadataService, ApiService, $routeParams, $rootScope, $location, $timeout, Config) {
|
||||
$scope.Config = Config;
|
||||
|
||||
var namespace = $routeParams.namespace;
|
||||
var name = $routeParams.name;
|
||||
|
||||
|
@ -351,6 +362,7 @@ function RepoCtrl($scope, $sanitize, Restangular, ImageMetadataService, ApiServi
|
|||
};
|
||||
|
||||
$scope.handleBuildStarted = function(build) {
|
||||
getBuildInfo($scope.repo);
|
||||
startBuildInfoTimer($scope.repo);
|
||||
};
|
||||
|
||||
|
@ -386,9 +398,9 @@ function RepoCtrl($scope, $sanitize, Restangular, ImageMetadataService, ApiServi
|
|||
|
||||
$scope.getMoreCount = function(changes) {
|
||||
if (!changes) { return 0; }
|
||||
var addedDisplayed = Math.min(5, changes.added.length);
|
||||
var removedDisplayed = Math.min(5, changes.removed.length);
|
||||
var changedDisplayed = Math.min(5, changes.changed.length);
|
||||
var addedDisplayed = Math.min(2, changes.added.length);
|
||||
var removedDisplayed = Math.min(2, changes.removed.length);
|
||||
var changedDisplayed = Math.min(2, changes.changed.length);
|
||||
|
||||
return (changes.added.length + changes.removed.length + changes.changed.length) -
|
||||
addedDisplayed - removedDisplayed - changedDisplayed;
|
||||
|
@ -417,57 +429,21 @@ function RepoCtrl($scope, $sanitize, Restangular, ImageMetadataService, ApiServi
|
|||
$location.search('tag', null);
|
||||
$location.search('image', imageId.substr(0, 12));
|
||||
}
|
||||
};
|
||||
|
||||
$scope.showAddTag = function(image) {
|
||||
$scope.toTagImage = image;
|
||||
$('#addTagModal').modal('show');
|
||||
};
|
||||
|
||||
$scope.tagSpecificImages = function(tagName) {
|
||||
if (!tagName) { return []; }
|
||||
$scope.isOwnedTag = function(image, tagName) {
|
||||
if (!image || !tagName) { return false; }
|
||||
return image.tags.indexOf(tagName) >= 0;
|
||||
};
|
||||
|
||||
var tag = $scope.repo.tags[tagName];
|
||||
if (!tag) { return []; }
|
||||
|
||||
if ($scope.specificImages && $scope.specificImages[tagName]) {
|
||||
return $scope.specificImages[tagName];
|
||||
}
|
||||
|
||||
var getIdsForTag = function(currentTag) {
|
||||
var ids = {};
|
||||
forAllTagImages(currentTag, function(image) {
|
||||
ids[image.dbid] = true;
|
||||
});
|
||||
return ids;
|
||||
};
|
||||
|
||||
// Remove any IDs that match other tags.
|
||||
var toDelete = getIdsForTag(tag);
|
||||
for (var currentTagName in $scope.repo.tags) {
|
||||
var currentTag = $scope.repo.tags[currentTagName];
|
||||
if (currentTag != tag) {
|
||||
for (var dbid in getIdsForTag(currentTag)) {
|
||||
delete toDelete[dbid];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the matching list of images.
|
||||
var images = [];
|
||||
for (var i = 0; i < $scope.images.length; ++i) {
|
||||
var image = $scope.images[i];
|
||||
if (toDelete[image.dbid]) {
|
||||
images.push(image);
|
||||
}
|
||||
}
|
||||
|
||||
images.sort(function(a, b) {
|
||||
var result = new Date(b.created) - new Date(a.created);
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return b.dbid - a.dbid;
|
||||
});
|
||||
|
||||
$scope.specificImages[tagName] = images;
|
||||
return images;
|
||||
$scope.isAnotherImageTag = function(image, tagName) {
|
||||
if (!image || !tagName) { return false; }
|
||||
return image.tags.indexOf(tagName) < 0 && $scope.repo.tags[tagName];
|
||||
};
|
||||
|
||||
$scope.askDeleteTag = function(tagName) {
|
||||
|
@ -477,6 +453,39 @@ function RepoCtrl($scope, $sanitize, Restangular, ImageMetadataService, ApiServi
|
|||
$('#confirmdeleteTagModal').modal('show');
|
||||
};
|
||||
|
||||
$scope.createOrMoveTag = function(image, tagName, opt_invalid) {
|
||||
if (opt_invalid) { return; }
|
||||
|
||||
$scope.creatingTag = true;
|
||||
|
||||
var params = {
|
||||
'repository': $scope.repo.namespace + '/' + $scope.repo.name,
|
||||
'tag': tagName
|
||||
};
|
||||
|
||||
var data = {
|
||||
'image': image.id
|
||||
};
|
||||
|
||||
ApiService.changeTagImage(data, params).then(function(resp) {
|
||||
$scope.creatingTag = false;
|
||||
loadViewInfo();
|
||||
$('#addTagModal').modal('hide');
|
||||
}, function(resp) {
|
||||
$('#addTagModal').modal('hide');
|
||||
bootbox.dialog({
|
||||
"message": resp.data ? resp.data : 'Could not create or move tag',
|
||||
"title": "Cannot create or move tag",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.deleteTag = function(tagName) {
|
||||
if (!$scope.repo.can_admin) { return; }
|
||||
$('#confirmdeleteTagModal').modal('hide');
|
||||
|
@ -557,20 +566,6 @@ function RepoCtrl($scope, $sanitize, Restangular, ImageMetadataService, ApiServi
|
|||
|
||||
$scope.getFirstTextLine = getFirstTextLine;
|
||||
|
||||
$scope.getImageListingClasses = function(image, tagName) {
|
||||
var classes = '';
|
||||
if (image.ancestors.length > 1) {
|
||||
classes += 'child ';
|
||||
}
|
||||
|
||||
var currentTag = $scope.repo.tags[tagName];
|
||||
if (image.dbid == currentTag.image.dbid) {
|
||||
classes += 'tag-image ';
|
||||
}
|
||||
|
||||
return classes;
|
||||
};
|
||||
|
||||
$scope.getTagCount = function(repo) {
|
||||
if (!repo) { return 0; }
|
||||
var count = 0;
|
||||
|
@ -1096,6 +1091,7 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
|||
// Note: We use extend here rather than replacing as Angular is depending on the
|
||||
// root build object to remain the same object.
|
||||
$.extend(true, $scope.builds[$scope.currentBuildIndex], resp);
|
||||
var currentBuild = $scope.builds[$scope.currentBuildIndex];
|
||||
checkPollTimer();
|
||||
|
||||
// Load the updated logs for the build.
|
||||
|
@ -1112,6 +1108,18 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
|||
processLogs(resp['logs'], resp['start']);
|
||||
$scope.logStartIndex = resp['total'];
|
||||
$scope.polling = false;
|
||||
|
||||
// If the build status is an error, open the last two log entries.
|
||||
if (currentBuild['phase'] == 'error' && $scope.logEntries.length > 1) {
|
||||
var openLogEntries = function(entry) {
|
||||
if (entry.logs) {
|
||||
entry.logs.setVisible(true);
|
||||
}
|
||||
};
|
||||
|
||||
openLogEntries($scope.logEntries[$scope.logEntries.length - 2]);
|
||||
openLogEntries($scope.logEntries[$scope.logEntries.length - 1]);
|
||||
}
|
||||
}, function() {
|
||||
$scope.polling = false;
|
||||
});
|
||||
|
@ -1154,7 +1162,7 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
|
|||
fetchRepository();
|
||||
}
|
||||
|
||||
function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams, $rootScope, $location, UserService) {
|
||||
function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams, $rootScope, $location, UserService, Config) {
|
||||
var namespace = $routeParams.namespace;
|
||||
var name = $routeParams.name;
|
||||
|
||||
|
@ -1167,15 +1175,17 @@ function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams
|
|||
$scope.githubRedirectUri = KeyService.githubRedirectUri;
|
||||
$scope.githubClientId = KeyService.githubClientId;
|
||||
|
||||
$scope.showTriggerSetupCounter = 0;
|
||||
|
||||
$scope.getBadgeFormat = function(format, repo) {
|
||||
if (!repo) { return; }
|
||||
|
||||
var imageUrl = 'https://quay.io/repository/' + namespace + '/' + name + '/status';
|
||||
var imageUrl = Config.getUrl('/' + namespace + '/' + name + '/status');
|
||||
if (!$scope.repo.is_public) {
|
||||
imageUrl += '?token=' + $scope.repo.status_token;
|
||||
}
|
||||
|
||||
var linkUrl = 'https://quay.io/repository/' + namespace + '/' + name;
|
||||
var linkUrl = Config.getUrl('/' + namespace + '/' + name);
|
||||
|
||||
switch (format) {
|
||||
case 'svg':
|
||||
|
@ -1456,65 +1466,15 @@ function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams
|
|||
};
|
||||
|
||||
$scope.setupTrigger = function(trigger) {
|
||||
$scope.triggerSetupReady = false;
|
||||
$scope.currentSetupTrigger = trigger;
|
||||
|
||||
trigger['_pullEntity'] = null;
|
||||
trigger['_publicPull'] = true;
|
||||
|
||||
$('#setupTriggerModal').modal({});
|
||||
$('#setupTriggerModal').on('hidden.bs.modal', function () {
|
||||
$scope.$apply(function() {
|
||||
$scope.cancelSetupTrigger();
|
||||
});
|
||||
});
|
||||
$scope.showTriggerSetupCounter++;
|
||||
};
|
||||
|
||||
$scope.isNamespaceAdmin = function(namespace) {
|
||||
return UserService.isNamespaceAdmin(namespace);
|
||||
};
|
||||
$scope.cancelSetupTrigger = function(trigger) {
|
||||
if ($scope.currentSetupTrigger != trigger) { return; }
|
||||
|
||||
$scope.finishSetupTrigger = function(trigger) {
|
||||
$('#setupTriggerModal').modal('hide');
|
||||
$scope.currentSetupTrigger = null;
|
||||
|
||||
var params = {
|
||||
'repository': namespace + '/' + name,
|
||||
'trigger_uuid': trigger.id
|
||||
};
|
||||
|
||||
var data = {
|
||||
'config': trigger['config']
|
||||
};
|
||||
|
||||
if (trigger['_pullEntity']) {
|
||||
data['pull_robot'] = trigger['_pullEntity']['name'];
|
||||
}
|
||||
|
||||
ApiService.activateBuildTrigger(data, params).then(function(resp) {
|
||||
trigger['is_active'] = true;
|
||||
trigger['pull_robot'] = resp['pull_robot'];
|
||||
}, function(resp) {
|
||||
$scope.triggers.splice($scope.triggers.indexOf(trigger), 1);
|
||||
bootbox.dialog({
|
||||
"message": resp['data']['message'] || 'The build trigger setup could not be completed',
|
||||
"title": "Could not activate build trigger",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.cancelSetupTrigger = function() {
|
||||
if (!$scope.currentSetupTrigger) { return; }
|
||||
|
||||
$('#setupTriggerModal').modal('hide');
|
||||
$scope.deleteTrigger($scope.currentSetupTrigger);
|
||||
$scope.currentSetupTrigger = null;
|
||||
$scope.deleteTrigger(trigger);
|
||||
};
|
||||
|
||||
$scope.startTrigger = function(trigger) {
|
||||
|
@ -1542,6 +1502,8 @@ function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams
|
|||
};
|
||||
|
||||
$scope.deleteTrigger = function(trigger) {
|
||||
if (!trigger) { return; }
|
||||
|
||||
var params = {
|
||||
'repository': namespace + '/' + name,
|
||||
'trigger_uuid': trigger.id
|
||||
|
@ -1609,12 +1571,16 @@ function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams
|
|||
}
|
||||
|
||||
function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, UserService, CookieService, KeyService,
|
||||
$routeParams, $http, UIService) {
|
||||
$routeParams, $http, UIService, Features) {
|
||||
$scope.Features = Features;
|
||||
|
||||
if ($routeParams['migrate']) {
|
||||
$('#migrateTab').tab('show')
|
||||
}
|
||||
|
||||
UserService.updateUserIn($scope, function(user) {
|
||||
if (!Features.GITHUB_LOGIN) { return; }
|
||||
|
||||
$scope.cuser = jQuery.extend({}, user);
|
||||
|
||||
for (var i = 0; i < $scope.cuser.logins.length; i++) {
|
||||
|
@ -1639,7 +1605,7 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
|
|||
$scope.convertStep = 0;
|
||||
$scope.org = {};
|
||||
$scope.githubRedirectUri = KeyService.githubRedirectUri;
|
||||
$scope.githubClientId = KeyService.githubClientId;
|
||||
$scope.githubClientId = KeyService.githubLoginClientId;
|
||||
$scope.authorizedApps = null;
|
||||
|
||||
$scope.logsShown = 0;
|
||||
|
@ -1690,13 +1656,15 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
|
|||
};
|
||||
|
||||
$scope.showConvertForm = function() {
|
||||
PlanService.getMatchingBusinessPlan(function(plan) {
|
||||
$scope.org.plan = plan;
|
||||
});
|
||||
if (Features.BILLING) {
|
||||
PlanService.getMatchingBusinessPlan(function(plan) {
|
||||
$scope.org.plan = plan;
|
||||
});
|
||||
|
||||
PlanService.getPlans(function(plans) {
|
||||
$scope.orgPlans = plans;
|
||||
});
|
||||
PlanService.getPlans(function(plans) {
|
||||
$scope.orgPlans = plans;
|
||||
});
|
||||
}
|
||||
|
||||
$scope.convertStep = 1;
|
||||
};
|
||||
|
@ -1711,7 +1679,7 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
|
|||
var data = {
|
||||
'adminUser': $scope.org.adminUser,
|
||||
'adminPassword': $scope.org.adminPassword,
|
||||
'plan': $scope.org.plan.stripeId
|
||||
'plan': $scope.org.plan ? $scope.org.plan.stripeId : ''
|
||||
};
|
||||
|
||||
ApiService.convertUserToOrganization(data).then(function(resp) {
|
||||
|
@ -1906,7 +1874,7 @@ function V1Ctrl($scope, $location, UserService) {
|
|||
UserService.updateUserIn($scope);
|
||||
}
|
||||
|
||||
function NewRepoCtrl($scope, $location, $http, $timeout, UserService, ApiService, PlanService, KeyService) {
|
||||
function NewRepoCtrl($scope, $location, $http, $timeout, UserService, ApiService, PlanService, KeyService, Features) {
|
||||
UserService.updateUserIn($scope);
|
||||
|
||||
$scope.githubRedirectUri = KeyService.githubRedirectUri;
|
||||
|
@ -2028,13 +1996,19 @@ function NewRepoCtrl($scope, $location, $http, $timeout, UserService, ApiService
|
|||
var checkPrivateAllowed = function() {
|
||||
if (!$scope.repo || !$scope.repo.namespace) { return; }
|
||||
|
||||
if (!Features.BILLING) {
|
||||
$scope.checkingPlan = false;
|
||||
$scope.planRequired = null;
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.checkingPlan = true;
|
||||
|
||||
var isUserNamespace = $scope.isUserNamespace;
|
||||
ApiService.getPrivateAllowed(isUserNamespace ? null : $scope.repo.namespace).then(function(resp) {
|
||||
$scope.checkingPlan = false;
|
||||
|
||||
if (resp['privateAllowed']) {
|
||||
if (resp['privateAllowed']) {
|
||||
$scope.planRequired = null;
|
||||
return;
|
||||
}
|
||||
|
@ -2154,18 +2128,20 @@ function OrgViewCtrl($rootScope, $scope, ApiService, $routeParams) {
|
|||
loadOrganization();
|
||||
}
|
||||
|
||||
function OrgAdminCtrl($rootScope, $scope, $timeout, Restangular, $routeParams, UserService, PlanService, ApiService, UIService) {
|
||||
function OrgAdminCtrl($rootScope, $scope, $timeout, Restangular, $routeParams, UserService, PlanService, ApiService, Features, UIService) {
|
||||
var orgname = $routeParams.orgname;
|
||||
|
||||
// Load the list of plans.
|
||||
PlanService.getPlans(function(plans) {
|
||||
$scope.plans = plans;
|
||||
$scope.plan_map = {};
|
||||
|
||||
for (var i = 0; i < plans.length; ++i) {
|
||||
$scope.plan_map[plans[i].stripeId] = plans[i];
|
||||
}
|
||||
});
|
||||
if (Features.BILLING) {
|
||||
PlanService.getPlans(function(plans) {
|
||||
$scope.plans = plans;
|
||||
$scope.plan_map = {};
|
||||
|
||||
for (var i = 0; i < plans.length; ++i) {
|
||||
$scope.plan_map[plans[i].stripeId] = plans[i];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.orgname = orgname;
|
||||
$scope.membersLoading = true;
|
||||
|
@ -2347,30 +2323,39 @@ function OrgsCtrl($scope, UserService) {
|
|||
browserchrome.update();
|
||||
}
|
||||
|
||||
function NewOrgCtrl($scope, $routeParams, $timeout, $location, UserService, PlanService, ApiService, CookieService) {
|
||||
function NewOrgCtrl($scope, $routeParams, $timeout, $location, UserService, PlanService, ApiService, CookieService, Features) {
|
||||
$scope.Features = Features;
|
||||
$scope.holder = {};
|
||||
|
||||
UserService.updateUserIn($scope);
|
||||
|
||||
var requested = $routeParams['plan'];
|
||||
|
||||
// Load the list of plans.
|
||||
PlanService.getPlans(function(plans) {
|
||||
$scope.plans = plans;
|
||||
$scope.currentPlan = null;
|
||||
if (requested) {
|
||||
PlanService.getPlan(requested, function(plan) {
|
||||
$scope.currentPlan = plan;
|
||||
});
|
||||
}
|
||||
});
|
||||
if (Features.BILLING) {
|
||||
// Load the list of plans.
|
||||
PlanService.getPlans(function(plans) {
|
||||
$scope.plans = plans;
|
||||
$scope.currentPlan = null;
|
||||
if (requested) {
|
||||
PlanService.getPlan(requested, function(plan) {
|
||||
$scope.currentPlan = plan;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.signedIn = function() {
|
||||
PlanService.handleNotedPlan();
|
||||
if (Features.BILLING) {
|
||||
PlanService.handleNotedPlan();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.signinStarted = function() {
|
||||
PlanService.getMinimumPlan(1, true, function(plan) {
|
||||
PlanService.notePlan(plan.stripeId);
|
||||
});
|
||||
if (Features.BILLING) {
|
||||
PlanService.getMinimumPlan(1, true, function(plan) {
|
||||
PlanService.notePlan(plan.stripeId);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.setPlan = function(plan) {
|
||||
|
@ -2402,7 +2387,7 @@ function NewOrgCtrl($scope, $routeParams, $timeout, $location, UserService, Plan
|
|||
};
|
||||
|
||||
// If the selected plan is free, simply move to the org page.
|
||||
if ($scope.currentPlan.price == 0) {
|
||||
if (!Features.BILLING || $scope.currentPlan.price == 0) {
|
||||
showOrg();
|
||||
return;
|
||||
}
|
||||
|
@ -2595,4 +2580,135 @@ function ManageApplicationCtrl($scope, $routeParams, $rootScope, $location, $tim
|
|||
// Load the organization and application info.
|
||||
loadOrganization();
|
||||
loadApplicationInfo();
|
||||
}
|
||||
|
||||
|
||||
function SuperUserAdminCtrl($scope, ApiService, Features, UserService) {
|
||||
if (!Features.SUPER_USERS) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Monitor any user changes and place the current user into the scope.
|
||||
UserService.updateUserIn($scope);
|
||||
|
||||
$scope.loadUsers = function() {
|
||||
if ($scope.users) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.loadUsersInternal();
|
||||
};
|
||||
|
||||
$scope.loadUsersInternal = function() {
|
||||
ApiService.listAllUsers().then(function(resp) {
|
||||
$scope.users = resp['users'];
|
||||
}, function(resp) {
|
||||
$scope.users = [];
|
||||
$scope.usersError = resp['data']['message'] || resp['data']['error_description'];
|
||||
});
|
||||
};
|
||||
|
||||
$scope.showChangePassword = function(user) {
|
||||
$scope.userToChange = user;
|
||||
$('#changePasswordModal').modal({});
|
||||
};
|
||||
|
||||
$scope.showDeleteUser = function(user) {
|
||||
if (user.username == UserService.currentUser().username) {
|
||||
bootbox.dialog({
|
||||
"message": 'Cannot delete yourself!',
|
||||
"title": "Cannot delete user",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.userToDelete = user;
|
||||
$('#confirmDeleteUserModal').modal({});
|
||||
};
|
||||
|
||||
$scope.changeUserPassword = function(user) {
|
||||
$('#changePasswordModal').modal('hide');
|
||||
|
||||
var params = {
|
||||
'username': user.username
|
||||
};
|
||||
|
||||
var data = {
|
||||
'password': user.password
|
||||
};
|
||||
|
||||
ApiService.changeInstallUser(data, params).then(function(resp) {
|
||||
$scope.loadUsersInternal();
|
||||
}, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp.data ? resp.data.message : 'Could not change user',
|
||||
"title": "Cannot change user",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.deleteUser = function(user) {
|
||||
$('#confirmDeleteUserModal').modal('hide');
|
||||
|
||||
var params = {
|
||||
'username': user.username
|
||||
};
|
||||
|
||||
ApiService.deleteInstallUser(null, params).then(function(resp) {
|
||||
$scope.loadUsersInternal();
|
||||
}, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp.data ? resp.data.message : 'Could not delete user',
|
||||
"title": "Cannot delete user",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var seatUsageLoaded = function(usage) {
|
||||
$scope.usageLoading = false;
|
||||
|
||||
if (usage.count > usage.allowed) {
|
||||
$scope.limit = 'over';
|
||||
} else if (usage.count == usage.allowed) {
|
||||
$scope.limit = 'at';
|
||||
} else if (usage.count >= usage.allowed * 0.7) {
|
||||
$scope.limit = 'near';
|
||||
} else {
|
||||
$scope.limit = 'none';
|
||||
}
|
||||
|
||||
if (!$scope.chart) {
|
||||
$scope.chart = new UsageChart();
|
||||
$scope.chart.draw('seat-usage-chart');
|
||||
}
|
||||
|
||||
$scope.chart.update(usage.count, usage.allowed);
|
||||
};
|
||||
|
||||
var loadSeatUsage = function() {
|
||||
$scope.usageLoading = true;
|
||||
ApiService.getSeatCount().then(function(resp) {
|
||||
seatUsageLoaded(resp);
|
||||
});
|
||||
};
|
||||
|
||||
loadSeatUsage();
|
||||
}
|
|
@ -115,12 +115,20 @@ ImageHistoryTree.prototype.setupOverscroll_ = function() {
|
|||
$(that).trigger({
|
||||
'type': 'hideTagMenu'
|
||||
});
|
||||
|
||||
$(that).trigger({
|
||||
'type': 'hideImageMenu'
|
||||
});
|
||||
});
|
||||
|
||||
overscroll.on('scroll', function() {
|
||||
$(that).trigger({
|
||||
'type': 'hideTagMenu'
|
||||
});
|
||||
|
||||
$(that).trigger({
|
||||
'type': 'hideImageMenu'
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -664,7 +672,19 @@ ImageHistoryTree.prototype.update_ = function(source) {
|
|||
if (d.collapsed) { that.expandCollapsed_(d); }
|
||||
})
|
||||
.on('mouseover', tip.show)
|
||||
.on('mouseout', tip.hide);
|
||||
.on('mouseout', tip.hide)
|
||||
.on("contextmenu", function(d, e) {
|
||||
d3.event.preventDefault();
|
||||
|
||||
if (d.image) {
|
||||
$(that).trigger({
|
||||
'type': 'showImageMenu',
|
||||
'image': d.image.id,
|
||||
'clientX': d3.event.clientX,
|
||||
'clientY': d3.event.clientY
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
nodeEnter.selectAll("tags")
|
||||
.append("svg:text")
|
||||
|
@ -732,15 +752,16 @@ ImageHistoryTree.prototype.update_ = function(source) {
|
|||
return '';
|
||||
}
|
||||
|
||||
var html = '';
|
||||
var html = '<div style="width: ' + DEPTH_HEIGHT + 'px">';
|
||||
for (var i = 0; i < d.tags.length; ++i) {
|
||||
var tag = d.tags[i];
|
||||
var kind = 'default';
|
||||
if (tag == currentTag) {
|
||||
kind = 'success';
|
||||
}
|
||||
html += '<span class="label label-' + kind + ' tag" data-tag="' + tag + '" title="' + tag + '">' + tag + '</span>';
|
||||
html += '<span class="label label-' + kind + ' tag" data-tag="' + tag + '" title="' + tag + '" style="max-width: ' + DEPTH_HEIGHT + 'px">' + tag + '</span>';
|
||||
}
|
||||
html += '</div>';
|
||||
return html;
|
||||
});
|
||||
|
||||
|
@ -909,6 +930,8 @@ FileTreeBase.prototype.calculateDimensions_ = function(container) {
|
|||
* Updates the dimensions of the tree.
|
||||
*/
|
||||
FileTreeBase.prototype.updateDimensions_ = function() {
|
||||
if (!this.rootSvg_) { return; }
|
||||
|
||||
var container = this.container_;
|
||||
var dimensions = this.calculateDimensions_(container);
|
||||
|
||||
|
@ -1359,7 +1382,7 @@ FileTree.prototype.getNodesHeight = function() {
|
|||
/**
|
||||
* Based off of http://bl.ocks.org/mbostock/1346410
|
||||
*/
|
||||
function RepositoryUsageChart() {
|
||||
function UsageChart() {
|
||||
this.total_ = null;
|
||||
this.count_ = null;
|
||||
this.drawn_ = false;
|
||||
|
@ -1369,7 +1392,7 @@ function RepositoryUsageChart() {
|
|||
/**
|
||||
* Updates the chart with the given count and total of number of repositories.
|
||||
*/
|
||||
RepositoryUsageChart.prototype.update = function(count, total) {
|
||||
UsageChart.prototype.update = function(count, total) {
|
||||
if (!this.g_) { return; }
|
||||
this.total_ = total;
|
||||
this.count_ = count;
|
||||
|
@ -1380,7 +1403,7 @@ RepositoryUsageChart.prototype.update = function(count, total) {
|
|||
/**
|
||||
* Conducts the actual draw or update (if applicable).
|
||||
*/
|
||||
RepositoryUsageChart.prototype.drawInternal_ = function() {
|
||||
UsageChart.prototype.drawInternal_ = function() {
|
||||
// If the total is null, then we have not yet set the proper counts.
|
||||
if (this.total_ === null) { return; }
|
||||
|
||||
|
@ -1439,7 +1462,7 @@ RepositoryUsageChart.prototype.drawInternal_ = function() {
|
|||
/**
|
||||
* Draws the chart in the given container.
|
||||
*/
|
||||
RepositoryUsageChart.prototype.draw = function(container) {
|
||||
UsageChart.prototype.draw = function(container) {
|
||||
var cw = 200;
|
||||
var ch = 200;
|
||||
var radius = Math.min(cw, ch) / 2;
|
||||
|
@ -1716,7 +1739,7 @@ LogUsageChart.prototype.draw = function(container, logData, startDate, endDate)
|
|||
.duration(500)
|
||||
.call(chart);
|
||||
|
||||
nv.utils.windoweResize(chart.update);
|
||||
nv.utils.windowResize(chart.update);
|
||||
|
||||
chart.multibar.dispatch.on('elementClick', function(e) { that.handleElementClicked_(e); });
|
||||
chart.dispatch.on('stateChange', function(e) { that.handleStateChange_(e); });
|
||||
|
|
|
@ -135,7 +135,7 @@ angular.module("angular-tour", [])
|
|||
};
|
||||
|
||||
var fireMixpanelEvent = function() {
|
||||
if (!$scope.step || !mixpanel) { return; }
|
||||
if (!$scope.step || !window['mixpanel']) { return; }
|
||||
|
||||
var eventName = $scope.step['mixpanelEvent'];
|
||||
if (eventName) {
|
||||
|
|
Reference in a new issue