// Start the application code itself. quayApp = angular.module('quay', ['restangular', 'angularMoment', 'angulartics', 'angulartics.mixpanel', '$strap.directives'], function($provide) { $provide.factory('UserService', ['Restangular', function(Restangular) { var userResponse = { verified: false, anonymous: true, username: null, email: null, askForPassword: false, } var userService = {} userService.load = function() { var userFetch = Restangular.one('user/'); userFetch.get().then(function(loadedUser) { userResponse = loadedUser; if (!userResponse.anonymous) { mixpanel.identify(userResponse.username); mixpanel.people.set({ '$email': userResponse.email, '$username': userResponse.username, 'verified': userResponse.verified }); mixpanel.people.set_once({ '$created': new Date() }) } }); }; userService.currentUser = function() { return userResponse; } // Load the user the first time. userService.load(); return userService; }]); $provide.factory('KeyService', ['$location', function($location) { var keyService = {} if ($location.host() === 'quay.io') { keyService['stripePublishableKey'] = 'pk_live_P5wLU0vGdHnZGyKnXlFG4oiu'; keyService['githubClientId'] = '5a8c08b06c48d89d4d1e'; } else { keyService['stripePublishableKey'] = 'pk_test_uEDHANKm9CHCvVa2DLcipGRh'; keyService['githubClientId'] = 'cfbc4aca88e5c1b40679'; } return keyService; }]); $provide.factory('PlanService', ['Restangular', 'KeyService', function(Restangular, KeyService) { var plans = [ { title: 'Open Source', price: 0, privateRepos: 0, stripeId: 'free', audience: 'Share with the world', }, { title: 'Micro', price: 700, privateRepos: 5, stripeId: 'micro', audience: 'For smaller teams', }, { title: 'Basic', price: 1200, privateRepos: 10, stripeId: 'small', audience: 'For your basic team', }, { title: 'Medium', price: 2200, privateRepos: 20, stripeId: 'medium', audience: 'For medium-sized teams', }, ]; var planDict = {}; var i; for(i = 0; i < plans.length; i++) { planDict[plans[i].stripeId] = plans[i]; } var planService = {} planService.planList = function() { return plans; }; planService.getPlan = function(planId) { return planDict[planId]; }; planService.getMinimumPlan = function(privateCount) { for (var i = 0; i < plans.length; i++) { var plan = plans[i]; if (plan.privateRepos >= privateCount) { return plan; } } return null; }; planService.showSubscribeDialog = function($scope, planId, started, success, failed) { var submitToken = function(token) { $scope.$apply(function() { started(); }); mixpanel.track('plan_subscribe'); var subscriptionDetails = { token: token.id, plan: planId, }; var createSubscriptionRequest = Restangular.one('user/plan'); $scope.$apply(function() { createSubscriptionRequest.customPUT(subscriptionDetails).then(success, failed); }); }; var planDetails = planService.getPlan(planId) StripeCheckout.open({ key: KeyService.stripePublishableKey, address: false, // TODO change to true amount: planDetails.price, currency: 'usd', name: 'Quay ' + planDetails.title + ' Subscription', description: 'Up to ' + planDetails.privateRepos + ' private repositories', panelLabel: 'Subscribe', token: submitToken }); }; return planService; }]); }). directive('match', function($parse) { return { require: 'ngModel', link: function(scope, elem, attrs, ctrl) { scope.$watch(function() { return $parse(attrs.match)(scope) === ctrl.$modelValue; }, function(currentValue) { ctrl.$setValidity('mismatch', currentValue); }); } }; }). directive('onresize', function ($window, $parse) { return function (scope, element, attr) { var fn = $parse(attr.onresize); var notifyResized = function() { scope.$apply(function () { fn(scope); }); }; angular.element($window).on('resize', null, notifyResized); scope.$on('$destroy', function() { angular.element($window).off('resize', null, notifyResized); }); }; }). config(['$routeProvider', '$locationProvider', '$analyticsProvider', function($routeProvider, $locationProvider, $analyticsProvider) { $analyticsProvider.virtualPageviews(true); $locationProvider.html5Mode(true); // WARNING WARNING WARNING // If you add a route here, you must add a corresponding route in thr endpoints/web.py // 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/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: 'User Admin', templateUrl: '/static/partials/user-admin.html', controller: UserAdminCtrl}). when('/guide/', {title: 'User Guide', templateUrl: '/static/partials/guide.html', controller: GuideCtrl}). when('/plans/', {title: 'Plans and Pricing', templateUrl: '/static/partials/plans.html', controller: PlansCtrl}). when('/signin/', {title: 'Signin', templateUrl: '/static/partials/signin.html', controller: SigninCtrl}). when('/new/', {title: 'Create new repository', templateUrl: '/static/partials/new-repo.html', controller: NewRepoCtrl}). 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', {templateUrl: '/static/partials/org-teams.html', controller: OrgTeamsCtrl}). 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: '/'}); }]). config(function(RestangularProvider) { RestangularProvider.setBaseUrl('/api/'); }); quayApp.directive('repoCircle', function () { var directiveDefinitionObject = { priority: 0, templateUrl: '/static/directives/repo-circle.html', replace: false, transclude: false, restrict: 'C', scope: { 'repo': '=repo' }, controller: function($scope, $element) { } }; return directiveDefinitionObject; }); quayApp.directive('buildStatus', function () { var directiveDefinitionObject = { priority: 0, templateUrl: '/static/directives/build-status.html', replace: false, transclude: false, restrict: 'C', scope: { 'build': '=build' }, controller: function($scope, $element) { $scope.getBuildProgress = function(buildInfo) { switch (buildInfo.status) { case 'building': return (buildInfo.current_command / buildInfo.total_commands) * 100; break; case 'pushing': var imagePercentDecimal = (buildInfo.image_completion_percent / 100); return ((buildInfo.current_image + imagePercentDecimal) / buildInfo.total_images) * 100; break; case 'complete': return 100; break; case 'initializing': case 'starting': case 'waiting': return 0; break; } return -1; }; $scope.getBuildMessage = function(buildInfo) { switch (buildInfo.status) { case 'initializing': return 'Starting Dockerfile build'; break; case 'starting': case 'waiting': case 'building': return 'Building image from Dockerfile'; break; case 'pushing': return 'Pushing image built from Dockerfile'; break; case 'complete': return 'Dockerfile build completed and pushed'; break; case 'error': return 'Dockerfile build failed: ' + buildInfo.message; break; } }; } }; return directiveDefinitionObject; }); quayApp.run(['$location', '$rootScope', function($location, $rootScope) { $rootScope.$on('$routeChangeSuccess', function (event, current, previous) { if (current.$$route.title) { $rootScope.title = current.$$route.title; } }); }]);