2013-12-10 06:38:05 +00:00
var TEAM _PATTERN = '^[a-zA-Z][a-zA-Z0-9]+$' ;
var ROBOT _PATTERN = '^[a-zA-Z][a-zA-Z0-9]+$' ;
2013-12-26 22:45:16 +00:00
function getRestUrl ( args ) {
var url = '' ;
for ( var i = 0 ; i < arguments . length ; ++ i ) {
if ( i > 0 ) {
url += '/' ;
}
url += encodeURI ( arguments [ i ] )
}
return url ;
}
2014-01-10 01:17:28 +00:00
function clickElement ( el ) {
// From: http://stackoverflow.com/questions/16802795/click-not-working-in-mocha-phantomjs-on-certain-elements
var ev = document . createEvent ( "MouseEvent" ) ;
ev . initMouseEvent (
"click" ,
true /* bubble */ , true /* cancelable */ ,
window , null ,
0 , 0 , 0 , 0 , /* coordinates */
false , false , false , false , /* modifier keys */
0 /*left*/ , null ) ;
el . dispatchEvent ( ev ) ;
}
2013-12-26 22:45:16 +00:00
2013-11-05 00:36:56 +00:00
function getFirstTextLine ( commentString ) {
if ( ! commentString ) { return '' ; }
var lines = commentString . split ( '\n' ) ;
var MARKDOWN _CHARS = {
'#' : true ,
'-' : true ,
'>' : true ,
'`' : true
} ;
for ( var i = 0 ; i < lines . length ; ++ i ) {
// Skip code lines.
if ( lines [ i ] . indexOf ( ' ' ) == 0 ) {
continue ;
}
// Skip empty lines.
if ( $ . trim ( lines [ i ] ) . length == 0 ) {
continue ;
}
// Skip control lines.
if ( MARKDOWN _CHARS [ $ . trim ( lines [ i ] ) [ 0 ] ] ) {
continue ;
}
return getMarkedDown ( lines [ i ] ) ;
}
return '' ;
}
2013-12-26 22:45:16 +00:00
function createRobotAccount ( ApiService , is _org , orgname , name , callback ) {
ApiService . createRobot ( is _org ? orgname : null , null , { 'robot_shortname' : name } ) . then ( callback , function ( resp ) {
2013-12-10 06:38:05 +00:00
bootbox . dialog ( {
"message" : resp . data ? resp . data : 'The robot account could not be created' ,
"title" : "Cannot create robot account" ,
"buttons" : {
"close" : {
"label" : "Close" ,
"className" : "btn-primary"
}
}
} ) ;
} ) ;
}
2013-12-26 22:45:16 +00:00
function createOrganizationTeam ( ApiService , orgname , teamname , callback ) {
2013-12-10 06:38:05 +00:00
var data = {
'name' : teamname ,
'role' : 'member'
} ;
2013-12-26 22:45:16 +00:00
var params = {
'orgname' : orgname ,
'teamname' : teamname
} ;
2013-12-10 06:38:05 +00:00
2013-12-26 22:45:16 +00:00
ApiService . updateOrganizationTeam ( data , params ) . then ( callback , function ( ) {
2013-12-10 06:38:05 +00:00
bootbox . dialog ( {
"message" : resp . data ? resp . data : 'The team could not be created' ,
"title" : "Cannot create team" ,
"buttons" : {
"close" : {
"label" : "Close" ,
"className" : "btn-primary"
}
}
} ) ;
} ) ;
}
2013-11-05 00:36:56 +00:00
function getMarkedDown ( string ) {
return Markdown . getSanitizingConverter ( ) . makeHtml ( string || '' ) ;
}
2013-10-01 20:42:20 +00:00
// Start the application code itself.
2014-01-20 21:12:23 +00:00
quayApp = angular . module ( 'quay' , [ 'ngRoute' , 'chieffancypants.loadingBar' , 'restangular' , 'angularMoment' , 'angulartics' , /*'angulartics.google.analytics',*/ 'angulartics.mixpanel' , '$strap.directives' , 'ngCookies' , 'ngSanitize' , 'angular-md5' ] , function ( $provide , cfpLoadingBarProvider ) {
2013-12-17 18:19:59 +00:00
cfpLoadingBarProvider . includeSpinner = false ;
2013-12-26 22:45:16 +00:00
2014-01-14 21:01:37 +00:00
$provide . factory ( 'UtilService' , [ '$sanitize' , function ( $sanitize ) {
var utilService = { } ;
utilService . textToSafeHtml = function ( text ) {
var adjusted = text . replace ( /&/g , "&" )
. replace ( /</g , "<" )
. replace ( />/g , ">" )
. replace ( /"/g , """ )
. replace ( /'/g , "'" ) ;
return $sanitize ( adjusted ) ;
} ;
return utilService ;
} ] ) ;
$provide . factory ( 'ImageMetadataService' , [ 'UtilService' , function ( UtilService ) {
var metadataService = { } ;
metadataService . getFormattedCommand = function ( image ) {
if ( ! image || ! image . command || ! image . command . length ) {
return '' ;
}
var getCommandStr = function ( command ) {
// Handle /bin/sh commands specially.
if ( command . length > 2 && command [ 0 ] == '/bin/sh' && command [ 1 ] == '-c' ) {
return command [ 2 ] ;
}
return command . join ( ' ' ) ;
} ;
return getCommandStr ( image . command ) ;
} ;
metadataService . getEscapedFormattedCommand = function ( image ) {
return UtilService . textToSafeHtml ( metadataService . getFormattedCommand ( image ) ) ;
} ;
return metadataService ;
} ] ) ;
2013-12-26 22:45:16 +00:00
$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 ;
} ] ) ;
2013-12-18 22:26:56 +00:00
2013-12-17 20:03:34 +00:00
$provide . factory ( 'CookieService' , [ '$cookies' , '$cookieStore' , function ( $cookies , $cookieStore ) {
var cookieService = { } ;
cookieService . putPermanent = function ( name , value ) {
document . cookie = escape ( name ) + "=" + escape ( value ) + "; expires=Fri, 31 Dec 9999 23:59:59 GMT; path=/" ;
} ;
cookieService . putSession = function ( name , value ) {
$cookies [ name ] = value ;
} ;
cookieService . clear = function ( name ) {
$cookies [ name ] = '' ;
} ;
cookieService . get = function ( name ) {
return $cookies [ name ] ;
} ;
return cookieService ;
} ] ) ;
2013-12-26 22:45:16 +00:00
$provide . factory ( 'UserService' , [ 'ApiService' , 'CookieService' , function ( ApiService , CookieService ) {
2013-09-26 23:59:58 +00:00
var userResponse = {
verified : false ,
anonymous : true ,
username : null ,
2013-10-10 17:44:34 +00:00
email : null ,
askForPassword : false ,
2014-01-14 20:23:44 +00:00
organizations : [ ] ,
logins : [ ]
2013-09-26 23:59:58 +00:00
}
var userService = { }
2013-12-11 23:27:35 +00:00
userService . hasEverLoggedIn = function ( ) {
2013-12-17 20:03:34 +00:00
return CookieService . get ( 'quay.loggedin' ) == 'true' ;
2013-12-11 23:27:35 +00:00
} ;
2013-12-17 18:19:59 +00:00
userService . updateUserIn = function ( scope , opt _callback ) {
scope . $watch ( function ( ) { return userService . currentUser ( ) ; } , function ( currentUser ) {
scope . user = currentUser ;
if ( opt _callback ) {
opt _callback ( currentUser ) ;
}
} , true ) ;
2013-12-11 23:27:35 +00:00
} ;
2013-11-12 00:26:56 +00:00
userService . load = function ( opt _callback ) {
2013-12-26 22:45:16 +00:00
ApiService . getLoggedInUser ( ) . then ( function ( loadedUser ) {
2013-09-26 23:59:58 +00:00
userResponse = loadedUser ;
2013-10-03 19:46:22 +00:00
2013-10-03 20:16:10 +00:00
if ( ! userResponse . anonymous ) {
mixpanel . identify ( userResponse . username ) ;
mixpanel . people . set ( {
'$email' : userResponse . email ,
'$username' : userResponse . username ,
'verified' : userResponse . verified
} ) ;
2013-10-10 20:34:59 +00:00
mixpanel . people . set _once ( {
'$created' : new Date ( )
} )
2013-12-11 23:27:35 +00:00
2014-01-10 19:29:18 +00:00
if ( window . olark !== undefined ) {
olark ( 'api.visitor.getDetails' , function ( details ) {
if ( details . fullName === null ) {
olark ( 'api.visitor.updateFullName' , { fullName : userResponse . username } ) ;
}
} ) ;
olark ( 'api.visitor.updateEmailAddress' , { emailAddress : userResponse . email } ) ;
olark ( 'api.chat.updateVisitorStatus' , { snippet : 'username: ' + userResponse . username } ) ;
}
2013-12-17 20:03:34 +00:00
CookieService . putPermanent ( 'quay.loggedin' , 'true' ) ;
2013-10-03 20:16:10 +00:00
}
2013-11-12 00:26:56 +00:00
if ( opt _callback ) {
opt _callback ( ) ;
}
2013-09-26 23:59:58 +00:00
} ) ;
} ;
2013-11-08 22:50:42 +00:00
userService . getOrganization = function ( name ) {
if ( ! userResponse || ! userResponse . organizations ) { return null ; }
for ( var i = 0 ; i < userResponse . organizations . length ; ++ i ) {
var org = userResponse . organizations [ i ] ;
if ( org . name == name ) {
return org ;
}
}
2013-11-01 23:13:58 +00:00
2013-11-08 22:50:42 +00:00
return null ;
2013-11-01 23:13:58 +00:00
} ;
2013-12-10 20:22:22 +00:00
userService . isNamespaceAdmin = function ( namespace ) {
if ( namespace == userResponse . username ) {
return true ;
}
var org = userService . getOrganization ( namespace ) ;
if ( ! org ) {
return false ;
}
return org . is _org _admin ;
} ;
2014-01-31 18:52:35 +00:00
userService . isKnownNamespace = function ( namespace ) {
if ( namespace == userResponse . username ) {
return true ;
}
var org = userService . getOrganization ( namespace ) ;
return ! ! org ;
} ;
2013-12-10 20:22:22 +00:00
2013-09-26 23:59:58 +00:00
userService . currentUser = function ( ) {
return userResponse ;
2013-11-08 22:50:42 +00:00
} ;
2013-09-26 23:59:58 +00:00
// Load the user the first time.
userService . load ( ) ;
return userService ;
2013-10-04 18:35:51 +00:00
} ] ) ;
2013-10-08 17:57:48 +00:00
$provide . factory ( 'KeyService' , [ '$location' , function ( $location ) {
var keyService = { }
if ( $location . host ( ) === 'quay.io' ) {
keyService [ 'stripePublishableKey' ] = 'pk_live_P5wLU0vGdHnZGyKnXlFG4oiu' ;
2013-10-10 18:42:14 +00:00
keyService [ 'githubClientId' ] = '5a8c08b06c48d89d4d1e' ;
2014-01-14 20:23:44 +00:00
keyService [ 'githubRedirectUri' ] = 'https://quay.io/oauth2/github/callback' ;
2013-10-08 17:57:48 +00:00
} else {
keyService [ 'stripePublishableKey' ] = 'pk_test_uEDHANKm9CHCvVa2DLcipGRh' ;
2013-10-10 18:42:14 +00:00
keyService [ 'githubClientId' ] = 'cfbc4aca88e5c1b40679' ;
2014-01-14 20:23:44 +00:00
keyService [ 'githubRedirectUri' ] = 'http://localhost:5000/oauth2/github/callback' ;
2013-10-08 17:57:48 +00:00
}
return keyService ;
} ] ) ;
2013-12-26 22:45:16 +00:00
$provide . factory ( 'PlanService' , [ 'KeyService' , 'UserService' , 'CookieService' , 'ApiService' ,
function ( KeyService , UserService , CookieService , ApiService ) {
2013-11-01 23:13:58 +00:00
var plans = null ;
2013-10-04 18:35:51 +00:00
var planDict = { } ;
2013-11-15 23:17:12 +00:00
var planService = { } ;
var listeners = [ ] ;
2013-10-04 18:35:51 +00:00
2014-02-03 23:18:33 +00:00
var previousSubscribeFailure = false ;
2013-12-20 02:51:46 +00:00
planService . getFreePlan = function ( ) {
return 'free' ;
} ;
2013-11-15 23:17:12 +00:00
planService . registerListener = function ( obj , callback ) {
listeners . push ( { 'obj' : obj , 'callback' : callback } ) ;
} ;
planService . unregisterListener = function ( obj ) {
for ( var i = 0 ; i < listeners . length ; ++ i ) {
if ( listeners [ i ] . obj == obj ) {
listeners . splice ( i , 1 ) ;
break ;
}
}
} ;
2013-12-11 22:50:48 +00:00
planService . notePlan = function ( planId ) {
2013-12-17 20:03:34 +00:00
CookieService . putSession ( 'quay.notedplan' , planId ) ;
2013-12-11 22:50:48 +00:00
} ;
2013-12-20 02:51:46 +00:00
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 ) ;
} ) ;
} ) ;
2013-12-11 22:50:48 +00:00
} ;
planService . handleNotedPlan = function ( ) {
var planId = planService . getAndResetNotedPlan ( ) ;
if ( ! planId ) { return ; }
2013-12-11 23:20:24 +00:00
UserService . load ( function ( ) {
if ( UserService . currentUser ( ) . anonymous ) {
return ;
2013-12-11 22:50:48 +00:00
}
2013-12-18 23:16:32 +00:00
planService . getPlan ( planId , function ( plan ) {
2013-12-20 02:51:46 +00:00
if ( planService . isOrgCompatible ( plan ) ) {
2013-12-11 23:20:24 +00:00
document . location = '/organizations/new/?plan=' + planId ;
} else {
document . location = '/user?plan=' + planId ;
}
} ) ;
2013-12-11 22:50:48 +00:00
} ) ;
} ;
planService . getAndResetNotedPlan = function ( ) {
2013-12-17 20:03:34 +00:00
var planId = CookieService . get ( 'quay.notedplan' ) ;
CookieService . clear ( 'quay.notedplan' ) ;
2013-12-11 22:50:48 +00:00
return planId ;
} ;
2013-11-19 22:06:17 +00:00
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 ;
} ;
2013-11-01 23:13:58 +00:00
planService . verifyLoaded = function ( callback ) {
if ( plans ) {
callback ( plans ) ;
return ;
}
2013-12-26 22:45:16 +00:00
ApiService . listPlans ( ) . then ( function ( data ) {
2013-11-05 19:40:45 +00:00
var i = 0 ;
2013-12-20 02:51:46 +00:00
for ( i = 0 ; i < data . plans . length ; i ++ ) {
planDict [ data . plans [ i ] . stripeId ] = data . plans [ i ] ;
2013-11-05 19:40:45 +00:00
}
2013-12-20 02:51:46 +00:00
plans = data . plans ;
2013-11-01 23:13:58 +00:00
callback ( plans ) ;
} , function ( ) { callback ( [ ] ) ; } ) ;
} ;
2013-12-20 02:51:46 +00:00
planService . getPlans = function ( callback , opt _includePersonal ) {
2013-12-11 22:50:48 +00:00
planService . verifyLoaded ( function ( ) {
2013-12-20 02:51:46 +00:00
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 ) ;
2013-12-11 22:50:48 +00:00
}
2013-12-20 02:51:46 +00:00
callback ( filtered ) ;
2013-12-11 22:50:48 +00:00
} ) ;
} ;
2013-12-20 02:51:46 +00:00
planService . getPlan = function ( planId , callback ) {
planService . getPlanIncludingDeprecated ( planId , function ( plan ) {
if ( ! plan [ 'deprecated' ] ) {
callback ( plan ) ;
}
} ) ;
2013-10-28 21:08:26 +00:00
} ;
2013-10-04 18:35:51 +00:00
2013-12-20 02:51:46 +00:00
planService . getPlanIncludingDeprecated = function ( planId , callback ) {
2013-11-01 23:13:58 +00:00
planService . verifyLoaded ( function ( ) {
2013-12-20 02:51:46 +00:00
if ( planDict [ planId ] ) {
2013-11-06 23:14:22 +00:00
callback ( planDict [ planId ] ) ;
}
2013-11-01 23:13:58 +00:00
} ) ;
2013-10-28 21:08:26 +00:00
} ;
2013-11-05 19:40:45 +00:00
planService . getMinimumPlan = function ( privateCount , isBusiness , callback ) {
2013-12-21 03:41:00 +00:00
planService . getPlans ( function ( plans ) {
2013-12-20 02:51:46 +00:00
for ( var i = 0 ; i < plans . length ; i ++ ) {
var plan = plans [ i ] ;
if ( isBusiness && ! planService . isOrgCompatible ( plan ) ) {
continue ;
}
2013-11-05 19:40:45 +00:00
2013-11-01 23:13:58 +00:00
if ( plan . privateRepos >= privateCount ) {
callback ( plan ) ;
return ;
}
2013-10-28 21:08:26 +00:00
}
2013-11-01 23:13:58 +00:00
callback ( null ) ;
} ) ;
2013-10-28 21:08:26 +00:00
} ;
2013-11-15 23:17:12 +00:00
planService . getSubscription = function ( orgname , success , failure ) {
2013-12-26 22:45:16 +00:00
ApiService . getSubscription ( orgname ) . then ( success , failure ) ;
2013-11-06 22:30:20 +00:00
} ;
planService . setSubscription = function ( orgname , planId , success , failure , opt _token ) {
var subscriptionDetails = {
plan : planId
} ;
2013-10-28 21:08:26 +00:00
2013-11-06 22:30:20 +00:00
if ( opt _token ) {
subscriptionDetails [ 'token' ] = opt _token . id ;
}
2013-12-26 22:45:16 +00:00
ApiService . updateSubscription ( orgname , subscriptionDetails ) . then ( function ( resp ) {
2013-11-15 23:17:12 +00:00
success ( resp ) ;
planService . getPlan ( planId , function ( plan ) {
for ( var i = 0 ; i < listeners . length ; ++ i ) {
listeners [ i ] [ 'callback' ] ( plan ) ;
}
} ) ;
} , failure ) ;
2013-11-06 22:30:20 +00:00
} ;
2013-11-15 23:58:47 +00:00
planService . getCardInfo = function ( orgname , callback ) {
2013-12-26 22:45:16 +00:00
ApiService . getCard ( orgname ) . then ( function ( resp ) {
2013-11-15 23:58:47 +00:00
callback ( resp . card ) ;
} , function ( ) {
callback ( { 'is_valid' : false } ) ;
} ) ;
} ;
planService . changePlan = function ( $scope , orgname , planId , callbacks ) {
2013-11-09 01:32:56 +00:00
if ( callbacks [ 'started' ] ) {
2013-11-15 23:58:47 +00:00
callbacks [ 'started' ] ( ) ;
2013-11-09 01:32:56 +00:00
}
2013-11-15 23:58:47 +00:00
planService . getPlan ( planId , function ( plan ) {
2013-12-20 02:51:46 +00:00
if ( orgname && ! planService . isOrgCompatible ( plan ) ) { return ; }
2013-11-15 23:58:47 +00:00
planService . getCardInfo ( orgname , function ( cardInfo ) {
2014-02-03 23:18:33 +00:00
if ( plan . price > 0 && ( previousSubscribeFailure || ! cardInfo . last4 ) ) {
2013-11-15 23:58:47 +00:00
planService . showSubscribeDialog ( $scope , orgname , planId , callbacks ) ;
return ;
}
2014-02-03 23:18:33 +00:00
previousSubscribeFailure = false ;
2013-11-19 22:06:17 +00:00
planService . setSubscription ( orgname , planId , callbacks [ 'success' ] , function ( resp ) {
2014-02-03 23:18:33 +00:00
previousSubscribeFailure = true ;
2013-11-19 22:06:17 +00:00
planService . handleCardError ( resp ) ;
callbacks [ 'failure' ] ( resp ) ;
} ) ;
2013-11-15 23:58:47 +00:00
} ) ;
} ) ;
2013-11-06 22:30:20 +00:00
} ;
2013-11-15 23:17:12 +00:00
planService . changeCreditCard = function ( $scope , orgname , callbacks ) {
if ( callbacks [ 'opening' ] ) {
callbacks [ 'opening' ] ( ) ;
}
2013-11-19 22:06:17 +00:00
var submitted = false ;
2013-11-15 23:17:12 +00:00
var submitToken = function ( token ) {
2013-11-19 22:06:17 +00:00
if ( submitted ) { return ; }
submitted = true ;
2013-11-15 23:17:12 +00:00
$scope . $apply ( function ( ) {
if ( callbacks [ 'started' ] ) {
callbacks [ 'started' ] ( ) ;
}
var cardInfo = {
'token' : token . id
} ;
2013-12-26 22:45:16 +00:00
ApiService . setCard ( orgname , cardInfo ) . then ( callbacks [ 'success' ] , function ( resp ) {
planService . handleCardError ( resp ) ;
callbacks [ 'failure' ] ( resp ) ;
} ) ;
2013-11-15 23:17:12 +00:00
} ) ;
} ;
var email = planService . getEmail ( orgname ) ;
StripeCheckout . open ( {
key : KeyService . stripePublishableKey ,
address : false ,
email : email ,
currency : 'usd' ,
name : 'Update credit card' ,
description : 'Enter your credit card number' ,
panelLabel : 'Update' ,
token : submitToken ,
image : 'static/img/quay-icon-stripe.png' ,
opened : function ( ) { $scope . $apply ( function ( ) { callbacks [ 'opened' ] ( ) } ) ; } ,
closed : function ( ) { $scope . $apply ( function ( ) { callbacks [ 'closed' ] ( ) } ) ; }
} ) ;
} ;
planService . getEmail = function ( orgname ) {
var email = null ;
if ( UserService . currentUser ( ) ) {
email = UserService . currentUser ( ) . email ;
if ( orgname ) {
org = UserService . getOrganization ( orgname ) ;
if ( org ) {
emaiil = org . email ;
}
}
}
return email ;
} ;
2013-11-09 01:32:56 +00:00
planService . showSubscribeDialog = function ( $scope , orgname , planId , callbacks ) {
if ( callbacks [ 'opening' ] ) {
callbacks [ 'opening' ] ( ) ;
}
2013-11-19 22:06:17 +00:00
var submitted = false ;
2013-11-06 22:30:20 +00:00
var submitToken = function ( token ) {
2013-11-19 22:06:17 +00:00
if ( submitted ) { return ; }
submitted = true ;
2013-11-06 22:30:20 +00:00
mixpanel . track ( 'plan_subscribe' ) ;
2013-10-28 21:08:26 +00:00
$scope . $apply ( function ( ) {
2013-11-09 01:32:56 +00:00
if ( callbacks [ 'started' ] ) {
callbacks [ 'started' ] ( ) ;
}
2013-11-15 20:31:05 +00:00
planService . setSubscription ( orgname , planId , callbacks [ 'success' ] , callbacks [ 'failure' ] , token ) ;
2013-10-28 21:08:26 +00:00
} ) ;
} ;
2013-11-01 23:13:58 +00:00
planService . getPlan ( planId , function ( planDetails ) {
2013-11-15 23:17:12 +00:00
var email = planService . getEmail ( orgname ) ;
2013-11-01 23:13:58 +00:00
StripeCheckout . open ( {
key : KeyService . stripePublishableKey ,
address : false ,
2013-11-08 22:50:42 +00:00
email : email ,
2013-11-01 23:13:58 +00:00
amount : planDetails . price ,
currency : 'usd' ,
name : 'Quay ' + planDetails . title + ' Subscription' ,
description : 'Up to ' + planDetails . privateRepos + ' private repositories' ,
panelLabel : 'Subscribe' ,
2013-11-06 19:55:40 +00:00
token : submitToken ,
2013-11-09 01:32:56 +00:00
image : 'static/img/quay-icon-stripe.png' ,
opened : function ( ) { $scope . $apply ( function ( ) { callbacks [ 'opened' ] ( ) } ) ; } ,
closed : function ( ) { $scope . $apply ( function ( ) { callbacks [ 'closed' ] ( ) } ) ; }
2013-11-01 23:13:58 +00:00
} ) ;
2013-10-28 21:08:26 +00:00
} ) ;
} ;
2013-10-04 18:35:51 +00:00
return planService ;
} ] ) ;
2013-09-26 23:59:58 +00:00
} ) .
2013-10-01 23:37:33 +00:00
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 ) ;
} ) ;
}
} ;
} ) .
2013-10-17 18:29:47 +00:00
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 ) ;
} ) ;
} ;
} ) .
2013-10-03 19:46:22 +00:00
config ( [ '$routeProvider' , '$locationProvider' , '$analyticsProvider' ,
function ( $routeProvider , $locationProvider , $analyticsProvider ) {
2013-10-03 20:16:10 +00:00
$analyticsProvider . virtualPageviews ( true ) ;
2013-10-10 23:06:04 +00:00
$locationProvider . html5Mode ( true ) ;
2013-10-14 02:06:31 +00:00
// 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
2013-10-03 20:16:10 +00:00
$routeProvider .
2013-11-20 21:17:47 +00:00
when ( '/repository/:namespace/:name' , { templateUrl : '/static/partials/view-repo.html' , controller : RepoCtrl ,
2013-12-18 03:56:28 +00:00
fixFooter : false , reloadOnSearch : false } ) .
2013-11-20 21:17:47 +00:00
when ( '/repository/:namespace/:name/tag/:tag' , { templateUrl : '/static/partials/view-repo.html' , controller : RepoCtrl ,
2013-12-18 03:56:28 +00:00
fixFooter : false } ) .
2013-12-17 18:19:59 +00:00
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 } ) .
2013-11-19 00:03:35 +00:00
when ( '/repository/' , { title : 'Repositories' , description : 'Public and private docker repositories list' ,
templateUrl : '/static/partials/repo-list.html' , controller : RepoListCtrl } ) .
2013-12-10 04:33:28 +00:00
when ( '/user/' , { title : 'Account Settings' , description : 'Account settings for Quay.io' , templateUrl : '/static/partials/user-admin.html' ,
reloadOnSearch : false , controller : UserAdminCtrl } ) .
when ( '/guide/' , { title : 'Guide' , description : 'Guide to using private docker repositories on Quay.io' , templateUrl : '/static/partials/guide.html' ,
controller : GuideCtrl } ) .
2013-12-17 22:02:37 +00:00
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 } ) .
2013-11-22 20:54:23 +00:00
when ( '/plans/' , { title : 'Plans and Pricing' , description : 'Plans and pricing for private docker repositories on Quay.io' ,
2013-11-19 00:03:35 +00:00
templateUrl : '/static/partials/plans.html' , controller : PlansCtrl } ) .
2013-11-22 20:54:23 +00:00
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 } ) .
2013-11-19 00:03:35 +00:00
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 } ) .
2013-11-22 20:54:23 +00:00
when ( '/organizations/new/' , { title : 'New Organization' , description : 'Create a new organization on Quay.io' ,
2013-11-19 00:03:35 +00:00
templateUrl : '/static/partials/new-organization.html' , controller : NewOrgCtrl } ) .
2013-10-31 22:17:26 +00:00
when ( '/organization/:orgname' , { templateUrl : '/static/partials/org-view.html' , controller : OrgViewCtrl } ) .
2013-12-10 04:33:28 +00:00
when ( '/organization/:orgname/admin' , { templateUrl : '/static/partials/org-admin.html' , controller : OrgAdminCtrl , reloadOnSearch : false } ) .
2013-10-31 22:17:26 +00:00
when ( '/organization/:orgname/teams/:teamname' , { templateUrl : '/static/partials/team-view.html' , controller : TeamViewCtrl } ) .
2013-12-07 00:25:27 +00:00
when ( '/organization/:orgname/logs/:membername' , { templateUrl : '/static/partials/org-member-logs.html' , controller : OrgMemberLogsCtrl } ) .
2013-10-17 21:45:08 +00:00
when ( '/v1/' , { title : 'Activation information' , templateUrl : '/static/partials/v1-page.html' , controller : V1Ctrl } ) .
2013-10-09 22:33:25 +00:00
when ( '/' , { title : 'Hosted Private Docker Registry' , templateUrl : '/static/partials/landing.html' , controller : LandingCtrl } ) .
2013-10-03 20:16:10 +00:00
otherwise ( { redirectTo : '/' } ) ;
} ] ) .
2013-09-24 22:21:14 +00:00
config ( function ( RestangularProvider ) {
RestangularProvider . setBaseUrl ( '/api/' ) ;
2013-09-26 21:59:20 +00:00
} ) ;
2013-11-05 00:36:56 +00:00
2013-11-26 19:37:55 +00:00
quayApp . directive ( 'entityReference' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/entity-reference.html' ,
replace : false ,
transclude : false ,
restrict : 'C' ,
scope : {
2014-01-21 21:23:00 +00:00
'entity' : '=entity' ,
'namespace' : '=namespace'
2013-11-26 19:37:55 +00:00
} ,
2013-12-10 20:22:22 +00:00
controller : function ( $scope , $element , UserService ) {
2014-01-21 21:23:00 +00:00
$scope . getIsAdmin = function ( namespace ) {
return UserService . isNamespaceAdmin ( namespace ) ;
2013-12-10 20:22:22 +00:00
} ;
2013-11-26 19:37:55 +00:00
$scope . getPrefix = function ( name ) {
if ( ! name ) { return '' ; }
var plus = name . indexOf ( '+' ) ;
return name . substr ( 0 , plus + 1 ) ;
} ;
$scope . getShortenedName = function ( name ) {
if ( ! name ) { return '' ; }
var plus = name . indexOf ( '+' ) ;
return name . substr ( plus + 1 ) ;
} ;
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-05 00:36:56 +00:00
quayApp . directive ( 'markdownView' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/markdown-view.html' ,
replace : false ,
transclude : false ,
restrict : 'C' ,
scope : {
'content' : '=content' ,
'firstLineOnly' : '=firstLineOnly'
} ,
2013-11-19 00:03:35 +00:00
controller : function ( $scope , $element , $sce ) {
2013-11-05 00:36:56 +00:00
$scope . getMarkedDown = function ( content , firstLineOnly ) {
if ( firstLineOnly ) {
content = getFirstTextLine ( content ) ;
}
2013-11-19 00:03:35 +00:00
return $sce . trustAsHtml ( getMarkedDown ( content ) ) ;
2013-11-05 00:36:56 +00:00
} ;
}
} ;
return directiveDefinitionObject ;
} ) ;
2014-01-31 18:52:35 +00:00
quayApp . directive ( 'repoBreadcrumb' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/repo-breadcrumb.html' ,
replace : false ,
transclude : false ,
restrict : 'C' ,
scope : {
'repo' : '=repo' ,
'image' : '=image'
} ,
controller : function ( $scope , $element , $location , UserService , CookieService ) {
$scope . showNamespace = function ( ) {
var namespace = $scope . repo . namespace || '' ;
if ( UserService . isKnownNamespace ( namespace ) ) {
CookieService . putPermanent ( 'quay.namespace' , namespace ) ;
}
$location . path ( '/repository/' ) ;
} ;
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-10-22 05:26:14 +00:00
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 ) {
2013-10-26 20:03:11 +00:00
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-12-11 23:20:24 +00:00
quayApp . directive ( 'userSetup' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/user-setup.html' ,
replace : false ,
transclude : true ,
restrict : 'C' ,
scope : {
'redirectUrl' : '=redirectUrl' ,
'signInStarted' : '&signInStarted' ,
'signedIn' : '&signedIn'
} ,
2013-12-26 22:45:16 +00:00
controller : function ( $scope , $location , $timeout , ApiService , KeyService , UserService ) {
2013-12-11 23:20:24 +00:00
$scope . sendRecovery = function ( ) {
2013-12-26 22:45:16 +00:00
ApiService . requestRecoveryEmail ( $scope . recovery ) . then ( function ( ) {
2014-01-10 18:30:17 +00:00
$scope . invalidRecovery = false ;
$scope . errorMessage = '' ;
2013-12-11 23:20:24 +00:00
$scope . sent = true ;
} , function ( result ) {
2014-01-10 18:30:17 +00:00
$scope . invalidRecovery = true ;
$scope . errorMessage = result . data ;
2013-12-11 23:20:24 +00:00
$scope . sent = false ;
} ) ;
} ;
2013-12-11 23:27:35 +00:00
$scope . hasSignedIn = function ( ) {
return UserService . hasEverLoggedIn ( ) ;
} ;
2013-12-11 23:20:24 +00:00
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-07 20:19:52 +00:00
quayApp . directive ( 'signinForm' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/signin-form.html' ,
replace : false ,
transclude : true ,
restrict : 'C' ,
scope : {
2013-12-11 22:50:48 +00:00
'redirectUrl' : '=redirectUrl' ,
'signInStarted' : '&signInStarted' ,
'signedIn' : '&signedIn'
2013-11-07 20:19:52 +00:00
} ,
2013-12-26 22:45:16 +00:00
controller : function ( $scope , $location , $timeout , ApiService , KeyService , UserService ) {
2013-12-11 22:50:48 +00:00
$scope . showGithub = function ( ) {
$scope . markStarted ( ) ;
2013-11-07 20:19:52 +00:00
2013-12-11 22:50:48 +00:00
var mixpanelDistinctIdClause = '' ;
2013-11-07 20:19:52 +00:00
if ( mixpanel . get _distinct _id !== undefined ) {
2013-12-11 22:50:48 +00:00
$scope . mixpanelDistinctIdClause = "&state=" + encodeURIComponent ( mixpanel . get _distinct _id ( ) ) ;
2013-11-07 20:19:52 +00:00
}
2013-12-11 22:50:48 +00:00
// Needed to ensure that UI work done by the started callback is finished before the location
// changes.
$timeout ( function ( ) {
var url = 'https://github.com/login/oauth/authorize?client_id=' + encodeURIComponent ( KeyService . githubClientId ) +
'&scope=user:email' + mixpanelDistinctIdClause ;
document . location = url ;
} , 250 ) ;
2013-11-07 20:19:52 +00:00
} ;
2013-12-11 22:50:48 +00:00
$scope . markStarted = function ( ) {
if ( $scope . signInStarted != null ) {
$scope . signInStarted ( ) ;
}
} ;
2013-11-07 20:19:52 +00:00
$scope . signin = function ( ) {
2013-12-11 22:50:48 +00:00
$scope . markStarted ( ) ;
2013-12-26 22:45:16 +00:00
ApiService . signinUser ( $scope . user ) . then ( function ( ) {
2013-11-07 20:19:52 +00:00
$scope . needsEmailVerification = false ;
$scope . invalidCredentials = false ;
2013-12-11 22:50:48 +00:00
if ( $scope . signedIn != null ) {
$scope . signedIn ( ) ;
}
2013-11-07 20:19:52 +00:00
UserService . load ( ) ;
2013-12-11 22:50:48 +00:00
// Redirect to the specified page or the landing page
// Note: The timeout of 500ms is needed to ensure dialogs containing sign in
// forms get removed before the location changes.
$timeout ( function ( ) {
if ( $scope . redirectUrl == $location . path ( ) ) {
return ;
}
$location . path ( $scope . redirectUrl ? $scope . redirectUrl : '/' ) ;
} , 500 ) ;
2013-11-07 20:19:52 +00:00
} , function ( result ) {
$scope . needsEmailVerification = result . data . needsEmailVerification ;
$scope . invalidCredentials = result . data . invalidCredentials ;
} ) ;
} ;
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-12-11 21:50:10 +00:00
quayApp . directive ( 'signupForm' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/signup-form.html' ,
replace : false ,
transclude : true ,
restrict : 'C' ,
scope : {
} ,
2013-12-26 22:45:16 +00:00
controller : function ( $scope , $location , $timeout , ApiService , KeyService , UserService ) {
2013-12-11 21:50:10 +00:00
$ ( '.form-signup' ) . popover ( ) ;
angulartics . waitForVendorApi ( mixpanel , 500 , function ( loadedMixpanel ) {
var mixpanelId = loadedMixpanel . get _distinct _id ( ) ;
$scope . github _state _clause = '&state=' + mixpanelId ;
} ) ;
$scope . githubClientId = KeyService . githubClientId ;
$scope . awaitingConfirmation = false ;
$scope . registering = false ;
$scope . register = function ( ) {
$ ( '.form-signup' ) . popover ( 'hide' ) ;
$scope . registering = true ;
2013-12-26 22:45:16 +00:00
ApiService . createNewUser ( $scope . newUser ) . then ( function ( ) {
2013-12-11 21:50:10 +00:00
$scope . awaitingConfirmation = true ;
$scope . registering = false ;
mixpanel . alias ( $scope . newUser . username ) ;
} , function ( result ) {
$scope . registering = false ;
$scope . registerError = result . data . message ;
$timeout ( function ( ) {
$ ( '.form-signup' ) . popover ( 'show' ) ;
} ) ;
} ) ;
} ;
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-08 03:08:23 +00:00
quayApp . directive ( 'plansTable' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/plans-table.html' ,
replace : false ,
2013-11-23 01:14:44 +00:00
transclude : false ,
2013-11-08 03:08:23 +00:00
restrict : 'C' ,
scope : {
'plans' : '=plans' ,
'currentPlan' : '=currentPlan'
} ,
controller : function ( $scope , $element ) {
$scope . setPlan = function ( plan ) {
$scope . currentPlan = plan ;
} ;
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-23 01:14:44 +00:00
quayApp . directive ( 'dockerAuthDialog' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/docker-auth-dialog.html' ,
replace : false ,
transclude : true ,
restrict : 'C' ,
scope : {
'username' : '=username' ,
'token' : '=token' ,
'shown' : '=shown' ,
'counter' : '=counter'
} ,
2013-12-26 22:45:16 +00:00
controller : function ( $scope , $element ) {
2013-11-23 01:14:44 +00:00
$scope . isDownloadSupported = function ( ) {
try { return ! ! new Blob ( ) ; } catch ( e ) { }
return false ;
} ;
$scope . downloadCfg = function ( ) {
var auth = $ . base64 . encode ( $scope . username + ":" + $scope . token ) ;
config = {
"https://quay.io/v1/" : {
"auth" : auth ,
"email" : ""
}
} ;
var file = JSON . stringify ( config , null , ' ' ) ;
var blob = new Blob ( [ file ] ) ;
saveAs ( blob , '.dockercfg' ) ;
} ;
var show = function ( r ) {
if ( ! $scope . shown || ! $scope . username || ! $scope . token ) {
$ ( '#dockerauthmodal' ) . modal ( 'hide' ) ;
return ;
}
$ ( '#copyClipboard' ) . clipboardCopy ( ) ;
$ ( '#dockerauthmodal' ) . modal ( { } ) ;
} ;
$scope . $watch ( 'counter' , show ) ;
$scope . $watch ( 'shown' , show ) ;
$scope . $watch ( 'username' , show ) ;
$scope . $watch ( 'token' , show ) ;
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-22 23:20:51 +00:00
2014-01-03 21:32:00 +00:00
quayApp . filter ( 'bytes' , function ( ) {
return function ( bytes , precision ) {
2014-01-03 21:42:38 +00:00
if ( ! bytes || isNaN ( parseFloat ( bytes ) ) || ! isFinite ( bytes ) ) return 'Unknown' ;
2014-01-03 21:32:00 +00:00
if ( typeof precision === 'undefined' ) precision = 1 ;
var units = [ 'bytes' , 'kB' , 'MB' , 'GB' , 'TB' , 'PB' ] ,
number = Math . floor ( Math . log ( bytes ) / Math . log ( 1024 ) ) ;
return ( bytes / Math . pow ( 1024 , Math . floor ( number ) ) ) . toFixed ( precision ) + ' ' + units [ number ] ;
}
} ) ;
2013-11-27 07:29:31 +00:00
quayApp . filter ( 'visibleLogFilter' , function ( ) {
return function ( logs , allowed ) {
if ( ! allowed ) {
return logs ;
}
var filtered = [ ] ;
angular . forEach ( logs , function ( log ) {
if ( allowed [ log . kind ] ) {
filtered . push ( log ) ;
}
} ) ;
return filtered ;
} ;
} ) ;
2013-12-21 03:38:53 +00:00
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'
} ,
2013-12-26 22:45:16 +00:00
controller : function ( $scope , $element , $sce , ApiService ) {
2013-12-21 03:38:53 +00:00
$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 ;
2013-12-26 22:45:16 +00:00
ApiService . listInvoices ( $scope . organization ) . then ( function ( resp ) {
2013-12-21 03:38:53 +00:00
$scope . invoices = resp . invoices ;
$scope . loading = false ;
} ) ;
} ;
$scope . $watch ( 'organization' , update ) ;
$scope . $watch ( 'user' , update ) ;
$scope . $watch ( 'visible' , update ) ;
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-27 07:29:31 +00:00
quayApp . directive ( 'logsView' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/logs-view.html' ,
replace : false ,
transclude : false ,
restrict : 'C' ,
scope : {
'organization' : '=organization' ,
'user' : '=user' ,
2013-12-02 19:55:04 +00:00
'visible' : '=visible' ,
2013-12-07 00:25:27 +00:00
'repository' : '=repository' ,
'performer' : '=performer'
2013-11-27 07:29:31 +00:00
} ,
2013-12-26 22:45:16 +00:00
controller : function ( $scope , $element , $sce , Restangular , ApiService ) {
2013-11-27 07:29:31 +00:00
$scope . loading = true ;
$scope . logs = null ;
$scope . kindsAllowed = null ;
$scope . chartVisible = true ;
2013-12-06 20:59:59 +00:00
$scope . logsPath = '' ;
2013-11-27 07:29:31 +00:00
2013-12-09 22:28:23 +00:00
var datetime = new Date ( ) ;
$scope . logStartDate = new Date ( datetime . getUTCFullYear ( ) , datetime . getUTCMonth ( ) , datetime . getUTCDate ( ) - 7 ) ;
$scope . logEndDate = new Date ( datetime . getUTCFullYear ( ) , datetime . getUTCMonth ( ) , datetime . getUTCDate ( ) ) ;
2014-01-21 23:39:42 +00:00
var defaultPermSuffix = function ( metadata ) {
if ( metadata . activating _username ) {
return ', when creating user is {activating_username}' ;
}
return '' ;
} ;
2013-11-29 05:04:50 +00:00
var logDescriptions = {
'account_change_plan' : 'Change plan' ,
'account_change_cc' : 'Update credit card' ,
'account_change_password' : 'Change password' ,
'account_convert' : 'Convert account to organization' ,
'create_robot' : 'Create Robot Account: {robot}' ,
'delete_robot' : 'Delete Robot Account: {robot}' ,
'create_repo' : 'Create Repository: {repo}' ,
'push_repo' : 'Push to repository: {repo}' ,
'pull_repo' : function ( metadata ) {
2013-12-02 19:55:04 +00:00
if ( metadata . token ) {
return 'Pull repository {repo} via token {token}' ;
} else if ( metadata . username ) {
return 'Pull repository {repo} by {username}' ;
} else {
return 'Public pull of repository {repo} by {_ip}' ;
}
2013-11-29 05:04:50 +00:00
} ,
'delete_repo' : 'Delete repository: {repo}' ,
2013-12-02 19:55:04 +00:00
'change_repo_permission' : function ( metadata ) {
if ( metadata . username ) {
return 'Change permission for user {username} in repository {repo} to {role}' ;
} else if ( metadata . team ) {
return 'Change permission for team {team} in repository {repo} to {role}' ;
} else if ( metadata . token ) {
return 'Change permission for token {token} in repository {repo} to {role}' ;
}
} ,
'delete_repo_permission' : function ( metadata ) {
if ( metadata . username ) {
return 'Remove permission for user {username} from repository {repo}' ;
} else if ( metadata . team ) {
return 'Remove permission for team {team} from repository {repo}' ;
} else if ( metadata . token ) {
return 'Remove permission for token {token} from repository {repo}' ;
}
} ,
2014-01-21 22:04:00 +00:00
'delete_tag' : 'Tag {tag} deleted in repository {repo} by user {username}' ,
2013-11-29 05:04:50 +00:00
'change_repo_visibility' : 'Change visibility for repository {repo} to {visibility}' ,
'add_repo_accesstoken' : 'Create access token {token} in repository {repo}' ,
'delete_repo_accesstoken' : 'Delete access token {token} in repository {repo}' ,
'add_repo_webhook' : 'Add webhook in repository {repo}' ,
'delete_repo_webhook' : 'Delete webhook in repository {repo}' ,
'set_repo_description' : 'Change description for repository {repo}: {description}' ,
'build_dockerfile' : 'Build image from Dockerfile for repository {repo}' ,
'org_create_team' : 'Create team: {team}' ,
'org_delete_team' : 'Delete team: {team}' ,
'org_add_team_member' : 'Add member {member} to team {team}' ,
'org_remove_team_member' : 'Remove member {member} from team {team}' ,
'org_set_team_description' : 'Change description of team {team}: {description}' ,
2014-01-21 22:04:00 +00:00
'org_set_team_role' : 'Change permission of team {team} to {role}' ,
'create_prototype_permission' : function ( metadata ) {
if ( metadata . delegate _user ) {
2014-01-21 23:39:42 +00:00
return 'Create default permission: {role} for {delegate_user}' + defaultPermSuffix ( metadata ) ;
2014-01-21 22:04:00 +00:00
} else if ( metadata . delegate _team ) {
2014-01-21 23:39:42 +00:00
return 'Create default permission: {role} for {delegate_team}' + defaultPermSuffix ( metadata ) ;
2014-01-21 22:04:00 +00:00
}
} ,
'modify_prototype_permission' : function ( metadata ) {
if ( metadata . delegate _user ) {
2014-01-21 23:39:42 +00:00
return 'Modify default permission: {role} (from {original_role}) for {delegate_user}' + defaultPermSuffix ( metadata ) ;
2014-01-21 22:04:00 +00:00
} else if ( metadata . delegate _team ) {
2014-01-21 23:39:42 +00:00
return 'Modify default permission: {role} (from {original_role}) for {delegate_team}' + defaultPermSuffix ( metadata ) ;
2014-01-21 22:04:00 +00:00
}
} ,
'delete_prototype_permission' : function ( metadata ) {
if ( metadata . delegate _user ) {
2014-01-21 23:39:42 +00:00
return 'Delete default permission: {role} for {delegate_user}' + defaultPermSuffix ( metadata ) ;
2014-01-21 22:04:00 +00:00
} else if ( metadata . delegate _team ) {
2014-01-21 23:39:42 +00:00
return 'Delete default permission: {role} for {delegate_team}' + defaultPermSuffix ( metadata ) ;
2014-01-21 22:04:00 +00:00
}
}
2013-11-29 05:04:50 +00:00
} ;
2013-11-27 07:29:31 +00:00
var logKinds = {
'account_change_plan' : 'Change plan' ,
'account_change_cc' : 'Update credit card' ,
'account_change_password' : 'Change password' ,
'account_convert' : 'Convert account to organization' ,
'create_robot' : 'Create Robot Account' ,
'delete_robot' : 'Delete Robot Account' ,
'create_repo' : 'Create Repository' ,
'push_repo' : 'Push to repository' ,
'pull_repo' : 'Pull repository' ,
'delete_repo' : 'Delete repository' ,
'change_repo_permission' : 'Change repository permission' ,
'delete_repo_permission' : 'Remove user permission from repository' ,
'change_repo_visibility' : 'Change repository visibility' ,
'add_repo_accesstoken' : 'Create access token' ,
'delete_repo_accesstoken' : 'Delete access token' ,
'add_repo_webhook' : 'Add webhook' ,
'delete_repo_webhook' : 'Delete webhook' ,
'set_repo_description' : 'Change repository description' ,
'build_dockerfile' : 'Build image from Dockerfile' ,
2014-01-21 22:04:00 +00:00
'delete_tag' : 'Delete Tag' ,
2013-11-27 07:29:31 +00:00
'org_create_team' : 'Create team' ,
'org_delete_team' : 'Delete team' ,
'org_add_team_member' : 'Add team member' ,
'org_remove_team_member' : 'Remove team member' ,
'org_set_team_description' : 'Change team description' ,
2014-01-21 22:04:00 +00:00
'org_set_team_role' : 'Change team permission' ,
'create_prototype_permission' : 'Create default permission' ,
'modify_prototype_permission' : 'Modify default permission' ,
'delete_prototype_permission' : 'Delete default permission'
2013-11-27 07:29:31 +00:00
} ;
2013-12-09 22:28:23 +00:00
var getDateString = function ( date ) {
return ( date . getMonth ( ) + 1 ) + '/' + date . getDate ( ) + '/' + date . getFullYear ( ) ;
} ;
var getOffsetDate = function ( date , days ) {
return new Date ( date . getFullYear ( ) , date . getMonth ( ) , date . getDate ( ) + days ) ;
} ;
2013-11-27 07:29:31 +00:00
var update = function ( ) {
2013-12-10 04:33:28 +00:00
var hasValidUser = ! ! $scope . user ;
var hasValidOrg = ! ! $scope . organization ;
var hasValidRepo = $scope . repository && $scope . repository . namespace ;
var isValid = hasValidUser || hasValidOrg || hasValidRepo ;
if ( ! $scope . visible || ! isValid ) {
2013-11-27 07:29:31 +00:00
return ;
}
2013-12-09 22:28:23 +00:00
var twoWeeksAgo = getOffsetDate ( $scope . logEndDate , - 14 ) ;
2013-12-10 02:13:21 +00:00
if ( $scope . logStartDate > $scope . logEndDate || $scope . logStartDate < twoWeeksAgo ) {
2013-12-09 22:28:23 +00:00
$scope . logStartDate = twoWeeksAgo ;
}
2013-11-27 21:56:07 +00:00
$scope . loading = true ;
2013-11-27 07:29:31 +00:00
2013-12-26 22:45:16 +00:00
// Note: We construct the URLs here manually because we also use it for the download
// path.
2013-12-02 19:55:04 +00:00
var url = getRestUrl ( 'user/logs' ) ;
if ( $scope . organization ) {
url = getRestUrl ( 'organization' , $scope . organization . name , 'logs' ) ;
}
if ( $scope . repository ) {
url = getRestUrl ( 'repository' , $scope . repository . namespace , $scope . repository . name , 'logs' ) ;
}
2013-12-07 00:25:27 +00:00
2013-12-09 22:28:23 +00:00
url += '?starttime=' + encodeURIComponent ( getDateString ( $scope . logStartDate ) ) ;
url += '&endtime=' + encodeURIComponent ( getDateString ( $scope . logEndDate ) ) ;
2013-12-07 00:25:27 +00:00
if ( $scope . performer ) {
2013-12-09 22:28:23 +00:00
url += '&performer=' + encodeURIComponent ( $scope . performer . username ) ;
2013-12-07 00:25:27 +00:00
}
2013-12-09 22:28:23 +00:00
2013-11-27 07:29:31 +00:00
var loadLogs = Restangular . one ( url ) ;
loadLogs . customGET ( ) . then ( function ( resp ) {
2013-12-06 20:59:59 +00:00
$scope . logsPath = '/api/' + url ;
2013-11-27 07:29:31 +00:00
if ( ! $scope . chart ) {
2013-11-27 21:56:07 +00:00
$scope . chart = new LogUsageChart ( logKinds ) ;
2013-11-27 07:29:31 +00:00
$ ( $scope . chart ) . bind ( 'filteringChanged' , function ( e ) {
$scope . $apply ( function ( ) { $scope . kindsAllowed = e . allowed ; } ) ;
} ) ;
}
2013-12-09 22:28:23 +00:00
$scope . chart . draw ( 'bar-chart' , resp . logs , $scope . logStartDate , $scope . logEndDate ) ;
2013-11-29 05:04:50 +00:00
$scope . kindsAllowed = null ;
2013-11-27 07:29:31 +00:00
$scope . logs = resp . logs ;
$scope . loading = false ;
} ) ;
} ;
$scope . toggleChart = function ( ) {
$scope . chartVisible = ! $scope . chartVisible ;
} ;
$scope . isVisible = function ( allowed , kind ) {
return allowed == null || allowed . hasOwnProperty ( kind ) ;
} ;
$scope . getColor = function ( kind ) {
return $scope . chart . getColor ( kind ) ;
} ;
$scope . getDescription = function ( log ) {
2013-12-02 19:55:04 +00:00
var fieldIcons = {
'username' : 'user' ,
2014-01-21 22:04:00 +00:00
'activating_username' : 'user' ,
'delegate_user' : 'user' ,
'delegate_team' : 'group' ,
2013-12-02 19:55:04 +00:00
'team' : 'group' ,
'token' : 'key' ,
2014-01-21 21:23:00 +00:00
'repo' : 'hdd-o' ,
2014-01-21 22:04:00 +00:00
'robot' : 'wrench' ,
'tag' : 'tag' ,
'role' : 'th-large' ,
'original_role' : 'th-large'
2013-12-02 19:55:04 +00:00
} ;
2014-01-08 23:44:50 +00:00
log . metadata [ '_ip' ] = log . ip ? log . ip : null ;
2013-12-02 19:05:19 +00:00
2014-01-10 01:09:56 +00:00
var description = logDescriptions [ log . kind ] || log . kind ;
2013-12-02 19:05:19 +00:00
if ( typeof description != 'string' ) {
description = description ( log . metadata ) ;
}
2013-11-27 07:29:31 +00:00
for ( var key in log . metadata ) {
if ( log . metadata . hasOwnProperty ( key ) ) {
2014-01-08 23:44:50 +00:00
var value = log . metadata [ key ] != null ? log . metadata [ key ] . toString ( ) : '(Unknown)' ;
var markedDown = getMarkedDown ( value ) ;
2013-11-27 07:29:31 +00:00
markedDown = markedDown . substr ( '<p>' . length , markedDown . length - '<p></p>' . length ) ;
2013-12-02 19:55:04 +00:00
var icon = fieldIcons [ key ] ;
if ( icon ) {
markedDown = '<i class="fa fa-' + icon + '"></i>' + markedDown ;
}
2013-11-27 07:29:31 +00:00
description = description . replace ( '{' + key + '}' , '<code>' + markedDown + '</code>' ) ;
}
}
2014-01-21 22:04:00 +00:00
return $sce . trustAsHtml ( description . replace ( '\n' , '<br>' ) ) ;
2013-11-27 07:29:31 +00:00
} ;
$scope . $watch ( 'organization' , update ) ;
$scope . $watch ( 'user' , update ) ;
2013-12-02 19:55:04 +00:00
$scope . $watch ( 'repository' , update ) ;
2013-11-27 07:29:31 +00:00
$scope . $watch ( 'visible' , update ) ;
2013-12-07 00:25:27 +00:00
$scope . $watch ( 'performer' , update ) ;
2013-12-09 22:28:23 +00:00
$scope . $watch ( 'logStartDate' , update ) ;
$scope . $watch ( 'logEndDate' , update ) ;
2013-11-27 07:29:31 +00:00
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-22 23:20:51 +00:00
quayApp . directive ( 'robotsManager' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/robots-manager.html' ,
replace : false ,
2013-11-23 01:14:44 +00:00
transclude : false ,
2013-11-22 23:20:51 +00:00
restrict : 'C' ,
scope : {
'organization' : '=organization' ,
'user' : '=user'
} ,
2013-12-26 22:45:16 +00:00
controller : function ( $scope , $element , ApiService ) {
2013-12-10 06:38:05 +00:00
$scope . ROBOT _PATTERN = ROBOT _PATTERN ;
2013-11-22 23:20:51 +00:00
$scope . robots = null ;
$scope . loading = false ;
2013-11-23 01:14:44 +00:00
$scope . shownRobot = null ;
$scope . showRobotCounter = 0 ;
$scope . showRobot = function ( info ) {
$scope . shownRobot = info ;
$scope . showRobotCounter ++ ;
} ;
2013-11-22 23:20:51 +00:00
$scope . getShortenedName = function ( name ) {
var plus = name . indexOf ( '+' ) ;
return name . substr ( plus + 1 ) ;
} ;
$scope . getPrefix = function ( name ) {
var plus = name . indexOf ( '+' ) ;
return name . substr ( 0 , plus ) ;
} ;
2013-11-23 01:14:44 +00:00
$scope . createRobot = function ( name ) {
if ( ! name ) { return ; }
2013-12-26 22:45:16 +00:00
createRobotAccount ( ApiService , ! ! $scope . organization , $scope . organization ? $scope . organization . name : '' , name ,
2013-12-10 06:38:05 +00:00
function ( created ) {
$scope . robots . push ( created ) ;
} ) ;
2013-11-23 01:14:44 +00:00
} ;
2013-11-22 23:20:51 +00:00
$scope . deleteRobot = function ( info ) {
var shortName = $scope . getShortenedName ( info . name ) ;
2013-12-26 22:45:16 +00:00
ApiService . deleteRobot ( $scope . organization , null , { 'robot_shortname' : shortName } ) . then ( function ( resp ) {
2013-11-22 23:20:51 +00:00
for ( var i = 0 ; i < $scope . robots . length ; ++ i ) {
if ( $scope . robots [ i ] . name == info . name ) {
2013-11-23 01:14:44 +00:00
$scope . robots . splice ( i , 1 ) ;
2013-11-22 23:20:51 +00:00
return ;
}
}
} , function ( ) {
2013-11-23 01:14:44 +00:00
bootbox . dialog ( {
"message" : 'The selected robot account could not be deleted' ,
"title" : "Cannot delete robot account" ,
"buttons" : {
"close" : {
"label" : "Close" ,
"className" : "btn-primary"
}
}
} ) ;
2013-11-22 23:20:51 +00:00
} ) ;
} ;
var update = function ( ) {
if ( ! $scope . user && ! $scope . organization ) { return ; }
if ( $scope . loading ) { return ; }
$scope . loading = true ;
2013-12-26 22:45:16 +00:00
ApiService . getRobots ( $scope . organization ) . then ( function ( resp ) {
2013-11-22 23:20:51 +00:00
$scope . robots = resp . robots ;
$scope . loading = false ;
} ) ;
} ;
$scope . $watch ( 'organization' , update ) ;
$scope . $watch ( 'user' , update ) ;
}
} ;
return directiveDefinitionObject ;
} ) ;
2014-01-21 19:18:20 +00:00
quayApp . directive ( 'prototypeManager' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/prototype-manager.html' ,
replace : false ,
transclude : false ,
restrict : 'C' ,
scope : {
'organization' : '=organization'
} ,
controller : function ( $scope , $element , ApiService ) {
$scope . loading = false ;
2014-01-21 20:09:47 +00:00
$scope . activatingForNew = null ;
$scope . delegateForNew = null ;
$scope . clearCounter = 0 ;
2014-01-21 23:34:54 +00:00
$scope . newForWholeOrg = true ;
2014-01-21 19:18:20 +00:00
$scope . roles = [
{ 'id' : 'read' , 'title' : 'Read' , 'kind' : 'success' } ,
{ 'id' : 'write' , 'title' : 'Write' , 'kind' : 'success' } ,
{ 'id' : 'admin' , 'title' : 'Admin' , 'kind' : 'primary' }
] ;
$scope . setRole = function ( role , prototype ) {
var params = {
'orgname' : $scope . organization . name ,
'prototypeid' : prototype . id
} ;
var data = {
'id' : prototype . id ,
'role' : role
} ;
ApiService . updateOrganizationPrototypePermission ( data , params ) . then ( function ( resp ) {
prototype . role = role ;
} , function ( resp ) {
bootbox . dialog ( {
"message" : resp . data ? resp . data : 'The permission could not be modified' ,
"title" : "Cannot modify permission" ,
"buttons" : {
"close" : {
"label" : "Close" ,
"className" : "btn-primary"
}
}
} ) ;
} ) ;
} ;
2014-01-21 23:34:54 +00:00
$scope . comparePrototypes = function ( p ) {
return p . activating _user ? p . activating _user . name : ' ' ;
} ;
2014-01-21 20:09:47 +00:00
$scope . setRoleForNew = function ( role ) {
$scope . newRole = role ;
} ;
2014-01-21 23:34:54 +00:00
$scope . setNewForWholeOrg = function ( value ) {
$scope . newForWholeOrg = value ;
} ;
2014-01-21 20:09:47 +00:00
$scope . showAddDialog = function ( ) {
$scope . activatingForNew = null ;
$scope . delegateForNew = null ;
$scope . newRole = 'read' ;
$scope . clearCounter ++ ;
2014-01-21 23:34:54 +00:00
$scope . newForWholeOrg = true ;
2014-01-21 20:09:47 +00:00
$ ( '#addPermissionDialogModal' ) . modal ( { } ) ;
} ;
$scope . createPrototype = function ( ) {
$scope . loading = true ;
var params = {
'orgname' : $scope . organization . name
} ;
var data = {
2014-01-21 23:34:54 +00:00
'activating_user' : $scope . newForWholeOrg ? null : $scope . activatingForNew ,
2014-01-21 20:09:47 +00:00
'delegate' : $scope . delegateForNew ,
'role' : $scope . newRole
} ;
ApiService . createOrganizationPrototypePermission ( data , params ) . then ( function ( resp ) {
$scope . prototypes . push ( resp ) ;
$scope . loading = false ;
$ ( '#addPermissionDialogModal' ) . modal ( 'hide' ) ;
} , function ( resp ) {
$ ( '#addPermissionDialogModal' ) . modal ( 'hide' ) ;
bootbox . dialog ( {
"message" : resp . data ? resp . data : 'The permission could not be created' ,
"title" : "Cannot create permission" ,
"buttons" : {
"close" : {
"label" : "Close" ,
"className" : "btn-primary"
}
}
} ) ;
} ) ;
} ;
2014-01-21 19:18:20 +00:00
$scope . deletePrototype = function ( prototype ) {
$scope . loading = true ;
var params = {
'orgname' : $scope . organization . name ,
'prototypeid' : prototype . id
} ;
ApiService . deleteOrganizationPrototypePermission ( null , params ) . then ( function ( resp ) {
$scope . prototypes . splice ( $scope . prototypes . indexOf ( prototype ) , 1 ) ;
$scope . loading = false ;
} , function ( resp ) {
bootbox . dialog ( {
"message" : resp . data ? resp . data : 'The permission could not be deleted' ,
"title" : "Cannot delete permission" ,
"buttons" : {
"close" : {
"label" : "Close" ,
"className" : "btn-primary"
}
}
2014-01-21 20:09:47 +00:00
} ) ;
2014-01-21 19:18:20 +00:00
} ) ;
} ;
var update = function ( ) {
if ( ! $scope . organization ) { return ; }
if ( $scope . loading ) { return ; }
var params = { 'orgname' : $scope . organization . name } ;
$scope . loading = true ;
ApiService . getOrganizationPrototypePermissions ( null , params ) . then ( function ( resp ) {
$scope . prototypes = resp . prototypes ;
$scope . loading = false ;
} ) ;
} ;
$scope . $watch ( 'organization' , update ) ;
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-23 01:14:44 +00:00
quayApp . directive ( 'popupInputButton' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/popup-input-button.html' ,
replace : false ,
transclude : true ,
restrict : 'C' ,
scope : {
'placeholder' : '=placeholder' ,
'pattern' : '=pattern' ,
'submitted' : '&submitted'
} ,
controller : function ( $scope , $element ) {
$scope . popupShown = function ( ) {
setTimeout ( function ( ) {
var box = $ ( '#input-box' ) ;
box [ 0 ] . value = '' ;
box . focus ( ) ;
} , 10 ) ;
} ;
$scope . getRegexp = function ( pattern ) {
if ( ! pattern ) {
pattern = '.*' ;
}
return new RegExp ( pattern ) ;
} ;
$scope . inputSubmit = function ( ) {
var box = $ ( '#input-box' ) ;
if ( box . hasClass ( 'ng-invalid' ) ) { return ; }
var entered = box [ 0 ] . value ;
if ( ! entered ) {
return ;
}
if ( $scope . submitted ) {
$scope . submitted ( { 'value' : entered } ) ;
}
} ;
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-22 23:20:51 +00:00
2013-12-17 18:19:59 +00:00
quayApp . directive ( 'resourceView' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/resource-view.html' ,
replace : false ,
transclude : true ,
restrict : 'C' ,
scope : {
'resource' : '=resource' ,
'errorMessage' : '=errorMessage'
} ,
controller : function ( $scope , $element ) {
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-12-18 03:56:28 +00:00
quayApp . directive ( 'quaySpinner' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/spinner.html' ,
replace : false ,
transclude : true ,
restrict : 'C' ,
scope : { } ,
controller : function ( $scope , $element ) {
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-04 19:56:54 +00:00
quayApp . directive ( 'organizationHeader' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/organization-header.html' ,
replace : false ,
2013-11-05 21:15:04 +00:00
transclude : true ,
2013-11-04 19:56:54 +00:00
restrict : 'C' ,
scope : {
'organization' : '=organization' ,
2013-12-02 22:19:19 +00:00
'teamName' : '=teamName' ,
'clickable' : '=clickable'
2013-11-04 19:56:54 +00:00
} ,
controller : function ( $scope , $element ) {
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-05 00:59:28 +00:00
quayApp . directive ( 'markdownInput' , function ( ) {
var counter = 0 ;
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/markdown-input.html' ,
replace : false ,
transclude : false ,
restrict : 'C' ,
scope : {
'content' : '=content' ,
'canWrite' : '=canWrite' ,
'contentChanged' : '=contentChanged' ,
'fieldTitle' : '=fieldTitle'
} ,
controller : function ( $scope , $element ) {
var elm = $element [ 0 ] ;
$scope . id = ( counter ++ ) ;
$scope . editContent = function ( ) {
if ( ! $scope . canWrite ) { return ; }
if ( ! $scope . markdownDescriptionEditor ) {
var converter = Markdown . getSanitizingConverter ( ) ;
var editor = new Markdown . Editor ( converter , '-description-' + $scope . id ) ;
editor . run ( ) ;
$scope . markdownDescriptionEditor = editor ;
}
$ ( '#wmd-input-description-' + $scope . id ) [ 0 ] . value = $scope . content ;
$ ( elm ) . find ( '.modal' ) . modal ( { } ) ;
} ;
$scope . saveContent = function ( ) {
$scope . content = $ ( '#wmd-input-description-' + $scope . id ) [ 0 ] . value ;
$ ( elm ) . find ( '.modal' ) . modal ( 'hide' ) ;
if ( $scope . contentChanged ) {
$scope . contentChanged ( $scope . content ) ;
}
} ;
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-19 00:03:35 +00:00
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">' ;
2014-01-15 20:40:37 +00:00
template += '<i class="fa fa-hdd-o fa-lg"></i>'
2013-11-19 00:03:35 +00:00
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 : {
} ,
2013-12-26 22:45:16 +00:00
controller : function ( $scope , $element , $location , UserService , PlanService , ApiService ) {
2013-12-19 04:03:19 +00:00
$scope . overPlan = false ;
var checkOverPlan = function ( ) {
if ( $scope . user . anonymous ) {
$scope . overPlan = false ;
return ;
}
2013-12-26 22:45:16 +00:00
ApiService . getUserPrivateCount ( ) . then ( function ( resp ) {
2013-12-19 20:29:39 +00:00
$scope . overPlan = resp . privateCount > resp . reposAllowed ;
2013-12-19 04:03:19 +00:00
} ) ;
} ;
// Monitor any user changes and place the current user into the scope.
UserService . updateUserIn ( $scope , checkOverPlan ) ;
// Monitor any plan changes.
PlanService . registerListener ( this , checkOverPlan ) ;
2013-11-19 00:03:35 +00:00
$scope . signout = function ( ) {
2013-12-26 22:45:16 +00:00
ApiService . logout ( ) . then ( function ( ) {
UserService . load ( ) ;
$location . path ( '/' ) ;
2013-11-19 00:03:35 +00:00
} ) ;
} ;
$scope . appLinkTarget = function ( ) {
if ( $ ( "div[ng-view]" ) . length === 0 ) {
return "_self" ;
}
return "" ;
2013-12-19 04:03:19 +00:00
} ;
2013-11-19 00:03:35 +00:00
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-02 01:48:10 +00:00
quayApp . directive ( 'entitySearch' , function ( ) {
var number = 0 ;
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/entity-search.html' ,
replace : false ,
transclude : false ,
restrict : 'C' ,
scope : {
2013-11-20 23:23:59 +00:00
'namespace' : '=namespace' ,
2013-11-02 01:48:10 +00:00
'inputTitle' : '=inputTitle' ,
2013-11-20 23:23:59 +00:00
'entitySelected' : '=entitySelected' ,
2013-12-10 06:38:05 +00:00
'includeTeams' : '=includeTeams' ,
2014-01-21 20:09:47 +00:00
'isOrganization' : '=isOrganization' ,
'isPersistent' : '=isPersistent' ,
'currentEntity' : '=currentEntity' ,
'clearNow' : '=clearNow'
2013-11-02 01:48:10 +00:00
} ,
2013-12-26 22:45:16 +00:00
controller : function ( $scope , $element , Restangular , UserService , ApiService ) {
2013-12-10 06:38:05 +00:00
$scope . lazyLoading = true ;
$scope . isAdmin = false ;
$scope . lazyLoad = function ( ) {
if ( ! $scope . namespace || ! $scope . lazyLoading ) { return ; }
2013-12-10 20:49:34 +00:00
$scope . isAdmin = UserService . isNamespaceAdmin ( $scope . namespace ) ;
2013-12-10 06:38:05 +00:00
if ( $scope . isOrganization && $scope . includeTeams ) {
2013-12-26 22:45:16 +00:00
ApiService . getOrganization ( null , { 'orgname' : $scope . namespace } ) . then ( function ( resp ) {
2013-12-10 06:38:05 +00:00
$scope . teams = resp . teams ;
} ) ;
}
2013-12-26 22:45:16 +00:00
ApiService . getRobots ( $scope . isOrganization ? $scope . namespace : null ) . then ( function ( resp ) {
2013-12-10 20:49:34 +00:00
$scope . robots = resp . robots ;
2013-12-10 06:38:05 +00:00
$scope . lazyLoading = false ;
2013-12-10 20:49:34 +00:00
} , function ( ) {
$scope . lazyLoading = false ;
} ) ;
2013-12-10 06:38:05 +00:00
} ;
$scope . createTeam = function ( ) {
2013-12-10 20:49:34 +00:00
if ( ! $scope . isAdmin ) { return ; }
2013-12-10 06:38:05 +00:00
bootbox . prompt ( 'Enter the name of the new team' , function ( teamname ) {
if ( ! teamname ) { return ; }
var regex = new RegExp ( TEAM _PATTERN ) ;
if ( ! regex . test ( teamname ) ) {
bootbox . alert ( 'Invalid team name' ) ;
return ;
}
2013-12-26 22:45:16 +00:00
createOrganizationTeam ( ApiService , $scope . namespace , teamname , function ( created ) {
2013-12-10 06:38:05 +00:00
$scope . setEntity ( created . name , 'team' , false ) ;
$scope . teams [ teamname ] = created ;
} ) ;
} ) ;
} ;
$scope . createRobot = function ( ) {
2013-12-10 20:49:34 +00:00
if ( ! $scope . isAdmin ) { return ; }
2013-12-10 06:38:05 +00:00
bootbox . prompt ( 'Enter the name of the new robot account' , function ( robotname ) {
if ( ! robotname ) { return ; }
var regex = new RegExp ( ROBOT _PATTERN ) ;
if ( ! regex . test ( robotname ) ) {
bootbox . alert ( 'Invalid robot account name' ) ;
return ;
}
2013-12-26 22:45:16 +00:00
createRobotAccount ( ApiService , $scope . isOrganization , $scope . namespace , robotname , function ( created ) {
2013-12-10 06:38:05 +00:00
$scope . setEntity ( created . name , 'user' , true ) ;
$scope . robots . push ( created ) ;
} ) ;
} ) ;
} ;
$scope . setEntity = function ( name , kind , is _robot ) {
var entity = {
'name' : name ,
'kind' : kind ,
'is_robot' : is _robot
} ;
if ( $scope . is _organization ) {
entity [ 'is_org_member' ] = true ;
}
2014-01-21 20:09:47 +00:00
$scope . setEntityInternal ( entity ) ;
2013-12-10 06:38:05 +00:00
} ;
2014-01-21 20:09:47 +00:00
$scope . clearEntityInternal = function ( ) {
$scope . currentEntity = null ;
if ( $scope . entitySelected ) {
$scope . entitySelected ( null ) ;
}
} ;
$scope . setEntityInternal = function ( entity ) {
$ ( input ) . typeahead ( 'setQuery' , $scope . isPersistent ? entity . name : '' ) ;
if ( $scope . isPersistent ) {
$scope . currentEntity = entity ;
}
if ( $scope . entitySelected ) {
$scope . entitySelected ( entity ) ;
}
} ;
2013-11-02 01:48:10 +00:00
number ++ ;
2013-12-10 06:38:05 +00:00
var input = $element [ 0 ] . firstChild . firstChild ;
2013-11-02 01:48:10 +00:00
$ ( input ) . typeahead ( {
name : 'entities' + number ,
remote : {
url : '/api/entities/%QUERY' ,
replace : function ( url , uriEncodedQuery ) {
2013-12-18 03:56:28 +00:00
var namespace = $scope . namespace || '' ;
url = url . replace ( '%QUERY' , uriEncodedQuery ) ;
url += '?namespace=' + encodeURIComponent ( namespace ) ;
if ( $scope . includeTeams ) {
url += '&includeTeams=true'
}
return url ;
2013-11-02 01:48:10 +00:00
} ,
filter : function ( data ) {
var datums = [ ] ;
for ( var i = 0 ; i < data . results . length ; ++ i ) {
var entity = data . results [ i ] ;
datums . push ( {
'value' : entity . name ,
'tokens' : [ entity . name ] ,
'entity' : entity
} ) ;
}
return datums ;
}
} ,
template : function ( datum ) {
template = '<div class="entity-mini-listing">' ;
2013-11-21 00:43:19 +00:00
if ( datum . entity . kind == 'user' && ! datum . entity . is _robot ) {
2013-11-02 01:48:10 +00:00
template += '<i class="fa fa-user fa-lg"></i>' ;
2013-11-21 00:43:19 +00:00
} else if ( datum . entity . kind == 'user' && datum . entity . is _robot ) {
template += '<i class="fa fa-wrench fa-lg"></i>' ;
2013-11-02 01:48:10 +00:00
} else if ( datum . entity . kind == 'team' ) {
template += '<i class="fa fa-group fa-lg"></i>' ;
}
template += '<span class="name">' + datum . value + '</span>' ;
2013-12-18 03:56:28 +00:00
if ( datum . entity . is _org _member === false && datum . entity . kind == 'user' ) {
template += '<i class="fa fa-exclamation-triangle" title="User is outside the organization"></i>' ;
2013-11-02 01:48:10 +00:00
}
template += '</div>' ;
return template ;
} ,
} ) ;
2014-01-21 20:09:47 +00:00
$ ( input ) . on ( 'input' , function ( e ) {
$scope . $apply ( function ( ) {
if ( $scope . isPersistent ) {
$scope . clearEntityInternal ( ) ;
}
} ) ;
} ) ;
2013-11-02 01:48:10 +00:00
$ ( input ) . on ( 'typeahead:selected' , function ( e , datum ) {
2013-12-10 06:38:05 +00:00
$scope . $apply ( function ( ) {
2014-01-21 20:09:47 +00:00
$scope . setEntityInternal ( datum . entity ) ;
2013-12-10 06:38:05 +00:00
} ) ;
2013-11-02 01:48:10 +00:00
} ) ;
2014-01-21 20:09:47 +00:00
$scope . $watch ( 'clearNow' , function ( ) {
$ ( input ) . typeahead ( 'setQuery' , '' ) ;
$scope . clearEntityInternal ( ) ;
} ) ;
2013-11-02 01:48:10 +00:00
$scope . $watch ( 'inputTitle' , function ( title ) {
input . setAttribute ( 'placeholder' , title ) ;
} ) ;
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-05 19:47:46 +00:00
quayApp . directive ( 'roleGroup' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/role-group.html' ,
replace : false ,
transclude : false ,
restrict : 'C' ,
scope : {
'roles' : '=roles' ,
'currentRole' : '=currentRole' ,
'roleChanged' : '&roleChanged'
} ,
controller : function ( $scope , $element ) {
$scope . setRole = function ( role ) {
2013-11-08 04:35:27 +00:00
if ( $scope . currentRole == role ) { return ; }
if ( $scope . roleChanged ) {
2013-11-05 19:47:46 +00:00
$scope . roleChanged ( { 'role' : role } ) ;
2013-11-08 04:35:27 +00:00
} else {
$scope . currentRole = role ;
2013-11-05 19:47:46 +00:00
}
} ;
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-15 19:42:31 +00:00
quayApp . directive ( 'billingOptions' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/billing-options.html' ,
replace : false ,
transclude : false ,
restrict : 'C' ,
scope : {
'user' : '=user' ,
'organization' : '=organization'
} ,
2013-12-26 22:45:16 +00:00
controller : function ( $scope , $element , PlanService , ApiService ) {
2013-11-15 19:42:31 +00:00
$scope . invoice _email = false ;
2013-11-15 23:17:12 +00:00
$scope . currentCard = null ;
// Listen to plan changes.
PlanService . registerListener ( this , function ( plan ) {
if ( plan && plan . price > 0 ) {
update ( ) ;
}
} ) ;
$scope . $on ( '$destroy' , function ( ) {
PlanService . unregisterListener ( this ) ;
} ) ;
$scope . changeCard = function ( ) {
2013-11-19 22:06:17 +00:00
var previousCard = $scope . currentCard ;
2013-11-15 23:17:12 +00:00
$scope . changingCard = true ;
var callbacks = {
'opened' : function ( ) { $scope . changingCard = true ; } ,
'closed' : function ( ) { $scope . changingCard = false ; } ,
'started' : function ( ) { $scope . currentCard = null ; } ,
'success' : function ( resp ) {
$scope . currentCard = resp . card ;
$scope . changingCard = false ;
} ,
2013-11-19 22:06:17 +00:00
'failure' : function ( resp ) {
2013-11-15 23:17:12 +00:00
$scope . changingCard = false ;
2013-11-19 22:06:17 +00:00
$scope . currentCard = previousCard ;
if ( ! PlanService . isCardError ( resp ) ) {
$ ( '#cannotchangecardModal' ) . modal ( { } ) ;
}
2013-11-15 23:17:12 +00:00
}
} ;
PlanService . changeCreditCard ( $scope , $scope . organization ? $scope . organization . name : null , callbacks ) ;
} ;
$scope . getCreditImage = function ( creditInfo ) {
2013-11-15 23:34:54 +00:00
if ( ! creditInfo || ! creditInfo . type ) { return 'credit.png' ; }
2013-11-15 23:17:12 +00:00
var kind = creditInfo . type . toLowerCase ( ) || 'credit' ;
var supported = {
'american express' : 'amex' ,
'credit' : 'credit' ,
'diners club' : 'diners' ,
'discover' : 'discover' ,
'jcb' : 'jcb' ,
'mastercard' : 'mastercard' ,
'visa' : 'visa'
} ;
kind = supported [ kind ] || 'credit' ;
return kind + '.png' ;
} ;
2013-11-15 19:42:31 +00:00
var update = function ( ) {
if ( ! $scope . user && ! $scope . organization ) { return ; }
$scope . obj = $scope . user ? $scope . user : $scope . organization ;
$scope . invoice _email = $scope . obj . invoice _email ;
2013-11-15 23:17:12 +00:00
// Load the credit card information.
2013-11-15 23:58:47 +00:00
PlanService . getCardInfo ( $scope . organization ? $scope . organization . name : null , function ( card ) {
$scope . currentCard = card ;
2013-11-15 23:17:12 +00:00
} ) ;
2013-11-15 19:42:31 +00:00
} ;
var save = function ( ) {
$scope . working = true ;
2013-12-26 22:45:16 +00:00
ApiService . changeDetails ( $scope . organization , $scope . obj ) . then ( function ( resp ) {
2013-11-15 19:42:31 +00:00
$scope . working = false ;
} ) ;
} ;
var checkSave = function ( ) {
if ( ! $scope . obj ) { return ; }
if ( $scope . obj . invoice _email != $scope . invoice _email ) {
$scope . obj . invoice _email = $scope . invoice _email ;
save ( ) ;
}
} ;
$scope . $watch ( 'invoice_email' , checkSave ) ;
$scope . $watch ( 'organization' , update ) ;
$scope . $watch ( 'user' , update ) ;
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-06 22:30:20 +00:00
quayApp . directive ( 'planManager' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/plan-manager.html' ,
replace : false ,
transclude : false ,
restrict : 'C' ,
scope : {
'user' : '=user' ,
2013-11-06 23:14:22 +00:00
'organization' : '=organization' ,
2013-11-15 23:17:12 +00:00
'readyForPlan' : '&readyForPlan' ,
'planChanged' : '&planChanged'
2013-11-06 22:30:20 +00:00
} ,
2013-12-26 22:45:16 +00:00
controller : function ( $scope , $element , PlanService , ApiService ) {
2013-11-06 22:30:20 +00:00
var hasSubscription = false ;
2013-12-20 02:51:46 +00:00
$scope . isPlanVisible = function ( plan , subscribedPlan ) {
if ( plan [ 'deprecated' ] ) {
return plan == subscribedPlan ;
}
if ( $scope . organization && ! PlanService . isOrgCompatible ( plan ) ) {
return false ;
}
return true ;
2013-11-06 22:30:20 +00:00
} ;
$scope . changeSubscription = function ( planId ) {
if ( $scope . planChanging ) { return ; }
2013-11-09 01:32:56 +00:00
var callbacks = {
'opening' : function ( ) { $scope . planChanging = true ; } ,
'started' : function ( ) { $scope . planChanging = true ; } ,
'opened' : function ( ) { $scope . planChanging = true ; } ,
'closed' : function ( ) { $scope . planChanging = false ; } ,
'success' : subscribedToPlan ,
2013-11-19 22:06:17 +00:00
'failure' : function ( resp ) {
$scope . planChanging = false ;
}
2013-11-09 01:32:56 +00:00
} ;
2013-11-15 23:58:47 +00:00
PlanService . changePlan ( $scope , $scope . organization , planId , callbacks ) ;
2013-11-06 22:30:20 +00:00
} ;
$scope . cancelSubscription = function ( ) {
2013-12-20 02:51:46 +00:00
$scope . changeSubscription ( PlanService . getFreePlan ( ) ) ;
2013-11-06 22:30:20 +00:00
} ;
var subscribedToPlan = function ( sub ) {
$scope . subscription = sub ;
2013-12-20 02:51:46 +00:00
if ( sub . plan != PlanService . getFreePlan ( ) ) {
2013-11-06 22:30:20 +00:00
hasSubscription = true ;
}
2013-12-20 02:51:46 +00:00
PlanService . getPlanIncludingDeprecated ( sub . plan , function ( subscribedPlan ) {
2013-11-06 22:30:20 +00:00
$scope . subscribedPlan = subscribedPlan ;
$scope . planUsagePercent = sub . usedPrivateRepos * 100 / $scope . subscribedPlan . privateRepos ;
2013-11-15 23:17:12 +00:00
if ( $scope . planChanged ) {
$scope . planChanged ( { 'plan' : subscribedPlan } ) ;
}
2013-11-06 22:30:20 +00:00
if ( sub . usedPrivateRepos > $scope . subscribedPlan . privateRepos ) {
2013-11-06 22:59:16 +00:00
$scope . limit = 'over' ;
} else if ( sub . usedPrivateRepos == $scope . subscribedPlan . privateRepos ) {
$scope . limit = 'at' ;
2013-11-06 22:30:20 +00:00
} else if ( sub . usedPrivateRepos >= $scope . subscribedPlan . privateRepos * 0.7 ) {
2013-11-06 22:59:16 +00:00
$scope . limit = 'near' ;
2013-11-06 22:30:20 +00:00
} else {
2013-11-06 22:59:16 +00:00
$scope . limit = 'none' ;
2013-11-06 22:30:20 +00:00
}
if ( ! $scope . chart ) {
$scope . chart = new RepositoryUsageChart ( ) ;
$scope . chart . draw ( 'repository-usage-chart' ) ;
}
$scope . chart . update ( sub . usedPrivateRepos || 0 , $scope . subscribedPlan . privateRepos || 0 ) ;
$scope . planChanging = false ;
$scope . planLoading = false ;
} ) ;
} ;
var update = function ( ) {
$scope . planLoading = true ;
if ( ! $scope . plans ) { return ; }
PlanService . getSubscription ( $scope . organization , subscribedToPlan , function ( ) {
// User/Organization has no subscription.
2013-12-20 02:51:46 +00:00
subscribedToPlan ( { 'plan' : PlanService . getFreePlan ( ) } ) ;
2013-11-06 22:30:20 +00:00
} ) ;
} ;
var loadPlans = function ( ) {
2013-11-07 20:33:56 +00:00
if ( $scope . plans || $scope . loadingPlans ) { return ; }
2013-11-06 22:59:16 +00:00
if ( ! $scope . user && ! $scope . organization ) { return ; }
2013-11-06 23:14:22 +00:00
2013-11-07 20:33:56 +00:00
$scope . loadingPlans = true ;
2013-12-20 02:51:46 +00:00
PlanService . verifyLoaded ( function ( plans ) {
$scope . plans = plans ;
2013-11-06 22:30:20 +00:00
update ( ) ;
2013-11-06 23:14:22 +00:00
if ( $scope . readyForPlan ) {
var planRequested = $scope . readyForPlan ( ) ;
2013-12-20 02:51:46 +00:00
if ( planRequested && planRequested != PlanService . getFreePlan ( ) ) {
2013-11-06 23:14:22 +00:00
$scope . changeSubscription ( planRequested ) ;
}
}
2013-11-06 22:30:20 +00:00
} ) ;
} ;
// Start the initial download.
2013-11-06 22:59:16 +00:00
$scope . planLoading = true ;
loadPlans ( ) ;
2013-11-06 22:30:20 +00:00
2013-11-07 00:19:21 +00:00
$scope . $watch ( 'organization' , loadPlans ) ;
$scope . $watch ( 'user' , loadPlans ) ;
2013-11-06 22:30:20 +00:00
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-01 21:35:26 +00:00
quayApp . directive ( 'namespaceSelector' , function ( ) {
var directiveDefinitionObject = {
priority : 0 ,
templateUrl : '/static/directives/namespace-selector.html' ,
replace : false ,
transclude : false ,
restrict : 'C' ,
scope : {
'user' : '=user' ,
2013-11-07 05:49:13 +00:00
'namespace' : '=namespace' ,
'requireCreate' : '=requireCreate'
2013-11-01 21:35:26 +00:00
} ,
2013-12-17 20:03:34 +00:00
controller : function ( $scope , $element , $routeParams , CookieService ) {
2013-11-07 05:49:13 +00:00
$scope . namespaces = { } ;
$scope . initialize = function ( user ) {
2014-01-16 00:15:38 +00:00
var preferredNamespace = user . username ;
2013-11-07 05:49:13 +00:00
var namespaces = { } ;
namespaces [ user . username ] = user ;
2013-11-07 06:48:58 +00:00
if ( user . organizations ) {
for ( var i = 0 ; i < user . organizations . length ; ++ i ) {
namespaces [ user . organizations [ i ] . name ] = user . organizations [ i ] ;
2014-01-16 00:15:38 +00:00
if ( user . organizations [ i ] . preferred _namespace ) {
preferredNamespace = user . organizations [ i ] . name ;
}
2013-11-07 06:48:58 +00:00
}
2013-11-07 05:49:13 +00:00
}
2014-01-16 00:15:38 +00:00
var initialNamespace = $routeParams [ 'namespace' ] || CookieService . get ( 'quay.namespace' ) ||
preferredNamespace || $scope . user . username ;
2013-11-07 05:49:13 +00:00
$scope . namespaces = namespaces ;
$scope . setNamespace ( $scope . namespaces [ initialNamespace ] ) ;
} ;
2013-11-01 21:35:26 +00:00
$scope . setNamespace = function ( namespaceObj ) {
if ( ! namespaceObj ) {
2013-11-07 05:49:13 +00:00
namespaceObj = $scope . namespaces [ $scope . user . username ] ;
}
if ( $scope . requireCreate && ! namespaceObj . can _create _repo ) {
namespaceObj = $scope . namespaces [ $scope . user . username ] ;
2013-11-01 21:35:26 +00:00
}
2013-11-07 05:49:13 +00:00
var newNamespace = namespaceObj . name || namespaceObj . username ;
2013-11-01 21:35:26 +00:00
$scope . namespaceObj = namespaceObj ;
2013-11-07 05:49:13 +00:00
$scope . namespace = newNamespace ;
2013-12-17 20:03:34 +00:00
if ( newNamespace ) {
CookieService . putPermanent ( 'quay.namespace' , newNamespace ) ;
}
2013-11-01 21:35:26 +00:00
} ;
2014-01-16 00:15:38 +00:00
$scope . $watch ( 'namespace' , function ( namespace ) {
if ( $scope . namespaceObj && namespace && namespace != $scope . namespaceObj . username ) {
$scope . setNamespace ( $scope . namespaces [ namespace ] ) ;
}
} ) ;
2013-11-01 21:35:26 +00:00
$scope . $watch ( 'user' , function ( user ) {
2013-11-07 05:49:13 +00:00
$scope . user = user ;
$scope . initialize ( user ) ;
2013-11-01 21:35:26 +00:00
} ) ;
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-10-26 20:03:11 +00:00
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' :
2014-01-02 19:13:16 +00:00
return buildInfo . push _completion * 100 ;
2013-10-26 20:03:11 +00:00
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 ;
}
} ;
2013-10-22 05:26:14 +00:00
}
} ;
return directiveDefinitionObject ;
} ) ;
2013-11-05 22:20:43 +00:00
// Note: ngBlur is not yet in Angular stable, so we add it manaully here.
quayApp . directive ( 'ngBlur' , function ( ) {
return function ( scope , elem , attrs ) {
elem . bind ( 'blur' , function ( ) {
scope . $apply ( attrs . ngBlur ) ;
} ) ;
} ;
} ) ;
2013-12-17 20:03:34 +00:00
quayApp . run ( [ '$location' , '$rootScope' , 'Restangular' , 'UserService' , 'PlanService' , '$http' , '$timeout' ,
function ( $location , $rootScope , Restangular , UserService , PlanService , $http , $timeout ) {
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 ) {
if ( response . status == 401 ) {
$ ( '#sessionexpiredModal' ) . modal ( { } ) ;
return false ;
2013-11-12 00:03:18 +00:00
}
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.
PlanService . handleNotedPlan ( ) ;
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
2014-01-10 01:17:28 +00:00
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 ) {
2014-01-10 01:17:28 +00:00
clickElement ( this ) ;
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 ) {
if ( current . $$route . title ) {
$rootScope . title = current . $$route . title ;
}
2013-11-19 00:03:35 +00:00
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.' ;
}
2013-11-20 21:17:47 +00:00
2013-11-24 01:03:08 +00:00
$rootScope . fixFooter = ! ! current . $$route . fixFooter ;
2013-12-10 04:33:28 +00:00
$rootScope . current = current . $$route ;
} ) ;
$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.
$ ( '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 data = isDefaultTab ? { } : { 'tab' : tabName } ;
$location . search ( data ) ;
} ) ;
e . preventDefault ( ) ;
} ) ;
if ( activeTab ) {
changeTab ( activeTab ) ;
}
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
} ] ) ;