import * as angular from "angular"; import * as Raven from "raven-js"; import { ViewArrayImpl } from "./services/view-array/view-array.impl"; import { NAME_PATTERNS } from "./constants/name-patterns.constant"; import { INJECTED_CONFIG, INJECTED_FEATURES, INJECTED_ENDPOINTS } from "./constants/injected-values.constant"; import { RegexMatchViewComponent } from "./directives/ui/regex-match-view/regex-match-view.component"; import { NgModule } from "angular-ts-decorators"; import { QuayRoutes } from "./quay-routes.module"; import { DockerfilePathSelectComponent } from './directives/ui/dockerfile-path-select/dockerfile-path-select.component'; var quayDependencies: any[] = [ QuayRoutes, 'chieffancypants.loadingBar', 'cfp.hotkeys', 'angular-tour', 'restangular', 'angularMoment', 'mgcrea.ngStrap', 'ngCookies', 'ngSanitize', 'angular-md5', 'pasvaz.bindonce', 'ansiToHtml', 'core-ui', 'core-config-setup', 'infinite-scroll', 'react' ]; if (INJECTED_CONFIG && (INJECTED_CONFIG.MIXPANEL_KEY || INJECTED_CONFIG.MUNCHKIN_KEY || INJECTED_CONFIG.GOOGLE_ANALYTICS_KEY)) { quayDependencies.push('angulartics'); } if (INJECTED_CONFIG && INJECTED_CONFIG.MIXPANEL_KEY) { quayDependencies.push('angulartics.mixpanel'); } if (INJECTED_CONFIG && INJECTED_CONFIG.MUNCHKIN_KEY) { quayDependencies.push('angulartics.marketo'); } if (INJECTED_CONFIG && INJECTED_CONFIG.GOOGLE_ANALYTICS_KEY) { quayDependencies.push('angulartics.google.analytics'); } if (INJECTED_CONFIG && INJECTED_CONFIG.RECAPTCHA_SITE_KEY) { quayDependencies.push('vcRecaptcha'); } /** * Main application module. */ @NgModule({ imports: quayDependencies, declarations: [ RegexMatchViewComponent, DockerfilePathSelectComponent, ], providers: [ ViewArrayImpl, ], }) export class quay { public config($provide: ng.auto.IProvideService, $injector: ng.auto.IInjectorService, INJECTED_CONFIG: any, cfpLoadingBarProvider: any, $tooltipProvider: any, $compileProvider: ng.ICompileProvider, RestangularProvider: any): void { cfpLoadingBarProvider.includeSpinner = false; // decorate the tooltip getter var tooltipFactory: any = $tooltipProvider.$get[$tooltipProvider.$get.length - 1]; $tooltipProvider.$get[$tooltipProvider.$get.length - 1] = function($window: ng.IWindowService) { if ('ontouchstart' in $window) { var existing: any = tooltipFactory.apply(this, arguments); return function(element) { // Note: We only disable bs-tooltip's themselves. $tooltip is used for other things // (such as the datepicker), so we need to be specific when canceling it. if (element !== undefined && element.attr('bs-tooltip') == null) { return existing.apply(this, arguments); } }; } return tooltipFactory.apply(this, arguments); }; if (!INJECTED_CONFIG['DEBUG']) { $compileProvider.debugInfoEnabled(false); } // Configure compile provider to add additional URL prefixes to the sanitization list. We use // these on the Contact page. $compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|irc):/); // Configure the API provider. RestangularProvider.setBaseUrl('/api/v1/'); // Configure analytics. if (INJECTED_CONFIG && INJECTED_CONFIG.MIXPANEL_KEY) { let $analyticsProvider: any = $injector.get('$analyticsProvider'); $analyticsProvider.virtualPageviews(true); } // Configure sentry. if (INJECTED_CONFIG && INJECTED_CONFIG.SENTRY_PUBLIC_DSN) { $provide.decorator("$exceptionHandler", function($delegate) { return function(ex, cause) { $delegate(ex, cause); Raven.captureException(ex, {extra: {cause: cause}}); }; }); } } public run($rootScope: QuayRunScope, Restangular: any, PlanService: any, $http: ng.IHttpService, CookieService: any, Features: any, $anchorScroll: ng.IAnchorScrollService, MetaService: any, INJECTED_CONFIG: any): void { var defaultTitle = INJECTED_CONFIG['REGISTRY_TITLE'] || 'Quay Container Registry'; // Handle session security. Restangular.setDefaultRequestParams(['post', 'put', 'remove', 'delete'], {'_csrf_token': (window).__token || ''}); // Handle session expiration. Restangular.setErrorInterceptor(function(response) { if (response !== undefined && response.status == 503) { ($('#cannotContactService')).modal({}); return false; } if (response !== undefined && response.status == 500) { window.location.href = '/500'; return false; } if (response !== undefined && !response.data) { return true; } var invalid_token = response.data['title'] == 'invalid_token' || response.data['error_type'] == 'invalid_token'; if (response !== undefined && response.status == 401 && invalid_token && response.data['session_required'] !== false) { ($('#sessionexpiredModal')).modal({}); return false; } return true; }); // Check if we need to redirect based on a previously chosen plan. 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; } $rootScope.$watch('description', function(description: string) { if (!description) { description = `Hosted private docker repositories. Includes full user management and history. Free for public repositories.`; } // Note: We set the content of the description tag manually here rather than using Angular binding // because we need the 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. $('#descriptionTag').attr('content', description); }); // Listen for scope changes and update the title and description accordingly. $rootScope.$watch(function() { var title = MetaService.getTitle($rootScope.currentPage) || defaultTitle; $rootScope.title = title; var description = MetaService.getDescription($rootScope.currentPage) || ''; if ($rootScope.description != description) { $rootScope.description = description; } }); $rootScope.$on('$routeChangeSuccess', function (event, current, previous) { $rootScope.current = current.$$route; $rootScope.currentPage = current; $rootScope.pageClass = ''; if (!current.$$route) { return; } var pageClass = current.$$route.pageClass || ''; if (typeof pageClass != 'string') { pageClass = pageClass(Features); } $rootScope.pageClass = pageClass; $rootScope.newLayout = !!current.$$route.newLayout; $rootScope.fixFooter = !!current.$$route.fixFooter; $anchorScroll(); }); var initallyChecked: boolean = false; (window).__isLoading = function() { if (!initallyChecked) { initallyChecked = true; return true; } return $http.pendingRequests.length > 0; }; } } interface QuayRunScope extends ng.IRootScopeService { currentPage: any; current: any; title: any; description: string, pageClass: any; newLayout: any; fixFooter: any; } // TODO: Move component registration to @NgModule and remove this. angular .module(quay.name) .constant('NAME_PATTERNS', NAME_PATTERNS) .constant('INJECTED_CONFIG', INJECTED_CONFIG) .constant('INJECTED_FEATURES', INJECTED_FEATURES) .constant('INJECTED_ENDPOINTS', INJECTED_ENDPOINTS);