Merge branch 'master' into looksirdroids
This commit is contained in:
commit
43f2dd80a0
38 changed files with 752 additions and 400 deletions
207
static/js/app.js
207
static/js/app.js
|
@ -47,7 +47,7 @@ function getMarkedDown(string) {
|
|||
}
|
||||
|
||||
// Start the application code itself.
|
||||
quayApp = angular.module('quay', ['restangular', 'angularMoment', 'angulartics', 'angulartics.mixpanel', '$strap.directives', 'ngCookies'], function($provide) {
|
||||
quayApp = angular.module('quay', ['ngRoute', 'restangular', 'angularMoment', 'angulartics', 'angulartics.mixpanel', '$strap.directives', 'ngCookies'], function($provide) {
|
||||
$provide.factory('UserService', ['Restangular', function(Restangular) {
|
||||
var userResponse = {
|
||||
verified: false,
|
||||
|
@ -137,7 +137,26 @@ quayApp = angular.module('quay', ['restangular', 'angularMoment', 'angulartics',
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
planService.handleCardError = function(resp) {
|
||||
if (!planService.isCardError(resp)) { return; }
|
||||
|
||||
bootbox.dialog({
|
||||
"message": resp.data.carderror,
|
||||
"title": "Credit card issue",
|
||||
"buttons": {
|
||||
"close": {
|
||||
"label": "Close",
|
||||
"className": "btn-primary"
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
planService.isCardError = function(resp) {
|
||||
return resp && resp.data && resp.data.carderror;
|
||||
};
|
||||
|
||||
planService.verifyLoaded = function(callback) {
|
||||
if (plans) {
|
||||
callback(plans);
|
||||
|
@ -259,7 +278,10 @@ quayApp = angular.module('quay', ['restangular', 'angularMoment', 'angulartics',
|
|||
return;
|
||||
}
|
||||
|
||||
planService.setSubscription(orgname, planId, callbacks['success'], callbacks['failure']);
|
||||
planService.setSubscription(orgname, planId, callbacks['success'], function(resp) {
|
||||
planService.handleCardError(resp);
|
||||
callbacks['failure'](resp);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
@ -269,7 +291,10 @@ quayApp = angular.module('quay', ['restangular', 'angularMoment', 'angulartics',
|
|||
callbacks['opening']();
|
||||
}
|
||||
|
||||
var submitted = false;
|
||||
var submitToken = function(token) {
|
||||
if (submitted) { return; }
|
||||
submitted = true;
|
||||
$scope.$apply(function() {
|
||||
if (callbacks['started']) {
|
||||
callbacks['started']();
|
||||
|
@ -281,7 +306,10 @@ quayApp = angular.module('quay', ['restangular', 'angularMoment', 'angulartics',
|
|||
|
||||
var url = orgname ? getRestUrl('organization', orgname, 'card') : 'user/card';
|
||||
var changeCardRequest = Restangular.one(url);
|
||||
changeCardRequest.customPOST(cardInfo).then(callbacks['success'], callbacks['failure']);
|
||||
changeCardRequest.customPOST(cardInfo).then(callbacks['success'], function(resp) {
|
||||
planService.handleCardError(resp);
|
||||
callbacks['failure'](resp);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -321,7 +349,11 @@ quayApp = angular.module('quay', ['restangular', 'angularMoment', 'angulartics',
|
|||
callbacks['opening']();
|
||||
}
|
||||
|
||||
var submitted = false;
|
||||
var submitToken = function(token) {
|
||||
if (submitted) { return; }
|
||||
submitted = true;
|
||||
|
||||
mixpanel.track('plan_subscribe');
|
||||
|
||||
$scope.$apply(function() {
|
||||
|
@ -395,26 +427,31 @@ quayApp = angular.module('quay', ['restangular', 'angularMoment', 'angulartics',
|
|||
// index rule to make sure that deep links directly deep into the app continue to work.
|
||||
// WARNING WARNING WARNING
|
||||
$routeProvider.
|
||||
when('/repository/:namespace/:name', {templateUrl: '/static/partials/view-repo.html', controller: RepoCtrl, reloadOnSearch: false}).
|
||||
when('/repository/:namespace/:name/tag/:tag', {templateUrl: '/static/partials/view-repo.html', controller: RepoCtrl}).
|
||||
when('/repository/:namespace/:name', {templateUrl: '/static/partials/view-repo.html', controller: RepoCtrl,
|
||||
hideFooter: true, reloadOnSearch: false}).
|
||||
when('/repository/:namespace/:name/tag/:tag', {templateUrl: '/static/partials/view-repo.html', controller: RepoCtrl,
|
||||
hideFooter: true}).
|
||||
when('/repository/:namespace/:name/image/:image', {templateUrl: '/static/partials/image-view.html', controller: ImageViewCtrl}).
|
||||
when('/repository/:namespace/:name/admin', {templateUrl: '/static/partials/repo-admin.html', controller:RepoAdminCtrl}).
|
||||
when('/repository/', {title: 'Repositories', templateUrl: '/static/partials/repo-list.html', controller: RepoListCtrl}).
|
||||
when('/user/', {title: 'Account Settings', templateUrl: '/static/partials/user-admin.html', controller: UserAdminCtrl}).
|
||||
when('/guide/', {title: 'Guide', templateUrl: '/static/partials/guide.html', controller: GuideCtrl}).
|
||||
when('/plans/', {title: 'Plans and Pricing', templateUrl: '/static/partials/plans.html', controller: PlansCtrl}).
|
||||
when('/signin/', {title: 'Sign In', templateUrl: '/static/partials/signin.html', controller: SigninCtrl}).
|
||||
when('/new/', {title: 'Create new repository', templateUrl: '/static/partials/new-repo.html', controller: NewRepoCtrl}).
|
||||
|
||||
when('/organizations/', {title: 'Organizations', templateUrl: '/static/partials/organizations.html', controller: OrgsCtrl}).
|
||||
when('/organizations/new/', {title: 'New Organization', templateUrl: '/static/partials/new-organization.html', controller: NewOrgCtrl}).
|
||||
|
||||
when('/repository/', {title: 'Repositories', description: 'Public and private docker repositories list',
|
||||
templateUrl: '/static/partials/repo-list.html', controller: RepoListCtrl}).
|
||||
when('/user/', {title: 'Account Settings', description:'Account settings for Quay.io', templateUrl: '/static/partials/user-admin.html', controller: UserAdminCtrl}).
|
||||
when('/guide/', {title: 'Guide', description:'Guide to using private docker repositories on Quay.io', templateUrl: '/static/partials/guide.html', controller: GuideCtrl}).
|
||||
when('/plans/', {title: 'Plans and Pricing', description: 'Plans and pricing for private docker repositories on Quay.io',
|
||||
templateUrl: '/static/partials/plans.html', controller: PlansCtrl}).
|
||||
when('/security/', {title: 'Security', description: 'Security features used when transmitting and storing data',
|
||||
templateUrl: '/static/partials/security.html', controller: SecurityCtrl}).
|
||||
when('/signin/', {title: 'Sign In', description: 'Sign into Quay.io', templateUrl: '/static/partials/signin.html', controller: SigninCtrl}).
|
||||
when('/new/', {title: 'Create new repository', description: 'Create a new public or private docker repository, optionally constructing from a dockerfile',
|
||||
templateUrl: '/static/partials/new-repo.html', controller: NewRepoCtrl}).
|
||||
when('/organizations/', {title: 'Organizations', description: 'Private docker repository hosting for businesses and organizations',
|
||||
templateUrl: '/static/partials/organizations.html', controller: OrgsCtrl}).
|
||||
when('/organizations/new/', {title: 'New Organization', description: 'Create a new organization on Quay.io',
|
||||
templateUrl: '/static/partials/new-organization.html', controller: NewOrgCtrl}).
|
||||
when('/organization/:orgname', {templateUrl: '/static/partials/org-view.html', controller: OrgViewCtrl}).
|
||||
when('/organization/:orgname/admin', {templateUrl: '/static/partials/org-admin.html', controller: OrgAdminCtrl}).
|
||||
when('/organization/:orgname/teams/:teamname', {templateUrl: '/static/partials/team-view.html', controller: TeamViewCtrl}).
|
||||
|
||||
when('/v1/', {title: 'Activation information', templateUrl: '/static/partials/v1-page.html', controller: V1Ctrl}).
|
||||
|
||||
when('/', {title: 'Hosted Private Docker Registry', templateUrl: '/static/partials/landing.html', controller: LandingCtrl}).
|
||||
otherwise({redirectTo: '/'});
|
||||
}]).
|
||||
|
@ -434,12 +471,12 @@ quayApp.directive('markdownView', function () {
|
|||
'content': '=content',
|
||||
'firstLineOnly': '=firstLineOnly'
|
||||
},
|
||||
controller: function($scope, $element) {
|
||||
controller: function($scope, $element, $sce) {
|
||||
$scope.getMarkedDown = function(content, firstLineOnly) {
|
||||
if (firstLineOnly) {
|
||||
content = getFirstTextLine(content);
|
||||
}
|
||||
return getMarkedDown(content);
|
||||
return $sce.trustAsHtml(getMarkedDown(content));
|
||||
};
|
||||
}
|
||||
};
|
||||
|
@ -661,6 +698,103 @@ quayApp.directive('markdownInput', function () {
|
|||
});
|
||||
|
||||
|
||||
quayApp.directive('repoSearch', function () {
|
||||
var number = 0;
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/repo-search.html',
|
||||
replace: false,
|
||||
transclude: false,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
},
|
||||
controller: function($scope, $element, $location, UserService, Restangular) {
|
||||
var searchToken = 0;
|
||||
$scope.$watch( function () { return UserService.currentUser(); }, function (currentUser) {
|
||||
++searchToken;
|
||||
}, true);
|
||||
|
||||
var element = $($element[0].childNodes[0]);
|
||||
element.typeahead({
|
||||
name: 'repositories',
|
||||
remote: {
|
||||
url: '/api/find/repository?query=%QUERY',
|
||||
replace: function (url, uriEncodedQuery) {
|
||||
url = url.replace('%QUERY', uriEncodedQuery);
|
||||
url += '&cb=' + searchToken;
|
||||
return url;
|
||||
},
|
||||
filter: function(data) {
|
||||
var datums = [];
|
||||
for (var i = 0; i < data.repositories.length; ++i) {
|
||||
var repo = data.repositories[i];
|
||||
datums.push({
|
||||
'value': repo.name,
|
||||
'tokens': [repo.name, repo.namespace],
|
||||
'repo': repo
|
||||
});
|
||||
}
|
||||
return datums;
|
||||
}
|
||||
},
|
||||
template: function (datum) {
|
||||
template = '<div class="repo-mini-listing">';
|
||||
template += '<i class="fa fa-hdd fa-lg"></i>'
|
||||
template += '<span class="name">' + datum.repo.namespace +'/' + datum.repo.name + '</span>'
|
||||
if (datum.repo.description) {
|
||||
template += '<span class="description">' + getFirstTextLine(datum.repo.description) + '</span>'
|
||||
}
|
||||
|
||||
template += '</div>'
|
||||
return template;
|
||||
}
|
||||
});
|
||||
|
||||
element.on('typeahead:selected', function (e, datum) {
|
||||
element.typeahead('setQuery', '');
|
||||
document.location = '/repository/' + datum.repo.namespace + '/' + datum.repo.name;
|
||||
});
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
});
|
||||
|
||||
|
||||
quayApp.directive('headerBar', function () {
|
||||
var number = 0;
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/header-bar.html',
|
||||
replace: false,
|
||||
transclude: false,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
},
|
||||
controller: function($scope, $element, $location, UserService, Restangular) {
|
||||
$scope.$watch( function () { return UserService.currentUser(); }, function (currentUser) {
|
||||
$scope.user = currentUser;
|
||||
}, true);
|
||||
|
||||
$scope.signout = function() {
|
||||
var signoutPost = Restangular.one('signout');
|
||||
signoutPost.customPOST().then(function() {
|
||||
UserService.load();
|
||||
$location.path('/');
|
||||
});
|
||||
};
|
||||
|
||||
$scope.appLinkTarget = function() {
|
||||
if ($("div[ng-view]").length === 0) {
|
||||
return "_self";
|
||||
}
|
||||
return "";
|
||||
};
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
});
|
||||
|
||||
|
||||
quayApp.directive('entitySearch', function () {
|
||||
var number = 0;
|
||||
var directiveDefinitionObject = {
|
||||
|
@ -795,6 +929,7 @@ quayApp.directive('billingOptions', function () {
|
|||
});
|
||||
|
||||
$scope.changeCard = function() {
|
||||
var previousCard = $scope.currentCard;
|
||||
$scope.changingCard = true;
|
||||
var callbacks = {
|
||||
'opened': function() { $scope.changingCard = true; },
|
||||
|
@ -804,9 +939,13 @@ quayApp.directive('billingOptions', function () {
|
|||
$scope.currentCard = resp.card;
|
||||
$scope.changingCard = false;
|
||||
},
|
||||
'failure': function() {
|
||||
$('#couldnotchangecardModal').modal({});
|
||||
'failure': function(resp) {
|
||||
$scope.changingCard = false;
|
||||
$scope.currentCard = previousCard;
|
||||
|
||||
if (!PlanService.isCardError(resp)) {
|
||||
$('#cannotchangecardModal').modal({});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -897,7 +1036,9 @@ quayApp.directive('planManager', function () {
|
|||
'opened': function() { $scope.planChanging = true; },
|
||||
'closed': function() { $scope.planChanging = false; },
|
||||
'success': subscribedToPlan,
|
||||
'failure': function() { $scope.planChanging = false; }
|
||||
'failure': function(resp) {
|
||||
$scope.planChanging = false;
|
||||
}
|
||||
};
|
||||
|
||||
PlanService.changePlan($scope, $scope.organization, planId, callbacks);
|
||||
|
@ -1123,7 +1264,8 @@ quayApp.directive('ngBlur', function() {
|
|||
};
|
||||
});
|
||||
|
||||
quayApp.run(['$location', '$rootScope', 'Restangular', 'UserService', function($location, $rootScope, Restangular, UserService) {
|
||||
quayApp.run(['$location', '$rootScope', 'Restangular', 'UserService', '$http',
|
||||
function($location, $rootScope, Restangular, UserService, $http) {
|
||||
Restangular.setErrorInterceptor(function(response) {
|
||||
if (response.status == 401) {
|
||||
$('#sessionexpiredModal').modal({});
|
||||
|
@ -1137,5 +1279,22 @@ quayApp.run(['$location', '$rootScope', 'Restangular', 'UserService', function($
|
|||
if (current.$$route.title) {
|
||||
$rootScope.title = current.$$route.title;
|
||||
}
|
||||
|
||||
if (current.$$route.description) {
|
||||
$rootScope.description = current.$$route.description;
|
||||
} else {
|
||||
$rootScope.description = 'Hosted private docker repositories. Includes full user management and history. Free for public repositories.';
|
||||
}
|
||||
|
||||
$rootScope.hideFooter = !!current.$$route.hideFooter;
|
||||
});
|
||||
|
||||
var initallyChecked = false;
|
||||
window.__isLoading = function() {
|
||||
if (!initallyChecked) {
|
||||
initallyChecked = true;
|
||||
return true;
|
||||
}
|
||||
return $http.pendingRequests.length > 0;
|
||||
};
|
||||
}]);
|
||||
|
|
Reference in a new issue