diff --git a/app/scripts/modules/core/core.module.js b/app/scripts/modules/core/core.module.js index e3050c91a63..0be8ee78a97 100644 --- a/app/scripts/modules/core/core.module.js +++ b/app/scripts/modules/core/core.module.js @@ -23,6 +23,7 @@ import {INSIGHT_NGMODULE} from './insight/insight.module'; import {REPLACE_FILTER} from './filter/replace.filter'; import {PIPELINE_TEMPLATE_MODULE} from './pipeline/config/templates/pipelineTemplate.module'; import {HEALTH_COUNTS_COMPONENT} from './healthCounts/healthCounts.component'; +import {CORE_PAGETITLE_SERVICE} from './pageTitle/pageTitle.service'; require('../../../fonts/spinnaker/icons.css'); @@ -109,7 +110,7 @@ module.exports = angular require('./notification/types/slack/slack.notification.type.module.js'), require('./notification/types/sms/sms.notification.type.module.js'), - require('./pageTitle/pageTitle.service.js'), + CORE_PAGETITLE_SERVICE, require('./pipeline/pipelines.module.js'), require('./pipeline/config/stages/bake/bakeStage.module.js'), diff --git a/app/scripts/modules/core/pageTitle/pageTitle.service.js b/app/scripts/modules/core/pageTitle/pageTitle.service.js deleted file mode 100644 index 8ea0c1e2628..00000000000 --- a/app/scripts/modules/core/pageTitle/pageTitle.service.js +++ /dev/null @@ -1,112 +0,0 @@ -'use strict'; - -let angular = require('angular'); - -module.exports = angular - .module('spinnaker.core.pageTitle.service', - [require('angular-ui-router').default] - ) - .factory('pageTitleService', function($rootScope, $stateParams) { - - let previousPageTitle = 'Spinnaker'; - - function handleRoutingCanceled() { - $rootScope.routing = false; - document.title = previousPageTitle; - } - - function handleRoutingStart() { - $rootScope.routing = true; - previousPageTitle = document.title; - document.title = 'Spinnaker: Loading...'; - } - - function handleRoutingError() { - $rootScope.routing = false; - document.title = 'Spinnaker: Error'; - } - - function handleRoutingSuccess(config) { - var parts = configurePageTitle(config); - var title = parts.main || 'Spinnaker'; - if (parts.section) { - title += ' · ' + parts.section; - } - if (parts.details) { - title += ' · ' + parts.details; - } - $rootScope.routing = false; - document.title = title; - } - - function resolveStateParams(config) { - if (!config) { - return null; - } - var result = config.title; - if (config.nameParam) { - result += ': ' + $stateParams[config.nameParam]; - } - if (config.accountParam || config.regionParam) { - result += ' ('; - if (config.accountParam && config.regionParam) { - result += $stateParams[config.accountParam] + ':' + $stateParams[config.regionParam]; - } else { - result += $stateParams[config.accountParam] || $stateParams[config.regionParam]; - } - result += ')'; - } - return result; - } - - function configureSection(sectionConfig) { - return resolveStateParams(sectionConfig); - } - - function configureDetails(detailsConfig) { - return resolveStateParams(detailsConfig); - } - - function configureMain(mainConfig) { - var main = null; - if (!mainConfig) { - return main; - } - if (mainConfig.field) { - main = $stateParams[mainConfig.field]; - } - if (mainConfig.label) { - main = mainConfig.label; - } - return main; - } - - function configurePageTitle(data = {}) { - return { - main: configureMain(data.pageTitleMain), - section: configureSection(data.pageTitleSection), - details: configureDetails(data.pageTitleDetails) - }; - } - - return { - handleRoutingStart: handleRoutingStart, - handleRoutingSuccess: handleRoutingSuccess, - handleRoutingError: handleRoutingError, - handleRoutingCanceled: handleRoutingCanceled, - }; - - }) - .run(function($rootScope, pageTitleService) { - $rootScope.$on('$stateChangeStart', function() { - pageTitleService.handleRoutingStart(); - }); - - $rootScope.$on('$stateChangeError', function() { - pageTitleService.handleRoutingError(); - }); - - $rootScope.$on('$stateChangeSuccess', function(event, toState) { - pageTitleService.handleRoutingSuccess(toState.data); - }); - }); diff --git a/app/scripts/modules/core/pageTitle/pageTitle.service.spec.js b/app/scripts/modules/core/pageTitle/pageTitle.service.spec.js index e72535f2ea7..66ddaffb32c 100644 --- a/app/scripts/modules/core/pageTitle/pageTitle.service.spec.js +++ b/app/scripts/modules/core/pageTitle/pageTitle.service.spec.js @@ -1,11 +1,10 @@ 'use strict'; +var pageTitleServiceModule = require('./pageTitle.service').CORE_PAGETITLE_SERVICE; describe('Service: pageTitleService', function() { beforeEach( - window.module( - require('./pageTitle.service') - ) + window.module(pageTitleServiceModule) ); beforeEach(window.inject(function (pageTitleService, $stateParams, $rootScope) { @@ -22,7 +21,7 @@ describe('Service: pageTitleService', function() { expect(document.title).toBe(''); this.pageTitleService.handleRoutingStart(); - expect(scope.routing).toBe(true); + expect(scope.routing).toBeTruthy(); expect(document.title).toBe('Spinnaker: Loading...'); }); }); @@ -32,11 +31,11 @@ describe('Service: pageTitleService', function() { var scope = this.$rootScope; this.pageTitleService.handleRoutingStart(); - expect(scope.routing).toBe(true); + expect(scope.routing).toBeTruthy(); expect(document.title).toBe('Spinnaker: Loading...'); - this.pageTitleService.handleRoutingError(); - expect(scope.routing).toBe(false); + this.pageTitleService.handleRoutingError({ type: 1 }); + expect(scope.routing).toBeFalsy(); expect(document.title).toBe('Spinnaker: Error'); }); @@ -45,7 +44,7 @@ describe('Service: pageTitleService', function() { describe('handleRoutingSuccess', function() { afterEach(function() { - expect(this.$rootScope.routing).toBe(false); + expect(this.$rootScope.routing).toBeFalsy(); }); it('falls back to "Spinnaker" when nothing configured', function() { diff --git a/app/scripts/modules/core/pageTitle/pageTitle.service.ts b/app/scripts/modules/core/pageTitle/pageTitle.service.ts new file mode 100644 index 00000000000..877e78b7a69 --- /dev/null +++ b/app/scripts/modules/core/pageTitle/pageTitle.service.ts @@ -0,0 +1,136 @@ +import { module, IScope } from 'angular'; +import { TransitionService, Rejection, RejectType, StateParams } from '@uirouter/core'; + +interface IMainConfig { + field: string; + label: string; +} + +interface ISectionConfig { + title: string; +} + +interface IDetailsConfig { + title: string; + nameParam?: string; + accountParam?: string; + regionParam?: string; +} + +interface IStatePageData { + pageTitleMain?: IMainConfig; + pageTitleSection?: ISectionConfig; + pageTitleDetails?: IDetailsConfig; +} + +interface IPageDataParts { + main: string; + section: string; + details: string; +} + +export class PageTitleService { + public static $inject = [ '$rootScope', '$stateParams', '$transitions' ]; + + private previousPageTitle = 'Spinnaker'; + + constructor(private $rootScope: IScope, private $stateParams: StateParams, $transitions: TransitionService) { + $rootScope.routing = 0; + + $transitions.onStart({}, transition => { + this.handleRoutingStart(); + const onSuccess = () => this.handleRoutingSuccess(transition.to().data); + const onReject = (err: Rejection) => this.handleRoutingError(err); + transition.promise.then(onSuccess, onReject); + }); + } + + public handleRoutingStart(): void { + this.$rootScope.routing++; + this.previousPageTitle = document.title; + document.title = 'Spinnaker: Loading...'; + } + + public handleRoutingError(rejection: Rejection): void { + this.$rootScope.routing--; + const cancelled = rejection.type === RejectType.ABORTED; + document.title = cancelled ? this.previousPageTitle : 'Spinnaker: Error'; + } + + public handleRoutingSuccess(config: IStatePageData): void { + const parts: IPageDataParts = this.configurePageTitle(config); + let title = parts.main || 'Spinnaker'; + if (parts.section) { + title += ' · ' + parts.section; + } + if (parts.details) { + title += ' · ' + parts.details; + } + this.$rootScope.routing = false; + document.title = title; + } + + public resolveStateParams(config: IDetailsConfig): string { + if (!config) { + return null; + } + + const { $stateParams } = this; + const { title, nameParam, accountParam, regionParam } = config; + + let result = title; + + if (nameParam) { + result += ': ' + $stateParams[nameParam]; + } + + if (accountParam || regionParam) { + result += ' ('; + if (accountParam && regionParam) { + result += $stateParams[accountParam] + ':' + $stateParams[regionParam]; + } else { + result += $stateParams[accountParam] || $stateParams[regionParam]; + } + result += ')'; + } + + return result; + } + + public configureSection(sectionConfig: ISectionConfig): string { + return this.resolveStateParams(sectionConfig); + } + + public configureDetails(detailsConfig: IDetailsConfig): string { + return this.resolveStateParams(detailsConfig); + } + + public configureMain(mainConfig: IMainConfig): string { + const { $stateParams } = this; + let main = null; + if (!mainConfig) { + return main; + } + if (mainConfig.field) { + main = $stateParams[mainConfig.field]; + } + if (mainConfig.label) { + main = mainConfig.label; + } + return main; + } + + public configurePageTitle(data: IStatePageData = {}): IPageDataParts { + return { + main: this.configureMain(data.pageTitleMain), + section: this.configureSection(data.pageTitleSection), + details: this.configureDetails(data.pageTitleDetails) + }; + } +} + +export const CORE_PAGETITLE_SERVICE = 'spinnaker.core.pageTitle.service'; + +module(CORE_PAGETITLE_SERVICE, [require('angular-ui-router').default]) + .service('pageTitleService', PageTitleService) + .run(['pageTitleService', (pts: PageTitleService) => pts]); diff --git a/app/scripts/modules/core/search/infrastructure/infrastructure.controller.js b/app/scripts/modules/core/search/infrastructure/infrastructure.controller.js index 8fb09074fb0..39976596aff 100644 --- a/app/scripts/modules/core/search/infrastructure/infrastructure.controller.js +++ b/app/scripts/modules/core/search/infrastructure/infrastructure.controller.js @@ -8,12 +8,13 @@ import {CLUSTER_FILTER_SERVICE} from 'core/cluster/filter/clusterFilter.service' import {CACHE_INITIALIZER_SERVICE} from 'core/cache/cacheInitializer.service'; import {OVERRIDE_REGISTRY} from 'core/overrideRegistry/override.registry'; import {RECENT_HISTORY_SERVICE} from 'core/history/recentHistory.service'; +import {CORE_PAGETITLE_SERVICE} from 'core/pageTitle/pageTitle.service'; module.exports = angular.module('spinnaker.search.infrastructure.controller', [ require('./infrastructureSearch.service.js'), RECENT_HISTORY_SERVICE, require('../searchResult/searchResult.directive.js'), - require('core/pageTitle/pageTitle.service.js'), + CORE_PAGETITLE_SERVICE, require('./project/infrastructureProject.directive.js'), require('../searchRank.filter.js'), CLUSTER_FILTER_SERVICE,