Merge remote-tracking branch 'origin/master' into tagyourit

Conflicts:
	static/css/quay.css
	static/js/graphing.js
	static/partials/view-repo.html
	test/data/test.db
This commit is contained in:
jakedt 2014-04-15 15:58:30 -04:00
commit 3f42d15335
132 changed files with 4266 additions and 1924 deletions

View file

@ -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,7 +263,7 @@ function RepoListCtrl($scope, $sanitize, Restangular, UserService, ApiService) {
loadPublicRepos();
}
function LandingCtrl($scope, UserService, ApiService) {
function LandingCtrl($scope, UserService, ApiService, Features, Config) {
$scope.namespace = null;
$scope.$watch('namespace', function(namespace) {
@ -303,10 +304,22 @@ function LandingCtrl($scope, UserService, ApiService) {
});
};
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;
@ -945,9 +958,13 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
var data = {
'file_id': build['resource_key'],
'subdirectory': subdirectory
'subdirectory': subdirectory,
};
if (build['pull_robot']) {
data['pull_robot'] = build['pull_robot']['name'];
}
var params = {
'repository': namespace + '/' + name
};
@ -1073,6 +1090,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.
@ -1089,6 +1107,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;
});
@ -1131,7 +1161,7 @@ function RepoBuildCtrl($scope, Restangular, ApiService, $routeParams, $rootScope
fetchRepository();
}
function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams, $rootScope, $location) {
function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams, $rootScope, $location, UserService, Config) {
var namespace = $routeParams.namespace;
var name = $routeParams.name;
@ -1144,15 +1174,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':
@ -1433,48 +1465,15 @@ function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams
};
$scope.setupTrigger = function(trigger) {
$scope.triggerSetupReady = false;
$scope.currentSetupTrigger = trigger;
$('#setupTriggerModal').modal({});
$('#setupTriggerModal').on('hidden.bs.modal', function () {
$scope.$apply(function() {
$scope.cancelSetupTrigger();
});
});
$scope.showTriggerSetupCounter++;
};
$scope.finishSetupTrigger = function(trigger) {
$('#setupTriggerModal').modal('hide');
$scope.currentSetupTrigger = null;
var params = {
'repository': namespace + '/' + name,
'trigger_uuid': trigger.id
};
ApiService.activateBuildTrigger(trigger['config'], params).then(function(resp) {
trigger['is_active'] = true;
}, 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.cancelSetupTrigger = function(trigger) {
if ($scope.currentSetupTrigger != trigger) { return; }
$scope.currentSetupTrigger = null;
$scope.deleteTrigger(trigger);
};
$scope.startTrigger = function(trigger) {
@ -1569,12 +1568,16 @@ function RepoAdminCtrl($scope, Restangular, ApiService, KeyService, $routeParams
}
function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, UserService, CookieService, KeyService,
$routeParams, $http) {
$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++) {
@ -1602,8 +1605,6 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
$scope.githubClientId = KeyService.githubClientId;
$scope.authorizedApps = null;
$('.form-change').popover();
$scope.logsShown = 0;
$scope.invoicesShown = 0;
@ -1652,13 +1653,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;
};
@ -1673,7 +1676,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) {
@ -1691,7 +1694,8 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
};
$scope.changeEmail = function() {
$('#changeEmailForm').popover('hide');
UIService.hidePopover('#changeEmailForm');
$scope.updatingUser = true;
$scope.changeEmailSent = false;
@ -1706,16 +1710,13 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
$scope.changeEmailForm.$setPristine();
}, function(result) {
$scope.updatingUser = false;
$scope.changeEmailError = result.data.message;
$timeout(function() {
$('#changeEmailForm').popover('show');
});
UIService.showFormError('#changeEmailForm', result);
});
};
$scope.changePassword = function() {
$('#changePasswordForm').popover('hide');
UIService.hidePopover('#changePasswordForm');
$scope.updatingUser = true;
$scope.changePasswordSuccess = false;
@ -1733,11 +1734,7 @@ function UserAdminCtrl($scope, $timeout, $location, ApiService, PlanService, Use
UserService.load();
}, function(result) {
$scope.updatingUser = false;
$scope.changePasswordError = result.data.message;
$timeout(function() {
$('#changePasswordForm').popover('show');
});
UIService.showFormError('#changePasswordForm', result);
});
};
}
@ -1874,7 +1871,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;
@ -1996,13 +1993,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;
}
@ -2122,18 +2125,20 @@ function OrgViewCtrl($rootScope, $scope, ApiService, $routeParams) {
loadOrganization();
}
function OrgAdminCtrl($rootScope, $scope, $timeout, Restangular, $routeParams, UserService, PlanService, ApiService) {
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;
@ -2161,10 +2166,12 @@ function OrgAdminCtrl($rootScope, $scope, $timeout, Restangular, $routeParams, U
};
$scope.$watch('organizationEmail', function(e) {
$('#changeEmailForm').popover('hide');
UIService.hidePopover('#changeEmailForm');
});
$scope.changeEmail = function() {
UIService.hidePopover('#changeEmailForm');
$scope.changingOrganization = true;
var params = {
'orgname': orgname
@ -2180,10 +2187,7 @@ function OrgAdminCtrl($rootScope, $scope, $timeout, Restangular, $routeParams, U
$scope.organization = org;
}, function(result) {
$scope.changingOrganization = false;
$scope.changeEmailError = result.data.message;
$timeout(function() {
$('#changeEmailForm').popover('show');
});
UIService.showFormError('#changeEmailForm', result);
});
};
@ -2316,30 +2320,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) {
@ -2371,7 +2384,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;
}
@ -2564,4 +2577,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();
}