2013-12-10 06:38:05 +00:00
var TEAM _PATTERN = '^[a-zA-Z][a-zA-Z0-9]+$' ;
2014-05-20 21:58:39 +00:00
var ROBOT _PATTERN = '^[a-zA-Z][a-zA-Z0-9]{3,29}$' ;
2014-10-01 18:23:15 +00:00
var USER _PATTERN = '^[a-z0-9_]{4,30}$' ;
2013-12-10 06:38:05 +00:00
2014-04-09 01:10:33 +00:00
quayDependencies = [ 'ngRoute' , 'chieffancypants.loadingBar' , 'angular-tour' , 'restangular' , 'angularMoment' ,
'mgcrea.ngStrap' , 'ngCookies' , 'ngSanitize' , 'angular-md5' , 'pasvaz.bindonce' , 'ansiToHtml' ,
2014-12-26 21:54:36 +00:00
'ngAnimate' , 'core-ui' , 'core-config-setup' ] ;
2014-04-09 01:10:33 +00:00
if ( window . _ _config && window . _ _config . MIXPANEL _KEY ) {
quayDependencies . push ( 'angulartics' ) ;
quayDependencies . push ( 'angulartics.mixpanel' ) ;
}
2015-02-19 21:21:54 +00:00
// Define the application.
2014-04-09 01:10:33 +00:00
quayApp = angular . module ( 'quay' , quayDependencies , function ( $provide , cfpLoadingBarProvider ) {
2015-02-19 21:21:54 +00:00
cfpLoadingBarProvider . includeSpinner = false ;
} ) ;
// Configure the routes.
quayApp . config ( [ '$routeProvider' , '$locationProvider' , function ( $routeProvider , $locationProvider ) {
var title = window . _ _config [ 'REGISTRY_TITLE' ] || 'Quay.io' ;
$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 ,
fixFooter : false , reloadOnSearch : false } ) .
when ( '/repository/:namespace/:name/tag/:tag' , { templateUrl : '/static/partials/view-repo.html' , controller : RepoCtrl ,
fixFooter : false } ) .
when ( '/repository/:namespace/:name/image/:image' , { templateUrl : '/static/partials/image-view.html' , controller : ImageViewCtrl , reloadOnSearch : false } ) .
when ( '/repository/:namespace/:name/admin' , { templateUrl : '/static/partials/repo-admin.html' , controller : RepoAdminCtrl , reloadOnSearch : false } ) .
when ( '/repository/:namespace/:name/build' , { templateUrl : '/static/partials/repo-build.html' , controller : RepoBuildCtrl , reloadOnSearch : false } ) .
when ( '/repository/:namespace/:name/build/:buildid/buildpack' , { templateUrl : '/static/partials/build-package.html' , controller : BuildPackageCtrl , reloadOnSearch : false } ) .
when ( '/repository/' , { title : 'Repositories' , description : 'Public and private docker repositories list' ,
templateUrl : '/static/partials/repo-list.html' , controller : RepoListCtrl , reloadOnSearch : false } ) .
when ( '/user/' , { title : 'Account Settings' , description : 'Account settings for ' + title , templateUrl : '/static/partials/user-admin.html' ,
reloadOnSearch : false , controller : UserAdminCtrl } ) .
when ( '/superuser/' , { title : 'Enterprise Registry Management' , description : 'Admin panel for ' + title , templateUrl : '/static/partials/super-user.html' ,
reloadOnSearch : false , controller : SuperUserAdminCtrl , newLayout : true } ) .
when ( '/setup/' , { title : 'Enterprise Registry Setup' , description : 'Setup for ' + title , templateUrl : '/static/partials/setup.html' ,
reloadOnSearch : false , controller : SetupCtrl , newLayout : true } ) .
when ( '/guide/' , { title : 'Guide' , description : 'Guide to using private docker repositories on ' + title ,
templateUrl : '/static/partials/guide.html' ,
controller : GuideCtrl } ) .
when ( '/tutorial/' , { title : 'Tutorial' , description : 'Interactive tutorial for using ' + title , templateUrl : '/static/partials/tutorial.html' ,
controller : TutorialCtrl } ) .
when ( '/contact/' , { title : 'Contact Us' , description : 'Different ways for you to get a hold of us when you need us most.' , templateUrl : '/static/partials/contact.html' ,
controller : ContactCtrl } ) .
when ( '/about/' , { title : 'About Us' , description : 'Information about the Quay.io team and the company.' , templateUrl : '/static/partials/about.html' } ) .
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' } ) .
when ( '/signin/' , { title : 'Sign In' , description : 'Sign into ' + title , templateUrl : '/static/partials/signin.html' , controller : SignInCtrl , reloadOnSearch : false } ) .
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 ' + title ,
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 , reloadOnSearch : false } ) .
when ( '/organization/:orgname/teams/:teamname' , { templateUrl : '/static/partials/team-view.html' , controller : TeamViewCtrl } ) .
when ( '/organization/:orgname/logs/:membername' , { templateUrl : '/static/partials/org-member-logs.html' , controller : OrgMemberLogsCtrl } ) .
when ( '/organization/:orgname/application/:clientid' , { templateUrl : '/static/partials/manage-application.html' ,
controller : ManageApplicationCtrl , reloadOnSearch : false } ) .
when ( '/v1/' , { title : 'Activation information' , templateUrl : '/static/partials/v1-page.html' , controller : V1Ctrl } ) .
when ( '/tour/' , { title : title + ' Tour' , templateUrl : '/static/partials/tour.html' , controller : TourCtrl } ) .
when ( '/tour/organizations' , { title : 'Teams and Organizations Tour' , templateUrl : '/static/partials/tour.html' , controller : TourCtrl } ) .
when ( '/tour/features' , { title : title + ' Features' , templateUrl : '/static/partials/tour.html' , controller : TourCtrl } ) .
when ( '/tour/enterprise' , { title : 'Enterprise Edition' , templateUrl : '/static/partials/tour.html' , controller : TourCtrl } ) .
when ( '/confirminvite' , { title : 'Confirm Invite' , templateUrl : '/static/partials/confirm-invite.html' , controller : ConfirmInviteCtrl , reloadOnSearch : false } ) .
when ( '/' , { title : 'Hosted Private Docker Registry' , templateUrl : '/static/partials/landing.html' , controller : LandingCtrl ,
pageClass : 'landing-page' } ) .
otherwise ( { redirectTo : '/' } ) ;
} ] ) ;
2014-01-14 21:01:37 +00:00
2015-02-19 21:21:54 +00:00
// Configure compile provider to add additional URL prefixes to the sanitization list. We use
// these on the Contact page.
quayApp . config ( function ( $compileProvider ) {
$compileProvider . aHrefSanitizationWhitelist ( /^\s*(https?|ftp|mailto|tel|irc):/ ) ;
} ) ;
2014-01-14 21:01:37 +00:00
2015-02-19 21:21:54 +00:00
// Configure the API provider.
quayApp . config ( function ( RestangularProvider ) {
RestangularProvider . setBaseUrl ( '/api/v1/' ) ;
} ) ;
2014-04-05 03:26:10 +00:00
2015-02-19 21:21:54 +00:00
// Configure analytics.
if ( window . _ _config && window . _ _config . MIXPANEL _KEY ) {
quayApp . config ( [ '$analyticsProvider' , function ( $analyticsProvider ) {
$analyticsProvider . virtualPageviews ( true ) ;
} ] ) ;
}
2014-04-05 03:26:10 +00:00
2015-02-19 21:21:54 +00:00
// Configure sentry.
if ( window . _ _config && window . _ _config . SENTRY _PUBLIC _DSN ) {
quayApp . config ( function ( $provide ) {
$provide . decorator ( "$exceptionHandler" , function ( $delegate ) {
return function ( ex , cause ) {
$delegate ( ex , cause ) ;
Raven . captureException ( ex , { extra : { cause : cause } } ) ;
2014-04-05 03:26:10 +00:00
} ;
2013-11-05 22:20:43 +00:00
} ) ;
2015-02-19 21:21:54 +00:00
} ) ;
}
2014-10-22 18:49:33 +00:00
2015-02-19 21:21:54 +00:00
// Run the application.
quayApp . run ( [ '$location' , '$rootScope' , 'Restangular' , 'UserService' , 'PlanService' , '$http' , '$timeout' , 'CookieService' , 'Features' , '$anchorScroll' , 'UtilService' ,
function ( $location , $rootScope , Restangular , UserService , PlanService , $http , $timeout , CookieService , Features , $anchorScroll , UtilService ) {
2013-12-28 19:07:44 +00:00
// Handle session security.
2014-01-27 18:58:12 +00:00
Restangular . setDefaultRequestParams ( [ 'post' , 'put' , 'remove' , 'delete' ] , { '_csrf_token' : window . _ _token || '' } ) ;
2013-12-28 19:07:44 +00:00
2013-12-11 22:50:48 +00:00
// Handle session expiration.
2013-11-12 00:26:56 +00:00
Restangular . setErrorInterceptor ( function ( response ) {
2014-09-04 18:24:20 +00:00
if ( response . status == 401 && response . data [ 'error_type' ] == 'invalid_token' &&
response . data [ 'session_required' ] !== false ) {
$ ( '#sessionexpiredModal' ) . modal ( { } ) ;
return false ;
2013-11-12 00:03:18 +00:00
}
2013-11-12 00:26:56 +00:00
2014-08-25 19:30:29 +00:00
if ( response . status == 503 ) {
$ ( '#cannotContactService' ) . modal ( { } ) ;
2014-05-28 19:22:36 +00:00
return false ;
}
2014-03-10 21:01:36 +00:00
if ( response . status == 500 ) {
document . location = '/500' ;
return false ;
}
2013-11-12 00:26:56 +00:00
return true ;
2013-11-12 00:03:18 +00:00
} ) ;
2013-12-11 22:50:48 +00:00
// Check if we need to redirect based on a previously chosen plan.
2014-03-19 18:27:33 +00:00
var result = PlanService . handleNotedPlan ( ) ;
// Check to see if we need to show a redirection page.
var redirectUrl = CookieService . get ( 'quay.redirectAfterLoad' ) ;
CookieService . clear ( 'quay.redirectAfterLoad' ) ;
if ( ! result && redirectUrl && redirectUrl . indexOf ( window . location . href ) == 0 ) {
window . location = redirectUrl ;
return ;
}
2013-12-11 22:50:48 +00:00
2013-12-21 03:38:53 +00:00
var changeTab = function ( activeTab , opt _timeout ) {
var checkCount = 0 ;
2013-12-10 04:33:28 +00:00
$timeout ( function ( ) {
2013-12-21 03:38:53 +00:00
if ( checkCount > 5 ) { return ; }
checkCount ++ ;
2013-12-10 04:33:28 +00:00
$ ( 'a[data-toggle="tab"]' ) . each ( function ( index ) {
var tabName = this . getAttribute ( 'data-target' ) . substr ( 1 ) ;
2013-12-21 03:38:53 +00:00
if ( tabName != activeTab ) {
return ;
}
if ( this . clientWidth == 0 ) {
changeTab ( activeTab , 500 ) ;
return ;
2013-12-10 04:33:28 +00:00
}
2013-12-21 03:38:53 +00:00
2015-02-19 21:21:54 +00:00
UtilService . clickElement ( this ) ;
2013-12-10 04:33:28 +00:00
} ) ;
2013-12-21 03:38:53 +00:00
} , opt _timeout ) ;
2013-12-10 04:33:28 +00:00
} ;
var resetDefaultTab = function ( ) {
$timeout ( function ( ) {
$ ( 'a[data-toggle="tab"]' ) . each ( function ( index ) {
if ( index == 0 ) {
2015-02-19 21:21:54 +00:00
UtilService . clickElement ( this ) ;
2013-12-10 04:33:28 +00:00
}
} ) ;
} ) ;
} ;
2014-04-11 21:15:03 +00:00
$rootScope . $watch ( 'description' , function ( description ) {
if ( ! description ) {
description = 'Hosted private docker repositories. Includes full user management and history. Free for public repositories.' ;
}
2014-11-24 21:07:38 +00:00
2014-04-11 21:15:03 +00:00
// Note: We set the content of the description tag manually here rather than using Angular binding
// because we need the <meta> tag to have a default description that is not of the form "{{ description }}",
// we read by tools that do not properly invoke the Angular code.
2014-11-24 21:07:38 +00:00
$ ( '#descriptionTag' ) . attr ( 'content' , description ) ;
2014-04-11 21:15:03 +00:00
} ) ;
2013-12-10 04:33:28 +00:00
$rootScope . $on ( '$routeUpdate' , function ( ) {
if ( $location . search ( ) [ 'tab' ] ) {
changeTab ( $location . search ( ) [ 'tab' ] ) ;
} else {
resetDefaultTab ( ) ;
}
} ) ;
2013-09-26 23:07:25 +00:00
$rootScope . $on ( '$routeChangeSuccess' , function ( event , current , previous ) {
2014-04-24 04:40:01 +00:00
$rootScope . pageClass = '' ;
2014-04-30 03:48:06 +00:00
$rootScope . current = current . $$route ;
if ( ! current . $$route ) { return ; }
2013-09-26 23:07:25 +00:00
if ( current . $$route . title ) {
$rootScope . title = current . $$route . title ;
}
2013-11-19 00:03:35 +00:00
2014-04-24 04:40:01 +00:00
if ( current . $$route . pageClass ) {
$rootScope . pageClass = current . $$route . pageClass ;
}
2014-12-22 20:13:23 +00:00
$rootScope . newLayout = ! ! current . $$route . newLayout ;
2013-11-19 00:03:35 +00:00
if ( current . $$route . description ) {
$rootScope . description = current . $$route . description ;
} else {
2014-04-11 21:15:03 +00:00
$rootScope . description = '' ;
2013-11-19 00:03:35 +00:00
}
2013-11-20 21:17:47 +00:00
2013-11-24 01:03:08 +00:00
$rootScope . fixFooter = ! ! current . $$route . fixFooter ;
2014-05-21 19:28:38 +00:00
$anchorScroll ( ) ;
2013-12-10 04:33:28 +00:00
} ) ;
$rootScope . $on ( '$viewContentLoaded' , function ( event , current ) {
var activeTab = $location . search ( ) [ 'tab' ] ;
// Setup deep linking of tabs. This will change the search field of the URL whenever a tab
// is changed in the UI.
2014-12-22 20:13:23 +00:00
$timeout ( function ( ) {
$ ( 'a[data-toggle="tab"]' ) . on ( 'shown.bs.tab' , function ( e ) {
var tabName = e . target . getAttribute ( 'data-target' ) . substr ( 1 ) ;
$rootScope . $apply ( function ( ) {
var isDefaultTab = $ ( 'a[data-toggle="tab"]' ) [ 0 ] == e . target ;
var newSearch = $ . extend ( $location . search ( ) , { } ) ;
if ( isDefaultTab ) {
delete newSearch [ 'tab' ] ;
} else {
newSearch [ 'tab' ] = tabName ;
}
2014-02-20 23:57:49 +00:00
2014-12-22 20:13:23 +00:00
$location . search ( newSearch ) ;
} ) ;
2014-11-24 21:07:38 +00:00
2014-12-22 20:13:23 +00:00
e . preventDefault ( ) ;
} ) ;
2013-12-10 04:33:28 +00:00
2014-12-22 20:13:23 +00:00
if ( activeTab ) {
changeTab ( activeTab ) ;
}
2015-01-23 22:19:15 +00:00
} , 400 ) ; // 400ms to make sure angular has rendered.
2013-09-26 23:07:25 +00:00
} ) ;
2013-11-18 22:11:06 +00:00
var initallyChecked = false ;
window . _ _isLoading = function ( ) {
if ( ! initallyChecked ) {
initallyChecked = true ;
return true ;
}
return $http . pendingRequests . length > 0 ;
} ;
2013-09-27 20:12:51 +00:00
} ] ) ;