Merge branch 'master' into fix_build
This commit is contained in:
commit
96fdae4f0d
23 changed files with 1323 additions and 692 deletions
531
static/js/app.js
531
static/js/app.js
|
@ -1,6 +1,18 @@
|
|||
var TEAM_PATTERN = '^[a-zA-Z][a-zA-Z0-9]+$';
|
||||
var ROBOT_PATTERN = '^[a-zA-Z][a-zA-Z0-9]+$';
|
||||
|
||||
function getRestUrl(args) {
|
||||
var url = '';
|
||||
for (var i = 0; i < arguments.length; ++i) {
|
||||
if (i > 0) {
|
||||
url += '/';
|
||||
}
|
||||
url += encodeURI(arguments[i])
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
|
||||
function getFirstTextLine(commentString) {
|
||||
if (!commentString) { return ''; }
|
||||
|
||||
|
@ -34,11 +46,8 @@ function getFirstTextLine(commentString) {
|
|||
return '';
|
||||
}
|
||||
|
||||
function createRobotAccount(Restangular, is_org, orgname, name, callback) {
|
||||
var url = is_org ? getRestUrl('organization', orgname, 'robots', name) :
|
||||
getRestUrl('user/robots', name);
|
||||
var createRobot = Restangular.one(url);
|
||||
createRobot.customPUT().then(callback, function(resp) {
|
||||
function createRobotAccount(ApiService, is_org, orgname, name, callback) {
|
||||
ApiService.createRobot(is_org ? orgname : null, null, {'robot_shortname': name}).then(callback, function(resp) {
|
||||
bootbox.dialog({
|
||||
"message": resp.data ? resp.data : 'The robot account could not be created',
|
||||
"title": "Cannot create robot account",
|
||||
|
@ -52,14 +61,18 @@ function createRobotAccount(Restangular, is_org, orgname, name, callback) {
|
|||
});
|
||||
}
|
||||
|
||||
function createOrganizationTeam(Restangular, orgname, teamname, callback) {
|
||||
var createTeam = Restangular.one(getRestUrl('organization', orgname, 'team', teamname));
|
||||
function createOrganizationTeam(ApiService, orgname, teamname, callback) {
|
||||
var data = {
|
||||
'name': teamname,
|
||||
'role': 'member'
|
||||
};
|
||||
|
||||
var params = {
|
||||
'orgname': orgname,
|
||||
'teamname': teamname
|
||||
};
|
||||
|
||||
createTeam.customPOST(data).then(callback, function() {
|
||||
ApiService.updateOrganizationTeam(data, params).then(callback, function() {
|
||||
bootbox.dialog({
|
||||
"message": resp.data ? resp.data : 'The team could not be created',
|
||||
"title": "Cannot create team",
|
||||
|
@ -73,17 +86,6 @@ function createOrganizationTeam(Restangular, orgname, teamname, callback) {
|
|||
});
|
||||
}
|
||||
|
||||
function getRestUrl(args) {
|
||||
var url = '';
|
||||
for (var i = 0; i < arguments.length; ++i) {
|
||||
if (i > 0) {
|
||||
url += '/';
|
||||
}
|
||||
url += encodeURI(arguments[i])
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
function getMarkedDown(string) {
|
||||
return Markdown.getSanitizingConverter().makeHtml(string || '');
|
||||
}
|
||||
|
@ -91,6 +93,137 @@ function getMarkedDown(string) {
|
|||
// Start the application code itself.
|
||||
quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'restangular', 'angularMoment', 'angulartics', /*'angulartics.google.analytics',*/ 'angulartics.mixpanel', '$strap.directives', 'ngCookies'], function($provide, cfpLoadingBarProvider) {
|
||||
cfpLoadingBarProvider.includeSpinner = false;
|
||||
|
||||
$provide.factory('ApiService', ['Restangular', function(Restangular) {
|
||||
var apiService = {};
|
||||
|
||||
var getResource = function(path) {
|
||||
var resource = {};
|
||||
resource.url = path;
|
||||
resource.withOptions = function(options) {
|
||||
this.options = options;
|
||||
return this;
|
||||
};
|
||||
|
||||
resource.get = function(processor, opt_errorHandler) {
|
||||
var options = this.options;
|
||||
var performer = Restangular.one(this.url);
|
||||
|
||||
var result = {
|
||||
'loading': true,
|
||||
'value': null,
|
||||
'hasError': false
|
||||
};
|
||||
|
||||
performer.get(options).then(function(resp) {
|
||||
result.value = processor(resp);
|
||||
result.loading = false;
|
||||
}, function(resp) {
|
||||
result.hasError = true;
|
||||
result.loading = false;
|
||||
if (opt_errorHandler) {
|
||||
opt_errorHandler(resp);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
return resource;
|
||||
};
|
||||
|
||||
var formatMethodName = function(endpointName) {
|
||||
var formatted = '';
|
||||
for (var i = 0; i < endpointName.length; ++i) {
|
||||
var c = endpointName[i];
|
||||
if (c == '_') {
|
||||
c = endpointName[i + 1].toUpperCase();
|
||||
i++;
|
||||
}
|
||||
|
||||
formatted += c;
|
||||
}
|
||||
|
||||
return formatted;
|
||||
};
|
||||
|
||||
var buildUrl = function(path, parameters) {
|
||||
// We already have /api/ on the URLs, so remove them from the paths.
|
||||
path = path.substr('/api/'.length, path.length);
|
||||
|
||||
var url = '';
|
||||
for (var i = 0; i < path.length; ++i) {
|
||||
var c = path[i];
|
||||
if (c == '<') {
|
||||
var end = path.indexOf('>', i);
|
||||
var varName = path.substr(i + 1, end - i - 1);
|
||||
var colon = varName.indexOf(':');
|
||||
var isPathVar = false;
|
||||
if (colon > 0) {
|
||||
isPathVar = true;
|
||||
varName = varName.substr(colon + 1);
|
||||
}
|
||||
|
||||
if (!parameters[varName]) {
|
||||
throw new Error('Missing parameter: ' + varName);
|
||||
}
|
||||
|
||||
url += isPathVar ? parameters[varName] : encodeURI(parameters[varName]);
|
||||
i = end;
|
||||
continue;
|
||||
}
|
||||
|
||||
url += c;
|
||||
}
|
||||
|
||||
return url;
|
||||
};
|
||||
|
||||
var getGenericMethodName = function(userMethodName) {
|
||||
return formatMethodName(userMethodName.replace('_user', ''));
|
||||
};
|
||||
|
||||
var buildMethodsForEndpoint = function(endpoint) {
|
||||
var method = endpoint.methods[0].toLowerCase();
|
||||
var methodName = formatMethodName(endpoint['name']);
|
||||
apiService[methodName] = function(opt_options, opt_parameters) {
|
||||
return Restangular.one(buildUrl(endpoint['path'], opt_parameters))['custom' + method.toUpperCase()](opt_options);
|
||||
};
|
||||
|
||||
if (method == 'get') {
|
||||
apiService[methodName + 'AsResource'] = function(opt_parameters) {
|
||||
return getResource(buildUrl(endpoint['path'], opt_parameters));
|
||||
};
|
||||
}
|
||||
|
||||
if (endpoint['user_method']) {
|
||||
apiService[getGenericMethodName(endpoint['user_method'])] = function(orgname, opt_options, opt_parameters) {
|
||||
if (orgname) {
|
||||
if (orgname.name) {
|
||||
orgname = orgname.name;
|
||||
}
|
||||
|
||||
var params = jQuery.extend({'orgname' : orgname}, opt_parameters || {});
|
||||
return apiService[methodName](opt_options, params);
|
||||
} else {
|
||||
return apiService[formatMethodName(endpoint['user_method'])](opt_options, opt_parameters);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// Construct the methods for each API endpoint.
|
||||
if (!window.__endpoints) {
|
||||
return apiService;
|
||||
}
|
||||
|
||||
for (var i = 0; i < window.__endpoints.length; ++i) {
|
||||
var endpoint = window.__endpoints[i];
|
||||
buildMethodsForEndpoint(endpoint);
|
||||
}
|
||||
|
||||
return apiService;
|
||||
}]);
|
||||
|
||||
$provide.factory('CookieService', ['$cookies', '$cookieStore', function($cookies, $cookieStore) {
|
||||
var cookieService = {};
|
||||
|
@ -113,7 +246,7 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
|||
return cookieService;
|
||||
}]);
|
||||
|
||||
$provide.factory('UserService', ['Restangular', 'CookieService', function(Restangular, CookieService) {
|
||||
$provide.factory('UserService', ['ApiService', 'CookieService', function(ApiService, CookieService) {
|
||||
var userResponse = {
|
||||
verified: false,
|
||||
anonymous: true,
|
||||
|
@ -139,8 +272,7 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
|||
};
|
||||
|
||||
userService.load = function(opt_callback) {
|
||||
var userFetch = Restangular.one('user/');
|
||||
userFetch.get().then(function(loadedUser) {
|
||||
ApiService.getLoggedInUser().then(function(loadedUser) {
|
||||
userResponse = loadedUser;
|
||||
|
||||
if (!userResponse.anonymous) {
|
||||
|
@ -198,48 +330,6 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
|||
return userService;
|
||||
}]);
|
||||
|
||||
|
||||
$provide.factory('ApiService', ['Restangular', function(Restangular) {
|
||||
var apiService = {}
|
||||
apiService.at = function(locationPieces) {
|
||||
var location = getRestUrl.apply(this, arguments);
|
||||
var info = {
|
||||
'url': location,
|
||||
'caller': Restangular.one(location),
|
||||
'withOptions': function(options) {
|
||||
info.options = options;
|
||||
return info;
|
||||
},
|
||||
'get': function(processor, opt_errorHandler) {
|
||||
var options = info.options;
|
||||
var caller = info.caller;
|
||||
var result = {
|
||||
'loading': true,
|
||||
'value': null,
|
||||
'hasError': false
|
||||
};
|
||||
|
||||
caller.get(options).then(function(resp) {
|
||||
result.value = processor(resp);
|
||||
result.loading = false;
|
||||
}, function(resp) {
|
||||
result.hasError = true;
|
||||
result.loading = false;
|
||||
if (opt_errorHandler) {
|
||||
opt_errorHandler(resp);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
return info;
|
||||
};
|
||||
|
||||
return apiService;
|
||||
}]);
|
||||
|
||||
$provide.factory('KeyService', ['$location', function($location) {
|
||||
var keyService = {}
|
||||
|
||||
|
@ -254,13 +344,17 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
|||
return keyService;
|
||||
}]);
|
||||
|
||||
$provide.factory('PlanService', ['Restangular', 'KeyService', 'UserService', 'CookieService',
|
||||
function(Restangular, KeyService, UserService, CookieService) {
|
||||
$provide.factory('PlanService', ['KeyService', 'UserService', 'CookieService', 'ApiService',
|
||||
function(KeyService, UserService, CookieService, ApiService) {
|
||||
var plans = null;
|
||||
var planDict = {};
|
||||
var planService = {};
|
||||
var listeners = [];
|
||||
|
||||
planService.getFreePlan = function() {
|
||||
return 'free';
|
||||
};
|
||||
|
||||
planService.registerListener = function(obj, callback) {
|
||||
listeners.push({'obj': obj, 'callback': callback});
|
||||
};
|
||||
|
@ -278,6 +372,27 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
|||
CookieService.putSession('quay.notedplan', planId);
|
||||
};
|
||||
|
||||
planService.isOrgCompatible = function(plan) {
|
||||
return plan['stripeId'] == planService.getFreePlan() || plan['bus_features'];
|
||||
};
|
||||
|
||||
planService.getMatchingBusinessPlan = function(callback) {
|
||||
planService.getPlans(function() {
|
||||
planService.getSubscription(null, function(sub) {
|
||||
var plan = planDict[sub.plan];
|
||||
if (!plan) {
|
||||
planService.getMinimumPlan(0, true, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
var count = Math.max(sub.usedPrivateRepos, plan.privateRepos);
|
||||
planService.getMinimumPlan(count, true, callback);
|
||||
}, function() {
|
||||
planService.getMinimumPlan(0, true, callback);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
planService.handleNotedPlan = function() {
|
||||
var planId = planService.getAndResetNotedPlan();
|
||||
if (!planId) { return; }
|
||||
|
@ -288,13 +403,11 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
|||
}
|
||||
|
||||
planService.getPlan(planId, function(plan) {
|
||||
planService.isBusinessPlan(planId, function(bus) {
|
||||
if (bus) {
|
||||
document.location = '/organizations/new/?plan=' + planId;
|
||||
} else {
|
||||
document.location = '/user?plan=' + planId;
|
||||
}
|
||||
});
|
||||
if (planService.isOrgCompatible(plan)) {
|
||||
document.location = '/organizations/new/?plan=' + planId;
|
||||
} else {
|
||||
document.location = '/user?plan=' + planId;
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -330,72 +443,53 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
|||
return;
|
||||
}
|
||||
|
||||
var getPlans = Restangular.one('plans');
|
||||
getPlans.get().then(function(data) {
|
||||
ApiService.listPlans().then(function(data) {
|
||||
var i = 0;
|
||||
for(i = 0; i < data.user.length; i++) {
|
||||
planDict[data.user[i].stripeId] = data.user[i];
|
||||
for(i = 0; i < data.plans.length; i++) {
|
||||
planDict[data.plans[i].stripeId] = data.plans[i];
|
||||
}
|
||||
for(i = 0; i < data.business.length; i++) {
|
||||
planDict[data.business[i].stripeId] = data.business[i];
|
||||
}
|
||||
plans = data;
|
||||
plans = data.plans;
|
||||
callback(plans);
|
||||
}, function() { callback([]); });
|
||||
};
|
||||
|
||||
planService.getMatchingBusinessPlan = function(callback) {
|
||||
planService.getPlans(function() {
|
||||
planService.getSubscription(null, function(sub) {
|
||||
var plan = planDict[sub.plan];
|
||||
if (!plan) {
|
||||
planService.getMinimumPlan(0, true, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
var count = Math.max(sub.usedPrivateRepos, plan.privateRepos);
|
||||
planService.getMinimumPlan(count, true, callback);
|
||||
}, function() {
|
||||
planService.getMinimumPlan(0, true, callback);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
planService.isBusinessPlan = function(planId, callback) {
|
||||
planService.getPlans = function(callback, opt_includePersonal) {
|
||||
planService.verifyLoaded(function() {
|
||||
planSource = plans.business;
|
||||
for (var i = 0; i < planSource.length; i++) {
|
||||
var plan = planSource[i];
|
||||
if (plan.stripeId == planId) {
|
||||
callback(true);
|
||||
return;
|
||||
}
|
||||
var filtered = [];
|
||||
for (var i = 0; i < plans.length; ++i) {
|
||||
var plan = plans[i];
|
||||
if (plan['deprecated']) { continue; }
|
||||
if (!opt_includePersonal && !planService.isOrgCompatible(plan)) { continue; }
|
||||
filtered.push(plan);
|
||||
}
|
||||
callback(false);
|
||||
callback(filtered);
|
||||
});
|
||||
};
|
||||
|
||||
planService.getPlans = function(callback) {
|
||||
planService.verifyLoaded(callback);
|
||||
};
|
||||
|
||||
planService.getPlan = function(planId, callback) {
|
||||
planService.getPlanIncludingDeprecated(planId, function(plan) {
|
||||
if (!plan['deprecated']) {
|
||||
callback(plan);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
planService.getPlanIncludingDeprecated = function(planId, callback) {
|
||||
planService.verifyLoaded(function() {
|
||||
if (planDict[planId]) {
|
||||
if (planDict[planId]) {
|
||||
callback(planDict[planId]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
planService.getMinimumPlan = function(privateCount, isBusiness, callback) {
|
||||
planService.verifyLoaded(function() {
|
||||
var planSource = plans.user;
|
||||
if (isBusiness) {
|
||||
planSource = plans.business;
|
||||
}
|
||||
planService.getPlans(function(plans) {
|
||||
for (var i = 0; i < plans.length; i++) {
|
||||
var plan = plans[i];
|
||||
if (isBusiness && !planService.isOrgCompatible(plan)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (var i = 0; i < planSource.length; i++) {
|
||||
var plan = planSource[i];
|
||||
if (plan.privateRepos >= privateCount) {
|
||||
callback(plan);
|
||||
return;
|
||||
|
@ -407,13 +501,7 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
|||
};
|
||||
|
||||
planService.getSubscription = function(orgname, success, failure) {
|
||||
var url = planService.getSubscriptionUrl(orgname);
|
||||
var getSubscription = Restangular.one(url);
|
||||
getSubscription.get().then(success, failure);
|
||||
};
|
||||
|
||||
planService.getSubscriptionUrl = function(orgname) {
|
||||
return orgname ? getRestUrl('organization', orgname, 'plan') : 'user/plan';
|
||||
ApiService.getSubscription(orgname).then(success, failure);
|
||||
};
|
||||
|
||||
planService.setSubscription = function(orgname, planId, success, failure, opt_token) {
|
||||
|
@ -425,9 +513,7 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
|||
subscriptionDetails['token'] = opt_token.id;
|
||||
}
|
||||
|
||||
var url = planService.getSubscriptionUrl(orgname);
|
||||
var createSubscriptionRequest = Restangular.one(url);
|
||||
createSubscriptionRequest.customPUT(subscriptionDetails).then(function(resp) {
|
||||
ApiService.updateSubscription(orgname, subscriptionDetails).then(function(resp) {
|
||||
success(resp);
|
||||
planService.getPlan(planId, function(plan) {
|
||||
for (var i = 0; i < listeners.length; ++i) {
|
||||
|
@ -438,9 +524,7 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
|||
};
|
||||
|
||||
planService.getCardInfo = function(orgname, callback) {
|
||||
var url = orgname ? getRestUrl('organization', orgname, 'card') : 'user/card';
|
||||
var getCard = Restangular.one(url);
|
||||
getCard.customGET().then(function(resp) {
|
||||
ApiService.getCard(orgname).then(function(resp) {
|
||||
callback(resp.card);
|
||||
}, function() {
|
||||
callback({'is_valid': false});
|
||||
|
@ -453,6 +537,8 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
|||
}
|
||||
|
||||
planService.getPlan(planId, function(plan) {
|
||||
if (orgname && !planService.isOrgCompatible(plan)) { return; }
|
||||
|
||||
planService.getCardInfo(orgname, function(cardInfo) {
|
||||
if (plan.price > 0 && !cardInfo.last4) {
|
||||
planService.showSubscribeDialog($scope, orgname, planId, callbacks);
|
||||
|
@ -485,12 +571,10 @@ quayApp = angular.module('quay', ['ngRoute', 'chieffancypants.loadingBar', 'rest
|
|||
'token': token.id
|
||||
};
|
||||
|
||||
var url = orgname ? getRestUrl('organization', orgname, 'card') : 'user/card';
|
||||
var changeCardRequest = Restangular.one(url);
|
||||
changeCardRequest.customPOST(cardInfo).then(callbacks['success'], function(resp) {
|
||||
planService.handleCardError(resp);
|
||||
callbacks['failure'](resp);
|
||||
});
|
||||
ApiService.setCard(orgname, cardInfo).then(callbacks['success'], function(resp) {
|
||||
planService.handleCardError(resp);
|
||||
callbacks['failure'](resp);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -732,10 +816,9 @@ quayApp.directive('userSetup', function () {
|
|||
'signInStarted': '&signInStarted',
|
||||
'signedIn': '&signedIn'
|
||||
},
|
||||
controller: function($scope, $location, $timeout, Restangular, KeyService, UserService) {
|
||||
controller: function($scope, $location, $timeout, ApiService, KeyService, UserService) {
|
||||
$scope.sendRecovery = function() {
|
||||
var signinPost = Restangular.one('recovery');
|
||||
signinPost.customPOST($scope.recovery).then(function() {
|
||||
ApiService.requestRecoveryEmail($scope.recovery).then(function() {
|
||||
$scope.invalidEmail = false;
|
||||
$scope.sent = true;
|
||||
}, function(result) {
|
||||
|
@ -765,7 +848,7 @@ quayApp.directive('signinForm', function () {
|
|||
'signInStarted': '&signInStarted',
|
||||
'signedIn': '&signedIn'
|
||||
},
|
||||
controller: function($scope, $location, $timeout, Restangular, KeyService, UserService) {
|
||||
controller: function($scope, $location, $timeout, ApiService, KeyService, UserService) {
|
||||
$scope.showGithub = function() {
|
||||
$scope.markStarted();
|
||||
|
||||
|
@ -792,8 +875,7 @@ quayApp.directive('signinForm', function () {
|
|||
$scope.signin = function() {
|
||||
$scope.markStarted();
|
||||
|
||||
var signinPost = Restangular.one('signin');
|
||||
signinPost.customPOST($scope.user).then(function() {
|
||||
ApiService.signinUser($scope.user).then(function() {
|
||||
$scope.needsEmailVerification = false;
|
||||
$scope.invalidCredentials = false;
|
||||
|
||||
|
@ -833,7 +915,7 @@ quayApp.directive('signupForm', function () {
|
|||
scope: {
|
||||
|
||||
},
|
||||
controller: function($scope, $location, $timeout, Restangular, KeyService, UserService) {
|
||||
controller: function($scope, $location, $timeout, ApiService, KeyService, UserService) {
|
||||
$('.form-signup').popover();
|
||||
|
||||
angulartics.waitForVendorApi(mixpanel, 500, function(loadedMixpanel) {
|
||||
|
@ -850,8 +932,7 @@ quayApp.directive('signupForm', function () {
|
|||
$('.form-signup').popover('hide');
|
||||
$scope.registering = true;
|
||||
|
||||
var newUserPost = Restangular.one('user/');
|
||||
newUserPost.customPOST($scope.newUser).then(function() {
|
||||
ApiService.createNewUser($scope.newUser).then(function() {
|
||||
$scope.awaitingConfirmation = true;
|
||||
$scope.registering = false;
|
||||
|
||||
|
@ -904,7 +985,7 @@ quayApp.directive('dockerAuthDialog', function () {
|
|||
'shown': '=shown',
|
||||
'counter': '=counter'
|
||||
},
|
||||
controller: function($scope, $element, Restangular) {
|
||||
controller: function($scope, $element) {
|
||||
$scope.isDownloadSupported = function() {
|
||||
try { return !!new Blob(); } catch(e){}
|
||||
return false;
|
||||
|
@ -962,6 +1043,53 @@ quayApp.filter('visibleLogFilter', function () {
|
|||
});
|
||||
|
||||
|
||||
quayApp.directive('billingInvoices', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/billing-invoices.html',
|
||||
replace: false,
|
||||
transclude: false,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'organization': '=organization',
|
||||
'user': '=user',
|
||||
'visible': '=visible'
|
||||
},
|
||||
controller: function($scope, $element, $sce, ApiService) {
|
||||
$scope.loading = false;
|
||||
$scope.invoiceExpanded = {};
|
||||
|
||||
$scope.toggleInvoice = function(id) {
|
||||
$scope.invoiceExpanded[id] = !$scope.invoiceExpanded[id];
|
||||
};
|
||||
|
||||
var update = function() {
|
||||
var hasValidUser = !!$scope.user;
|
||||
var hasValidOrg = !!$scope.organization;
|
||||
var isValid = hasValidUser || hasValidOrg;
|
||||
|
||||
if (!$scope.visible || !isValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.loading = true;
|
||||
|
||||
ApiService.listInvoices($scope.organization).then(function(resp) {
|
||||
$scope.invoices = resp.invoices;
|
||||
$scope.loading = false;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$watch('organization', update);
|
||||
$scope.$watch('user', update);
|
||||
$scope.$watch('visible', update);
|
||||
}
|
||||
};
|
||||
|
||||
return directiveDefinitionObject;
|
||||
});
|
||||
|
||||
|
||||
quayApp.directive('logsView', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
|
@ -976,7 +1104,7 @@ quayApp.directive('logsView', function () {
|
|||
'repository': '=repository',
|
||||
'performer': '=performer'
|
||||
},
|
||||
controller: function($scope, $element, $sce, Restangular) {
|
||||
controller: function($scope, $element, $sce, Restangular, ApiService) {
|
||||
$scope.loading = true;
|
||||
$scope.logs = null;
|
||||
$scope.kindsAllowed = null;
|
||||
|
@ -1092,6 +1220,8 @@ quayApp.directive('logsView', function () {
|
|||
|
||||
$scope.loading = true;
|
||||
|
||||
// Note: We construct the URLs here manually because we also use it for the download
|
||||
// path.
|
||||
var url = getRestUrl('user/logs');
|
||||
if ($scope.organization) {
|
||||
url = getRestUrl('organization', $scope.organization.name, 'logs');
|
||||
|
@ -1195,7 +1325,7 @@ quayApp.directive('robotsManager', function () {
|
|||
'organization': '=organization',
|
||||
'user': '=user'
|
||||
},
|
||||
controller: function($scope, $element, Restangular) {
|
||||
controller: function($scope, $element, ApiService) {
|
||||
$scope.ROBOT_PATTERN = ROBOT_PATTERN;
|
||||
$scope.robots = null;
|
||||
$scope.loading = false;
|
||||
|
@ -1220,7 +1350,7 @@ quayApp.directive('robotsManager', function () {
|
|||
$scope.createRobot = function(name) {
|
||||
if (!name) { return; }
|
||||
|
||||
createRobotAccount(Restangular, !!$scope.organization, $scope.organization ? $scope.organization.name : '', name,
|
||||
createRobotAccount(ApiService, !!$scope.organization, $scope.organization ? $scope.organization.name : '', name,
|
||||
function(created) {
|
||||
$scope.robots.push(created);
|
||||
});
|
||||
|
@ -1228,11 +1358,7 @@ quayApp.directive('robotsManager', function () {
|
|||
|
||||
$scope.deleteRobot = function(info) {
|
||||
var shortName = $scope.getShortenedName(info.name);
|
||||
var url = $scope.organization ? getRestUrl('organization', $scope.organization.name, 'robots', shortName) :
|
||||
getRestUrl('user/robots', shortName);
|
||||
|
||||
var deleteRobot = Restangular.one(url);
|
||||
deleteRobot.customDELETE().then(function(resp) {
|
||||
ApiService.deleteRobot($scope.organization, null, {'robot_shortname': shortName}).then(function(resp) {
|
||||
for (var i = 0; i < $scope.robots.length; ++i) {
|
||||
if ($scope.robots[i].name == info.name) {
|
||||
$scope.robots.splice(i, 1);
|
||||
|
@ -1258,9 +1384,7 @@ quayApp.directive('robotsManager', function () {
|
|||
if ($scope.loading) { return; }
|
||||
|
||||
$scope.loading = true;
|
||||
var url = $scope.organization ? getRestUrl('organization', $scope.organization.name, 'robots') : 'user/robots';
|
||||
var getRobots = Restangular.one(url);
|
||||
getRobots.customGET($scope.obj).then(function(resp) {
|
||||
ApiService.getRobots($scope.organization).then(function(resp) {
|
||||
$scope.robots = resp.robots;
|
||||
$scope.loading = false;
|
||||
});
|
||||
|
@ -1493,7 +1617,7 @@ quayApp.directive('headerBar', function () {
|
|||
restrict: 'C',
|
||||
scope: {
|
||||
},
|
||||
controller: function($scope, $element, $location, UserService, PlanService, Restangular) {
|
||||
controller: function($scope, $element, $location, UserService, PlanService, ApiService) {
|
||||
$scope.overPlan = false;
|
||||
|
||||
var checkOverPlan = function() {
|
||||
|
@ -1502,8 +1626,7 @@ quayApp.directive('headerBar', function () {
|
|||
return;
|
||||
}
|
||||
|
||||
var checkPrivate = Restangular.one('user/private');
|
||||
checkPrivate.customGET().then(function(resp) {
|
||||
ApiService.getUserPrivateCount().then(function(resp) {
|
||||
$scope.overPlan = resp.privateCount > resp.reposAllowed;
|
||||
});
|
||||
};
|
||||
|
@ -1515,10 +1638,9 @@ quayApp.directive('headerBar', function () {
|
|||
PlanService.registerListener(this, checkOverPlan);
|
||||
|
||||
$scope.signout = function() {
|
||||
var signoutPost = Restangular.one('signout');
|
||||
signoutPost.customPOST().then(function() {
|
||||
UserService.load();
|
||||
$location.path('/');
|
||||
ApiService.logout().then(function() {
|
||||
UserService.load();
|
||||
$location.path('/');
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -1549,7 +1671,7 @@ quayApp.directive('entitySearch', function () {
|
|||
'includeTeams': '=includeTeams',
|
||||
'isOrganization': '=isOrganization'
|
||||
},
|
||||
controller: function($scope, $element, Restangular, UserService) {
|
||||
controller: function($scope, $element, Restangular, UserService, ApiService) {
|
||||
$scope.lazyLoading = true;
|
||||
$scope.isAdmin = false;
|
||||
|
||||
|
@ -1559,16 +1681,12 @@ quayApp.directive('entitySearch', function () {
|
|||
$scope.isAdmin = UserService.isNamespaceAdmin($scope.namespace);
|
||||
|
||||
if ($scope.isOrganization && $scope.includeTeams) {
|
||||
var url = getRestUrl('organization', $scope.namespace);
|
||||
var getOrganization = Restangular.one(url);
|
||||
getOrganization.customGET().then(function(resp) {
|
||||
ApiService.getOrganization(null, {'orgname': $scope.namespace}).then(function(resp) {
|
||||
$scope.teams = resp.teams;
|
||||
});
|
||||
}
|
||||
|
||||
var url = $scope.isOrganization ? getRestUrl('organization', $scope.namespace, 'robots') : 'user/robots';
|
||||
var getRobots = Restangular.one(url);
|
||||
getRobots.customGET().then(function(resp) {
|
||||
ApiService.getRobots($scope.isOrganization ? $scope.namespace : null).then(function(resp) {
|
||||
$scope.robots = resp.robots;
|
||||
$scope.lazyLoading = false;
|
||||
}, function() {
|
||||
|
@ -1588,7 +1706,7 @@ quayApp.directive('entitySearch', function () {
|
|||
return;
|
||||
}
|
||||
|
||||
createOrganizationTeam(Restangular, $scope.namespace, teamname, function(created) {
|
||||
createOrganizationTeam(ApiService, $scope.namespace, teamname, function(created) {
|
||||
$scope.setEntity(created.name, 'team', false);
|
||||
$scope.teams[teamname] = created;
|
||||
});
|
||||
|
@ -1607,7 +1725,7 @@ quayApp.directive('entitySearch', function () {
|
|||
return;
|
||||
}
|
||||
|
||||
createRobotAccount(Restangular, $scope.isOrganization, $scope.namespace, robotname, function(created) {
|
||||
createRobotAccount(ApiService, $scope.isOrganization, $scope.namespace, robotname, function(created) {
|
||||
$scope.setEntity(created.name, 'user', true);
|
||||
$scope.robots.push(created);
|
||||
});
|
||||
|
@ -1733,7 +1851,7 @@ quayApp.directive('billingOptions', function () {
|
|||
'user': '=user',
|
||||
'organization': '=organization'
|
||||
},
|
||||
controller: function($scope, $element, PlanService, Restangular) {
|
||||
controller: function($scope, $element, PlanService, ApiService) {
|
||||
$scope.invoice_email = false;
|
||||
$scope.currentCard = null;
|
||||
|
||||
|
@ -1803,9 +1921,7 @@ quayApp.directive('billingOptions', function () {
|
|||
|
||||
var save = function() {
|
||||
$scope.working = true;
|
||||
var url = $scope.organization ? getRestUrl('organization', $scope.organization.name) : 'user/';
|
||||
var conductSave = Restangular.one(url);
|
||||
conductSave.customPUT($scope.obj).then(function(resp) {
|
||||
ApiService.changeDetails($scope.organization, $scope.obj).then(function(resp) {
|
||||
$scope.working = false;
|
||||
});
|
||||
};
|
||||
|
@ -1840,11 +1956,19 @@ quayApp.directive('planManager', function () {
|
|||
'readyForPlan': '&readyForPlan',
|
||||
'planChanged': '&planChanged'
|
||||
},
|
||||
controller: function($scope, $element, PlanService, Restangular) {
|
||||
controller: function($scope, $element, PlanService, ApiService) {
|
||||
var hasSubscription = false;
|
||||
|
||||
$scope.getActiveSubClass = function() {
|
||||
return 'active';
|
||||
$scope.isPlanVisible = function(plan, subscribedPlan) {
|
||||
if (plan['deprecated']) {
|
||||
return plan == subscribedPlan;
|
||||
}
|
||||
|
||||
if ($scope.organization && !PlanService.isOrgCompatible(plan)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
$scope.changeSubscription = function(planId) {
|
||||
|
@ -1865,17 +1989,17 @@ quayApp.directive('planManager', function () {
|
|||
};
|
||||
|
||||
$scope.cancelSubscription = function() {
|
||||
$scope.changeSubscription(getFreePlan());
|
||||
$scope.changeSubscription(PlanService.getFreePlan());
|
||||
};
|
||||
|
||||
var subscribedToPlan = function(sub) {
|
||||
$scope.subscription = sub;
|
||||
|
||||
if (sub.plan != getFreePlan()) {
|
||||
if (sub.plan != PlanService.getFreePlan()) {
|
||||
hasSubscription = true;
|
||||
}
|
||||
|
||||
PlanService.getPlan(sub.plan, function(subscribedPlan) {
|
||||
PlanService.getPlanIncludingDeprecated(sub.plan, function(subscribedPlan) {
|
||||
$scope.subscribedPlan = subscribedPlan;
|
||||
$scope.planUsagePercent = sub.usedPrivateRepos * 100 / $scope.subscribedPlan.privateRepos;
|
||||
|
||||
|
@ -1905,22 +2029,13 @@ quayApp.directive('planManager', function () {
|
|||
});
|
||||
};
|
||||
|
||||
var getFreePlan = function() {
|
||||
for (var i = 0; i < $scope.plans.length; ++i) {
|
||||
if ($scope.plans[i].price == 0) {
|
||||
return $scope.plans[i].stripeId;
|
||||
}
|
||||
}
|
||||
return 'free';
|
||||
};
|
||||
|
||||
var update = function() {
|
||||
$scope.planLoading = true;
|
||||
if (!$scope.plans) { return; }
|
||||
|
||||
PlanService.getSubscription($scope.organization, subscribedToPlan, function() {
|
||||
// User/Organization has no subscription.
|
||||
subscribedToPlan({ 'plan': getFreePlan() });
|
||||
subscribedToPlan({ 'plan': PlanService.getFreePlan() });
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -1929,13 +2044,13 @@ quayApp.directive('planManager', function () {
|
|||
if (!$scope.user && !$scope.organization) { return; }
|
||||
|
||||
$scope.loadingPlans = true;
|
||||
PlanService.getPlans(function(plans) {
|
||||
$scope.plans = plans[$scope.organization ? 'business' : 'user'];
|
||||
PlanService.verifyLoaded(function(plans) {
|
||||
$scope.plans = plans;
|
||||
update();
|
||||
|
||||
if ($scope.readyForPlan) {
|
||||
var planRequested = $scope.readyForPlan();
|
||||
if (planRequested && planRequested != getFreePlan()) {
|
||||
if (planRequested && planRequested != PlanService.getFreePlan()) {
|
||||
$scope.changeSubscription(planRequested);
|
||||
}
|
||||
}
|
||||
|
@ -2101,15 +2216,27 @@ quayApp.run(['$location', '$rootScope', 'Restangular', 'UserService', 'PlanServi
|
|||
// Check if we need to redirect based on a previously chosen plan.
|
||||
PlanService.handleNotedPlan();
|
||||
|
||||
var changeTab = function(activeTab) {
|
||||
var changeTab = function(activeTab, opt_timeout) {
|
||||
var checkCount = 0;
|
||||
|
||||
$timeout(function() {
|
||||
if (checkCount > 5) { return; }
|
||||
checkCount++;
|
||||
|
||||
$('a[data-toggle="tab"]').each(function(index) {
|
||||
var tabName = this.getAttribute('data-target').substr(1);
|
||||
if (tabName == activeTab) {
|
||||
this.click();
|
||||
if (tabName != activeTab) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.clientWidth == 0) {
|
||||
changeTab(activeTab, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
this.click();
|
||||
});
|
||||
});
|
||||
}, opt_timeout);
|
||||
};
|
||||
|
||||
var resetDefaultTab = function() {
|
||||
|
|
Reference in a new issue