# HG changeset patch # User Andrew Azores # Date 1507917909 14400 # Node ID 2eb2ae0f3b3fc382cb9d47b00fa0c0d5ed188507 # Parent 63df0ca94b6b15c5cabbd4a4b90f6044a10a7c10 Transition project to Angular 4 Hybrid Reviewed-by: jkang Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-October/025266.html diff -r 63df0ca94b6b -r 2eb2ae0f3b3f karma.conf.js --- a/karma.conf.js Fri Oct 13 11:39:51 2017 -0400 +++ b/karma.conf.js Fri Oct 13 14:05:09 2017 -0400 @@ -25,11 +25,12 @@ * exception statement from your version. */ +var webpackConfig = require('./webpack.config'); module.exports = function (config) { config.set({ basePath: '', - frameworks: ['mocha', 'should-sinon', 'sinon', 'should'], + frameworks: ['mocha', 'should-sinon', 'sinon', 'should', 'karma-typescript'], files: [ 'src/app/components/auth/keycloak.stub.js', @@ -41,7 +42,7 @@ 'src/tests.webpack.js': ['webpack', 'sourcemap'] }, - reporters: ['mocha', 'beep', 'junit', 'coverage-istanbul'], + reporters: ['mocha', 'beep', 'junit', 'coverage-istanbul', 'karma-typescript'], junitReporter: { outputDir: 'test-reports' @@ -66,7 +67,11 @@ browsers: ['PhantomJS'], - webpack: require('./webpack.config'), + webpack: { + module: webpackConfig.module, + resolve: webpackConfig.resolve, + devtool: webpackConfig.devtool + }, webpackMiddleware: { noInfo: 'errors-only' diff -r 63df0ca94b6b -r 2eb2ae0f3b3f package.json --- a/package.json Fri Oct 13 11:39:51 2017 -0400 +++ b/package.json Fri Oct 13 14:05:09 2017 -0400 @@ -10,6 +10,15 @@ "author": "", "license": "", "devDependencies": { + "@angular/core": "^4.4.2", + "@angular/platform-browser": "^4.4.2", + "@angular/upgrade": "^4.4.2", + "@types/angular": "^1.6.32", + "@types/big.js": "^3.2.0", + "@types/core-js": "^0.9.43", + "@types/mocha": "^2.2.43", + "@types/should": "^11.2.0", + "@types/sinon": "^2.3.5", "@uirouter/angularjs": "^1.0.0", "angular-mocks": "1.5.*", "angular-patternfly": "^4.4.1", @@ -49,29 +58,38 @@ "karma-should-sinon": "^1.0.0", "karma-sinon": "^1.0.5", "karma-sourcemap-loader": "^0.3.7", + "karma-typescript": "^3.0.7", "karma-webpack": "^2.0.3", "keycloak-js": "^3.2.0", "mkdirp": "^0.5.1", "mocha": "^3.2.0", "mocha-junit-reporter": "^1.13.0", "mocha-multi": "^0.11.0", + "ngx-bootstrap": "^1.9.3", "node-sass": "^4.5.2", "null-loader": "^0.1.1", "nyc": "^10.2.0", "oclazyload": "^1.1.0", + "patternfly": "^3.27.4", + "patternfly-ng": "^0.10.1", "phantomjs-prebuilt": "^2.1.14", "protractor": "^5.1.2", "raw-loader": "^0.5.1", + "reflect-metadata": "^0.1.10", "rimraf": "^2.6.1", "sass-loader": "^6.0.5", "should": "^11.2.1", "sinon": "^2.1.0", "style-loader": "^0.16.1", + "ts-loader": "^2.3.7", + "tslint": "^5.7.0", + "typescript": "^2.5.2", "url": "^0.11.0", "url-join": "^2.0.1", "webpack": "^2.6.1", "webpack-dev-server": "^2.4.2", - "yaml-loader": "^0.5.0" + "yaml-loader": "^0.5.0", + "zone.js": "^0.8.17" }, "scripts": { "clean": "rimraf checkstyle coverage dist test-reports", @@ -80,13 +98,15 @@ "prelint": "mkdirp checkstyle", "lint-js": "eslint --ext '!.spec.js' -c .eslintrc.yaml src || npm run lint-js-checkstyle", "lint-js-checkstyle": "eslint -c .eslintrc.yaml -f checkstyle -o checkstyle/checkstyle-src.xml src", + "lint-ts": "tslint --exclude 'src/app/**/*.spec.ts' --project ./tsconfig.json --type-check 'src/app/**/*.ts' || npm run lint-ts-checkstyle", + "lint-ts-checkstyle": "tslint --force --exclude 'src/app/**/*.spec.ts' --project ./tsconfig.json --type-check 'src/app/**/*.ts' -o checkstyle/checkstyle-ts-src.xml -t checkstyle 'src/app/**/*.ts'", "lint-html": "htmlhint -c .htmlhintrc 'src/**/*.html' || npm run lint-html-checkstyle", "lint-html-checkstyle": "htmlhint -c .htmlhintrc -f checkstyle 'src/**/*.html' > checkstyle/checkstyle-html.xml", "lint-tests": "eslint -c .eslintrc.test.yaml src --ext .spec.js || npm run lint-test-checkstyle", "lint-tests-checkstyle": "eslint -c .eslintrc.test.yaml --ext .spec.js -f checkstyle -o checkstyle/checkstyle-test.xml src", "lint-itests": "eslint -c .eslintrc.test.yaml integration-test --ext .spec.js || npm run lint-itest-checkstyle", "lint-itests-checkstyle": "eslint -c .eslintrc.test.yaml --ext .spec.js -f checkstyle -o checkstyle/checkstyle-itest.xml src", - "lint": "npm run lint-js && npm run lint-html", + "lint": "npm run lint-ts && npm run lint-js && npm run lint-html", "prebuild": "npm run clean && npm run license-check && npm run lint", "build": "webpack --bail --progress --profile", "postbuild": "npm test", diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/ang-app.module.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/ang-app.module.js Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,105 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import 'angular-patternfly'; +import '@uirouter/angularjs'; +import angularTranslate from 'angular-translate'; +import 'angular-translate-interpolation-messageformat'; +import 'oclazyload'; +import 'bootstrap'; +import 'bootstrap-switch'; + +import 'angular-patternfly/node_modules/patternfly/node_modules/jquery/dist/jquery.js'; +import 'angular-patternfly/node_modules/patternfly/node_modules/datatables.net/js/jquery.dataTables.js'; +import 'angular-patternfly/node_modules/patternfly/node_modules/datatables.net-select/js/dataTables.select.js'; +import 'angularjs-datatables/dist/angular-datatables.min.js'; +import 'angularjs-datatables/dist/plugins/select/angular-datatables.select.min.js'; + +import {default as authModule, config as authModSetup} from 'components/auth/auth.module.js'; + +require.ensure([], () => { + require('angular-patternfly/node_modules/datatables.net-dt/css/jquery.dataTables.css'); + require('angular-patternfly/node_modules/patternfly/dist/css/patternfly.css'); + require('angular-patternfly/node_modules/patternfly/dist/css/patternfly-additions.css'); + require('bootstrap-switch/dist/css/bootstrap3/bootstrap-switch.css'); + require('scss/app.scss'); +}); + +const angApp = 'appModule'; +export default angApp; + +/* istanbul ignore next */ +function initializeApplication () { + require('shared/services/services.module.js').init(); + require('shared/config/config.module.js').init(); + let authInterceptorFactory = require('./auth-interceptor.factory.js').default; + return angular + .module(angApp, [ + 'ui.router', + 'ui.bootstrap', + 'patternfly', + 'patternfly.navigation', + 'patternfly.table', + angularTranslate, + authModule, + authInterceptorFactory, + // non-core modules + require('./app.routing.js').default, + require('./app-root.component.js').default + ]) + .config($httpProvider => { + 'ngInject'; + $httpProvider.interceptors.push(authInterceptorFactory); + }) + .config($translateProvider => { + 'ngInject'; + $translateProvider + .useSanitizeValueStrategy('escapeParameters') + .addInterpolation('$translateMessageFormatInterpolation') + .registerAvailableLanguageKeys(['en'], { + 'en_*': 'en' + }) + .fallbackLanguage('en') + .determinePreferredLanguage(); + + let req = require.context('./', true, /\/([a-z]{2})\.locale\.yaml$/); + req.keys().map(key => { + let lang = /\/([a-z]{2})\.locale\.yaml$/.exec(key)[1]; + let translations = req(key); + $translateProvider.translations(lang, translations); + }); + }) + .name; +} + +/* istanbul ignore next */ +export function doInit () { + return new Promise((resolve, reject) => { + let appModule = initializeApplication(); + authModSetup(process.env.NODE_ENV, () => resolve()); + }); +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/app-root.component.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/app-root.component.js Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,36 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import controller from './app-root.controller.js'; + +export default angular + .module('appRoot.component', [controller]) + .component('appRoot', { + controller: 'AppRootController', + template: require('./app-root.html') + }) + .name; diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/app-root.controller.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/app-root.controller.js Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,84 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import authModule from 'components/auth/auth.module.js'; + +class AppRootController { + constructor ($scope, environment, authService, $translate) { + 'ngInject'; + this.env = environment; + this._authService = authService; + this._translate = $translate; + + $scope.$on('userLoginChanged', () => this._updateUsernameLabel()); + } + + $onInit () { + angular.element(document.querySelector('#logoutButton')).removeAttr('hidden'); + if (this.env !== 'production') { + angular.element(document.querySelector('#envHeader')).removeAttr('hidden'); + } + + this._updateUsernameLabel(); + + this._translate([ + 'navbar.states.JVM_LISTING', + 'navbar.states.MULTICHARTS' + ]).then(translations => { + this.navigationItems = [ + { + title: translations['navbar.states.JVM_LISTING'], + iconClass: 'fa pficon-domain', + uiSref: 'jvmList' + }, + { + title: translations['navbar.states.MULTICHARTS'], + iconClass: 'fa pficon-trend-up', + uiSref: 'multichart' + } + ]; + }); + } + + get loginStatus () { + return this._authService.status(); + } + + logout () { + return this._authService.logout(); + } + + _updateUsernameLabel () { + this.username = this._authService.username; + } + +} + +export default angular + .module('appRoot.controller', [authModule]) + .controller('AppRootController', AppRootController) + .name; diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/app-root.controller.spec.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/app-root.controller.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,170 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import { default as authModule, config } from './components/auth/auth.module.js'; +import controllerModule from './app-root.controller.js'; + +describe('AppRootController', () => { + + beforeEach(angular.mock.module($provide => { + 'ngInject'; + $provide.value('$transitions', { onBefore: angular.noop }); + + let localStorage = { + getItem: sinon.stub(), + hasItem: sinon.stub(), + removeItem: sinon.spy(), + setItem: sinon.spy(), + clear: sinon.spy() + }; + $provide.value('localStorage', localStorage); + })); + + beforeEach(() => { + angular.mock.module(authModule); + config(); + angular.mock.module(controllerModule); + }); + + ['testing', 'development', 'production'].forEach(env => { + describe(env, () => { + let ctrl, scope, authService, translate; + beforeEach(inject($controller => { + 'ngInject'; + + scope = { $on: sinon.spy() }; + authService = { + status: sinon.stub().returns(true), + login: sinon.spy(), + logout: sinon.spy() + }; + translate = sinon.stub().returns({ + then: sinon.stub().yields( + { + 'navbar.states.JVM_LISTING': 'JVM Listing', + 'navbar.states.MULTICHARTS': 'Multicharts' + } + ) + }); + + ctrl = $controller('AppRootController', { + environment: env, + $scope: scope, + authService: authService, + $translate: translate + }); + ctrl.$onInit(); + })); + + it('should set loginStatus', () => { + ctrl.loginStatus.should.be.True(); + authService.status.should.be.calledOnce(); + }); + }); + }); + + describe('logout()', () => { + let ctrl, scope, authService, translate; + beforeEach(inject($controller => { + 'ngInject'; + + scope = { $on: sinon.spy() }; + authService = { + status: sinon.stub().returns(true), + login: sinon.spy(), + logout: sinon.spy() + }; + translate = sinon.stub().returns({ + then: sinon.stub().yields( + { + 'navbar.states.JVM_LISTING': 'JVM Listing', + 'navbar.states.MULTICHARTS': 'Multicharts' + } + ) + }); + + ctrl = $controller('AppRootController', { + environment: 'testing', + $scope: scope, + authService: authService, + $translate: translate + }); + ctrl.$onInit(); + })); + + it('should delegate to AuthService', () => { + authService.logout.should.not.be.called(); + ctrl.logout(); + authService.logout.should.be.calledOnce(); + }); + }); + + describe('username', () => { + let rootScope, scope, ctrl, authService, translate; + beforeEach(inject(($controller, $rootScope) => { + 'ngInject'; + + rootScope = $rootScope; + scope = $rootScope.$new(); + authService = { + status: sinon.stub().returns(true), + login: sinon.spy(), + logout: sinon.spy(), + username: 'fake-username' + }; + translate = sinon.stub().returns({ + then: sinon.stub().yields( + { + 'navbar.states.JVM_LISTING': 'JVM Listing', + 'navbar.states.MULTICHARTS': 'Multicharts' + } + ) + }); + + ctrl = $controller('AppRootController', { + $scope: scope, + environment: 'testing', + authService: authService, + $translate: translate + }); + ctrl.$onInit(); + })); + + it('should be set on init', () => { + ctrl.should.have.ownProperty('username'); + ctrl.username.should.equal(authService.username); + }); + + it('should be set on userLoginChanged according to authService username', () => { + authService.username = 'new-username'; + rootScope.$broadcast('userLoginChanged'); + ctrl.should.have.ownProperty('username'); + ctrl.username.should.equal(authService.username); + }); + }); + +}); diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/app-root.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/app-root.html Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,97 @@ +
+ +
+ + + +
+
+
+
+
+
+ +
+ +
+
+ + + + + + +
+
+
+
+
+
+
+
+ +
+ diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/app.controller.js --- a/src/app/app.controller.js Fri Oct 13 11:39:51 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/** - * Copyright 2012-2017 Red Hat, Inc. - * - * Thermostat is distributed under the GNU General Public License, - * version 2 or any later version (with a special exception described - * below, commonly known as the "Classpath Exception"). - * - * A copy of GNU General Public License (GPL) is included in this - * distribution, in the file COPYING. - * - * Linking Thermostat code with other modules is making a combined work - * based on Thermostat. Thus, the terms and conditions of the GPL - * cover the whole combination. - * - * As a special exception, the copyright holders of Thermostat give you - * permission to link this code with independent modules to produce an - * executable, regardless of the license terms of these independent - * modules, and to copy and distribute the resulting executable under - * terms of your choice, provided that you also meet, for each linked - * independent module, the terms and conditions of the license of that - * module. An independent module is a module which is not derived from - * or based on Thermostat code. If you modify Thermostat, you may - * extend this exception to your version of the software, but you are - * not obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ - -import authModule from 'components/auth/auth.module.js'; - -class AppController { - constructor ($scope, environment, authService, $translate) { - 'ngInject'; - this.env = environment; - this._authService = authService; - this._translate = $translate; - - $scope.$on('userLoginChanged', () => this._updateUsernameLabel()); - } - - $onInit () { - angular.element('logoutButton').removeAttr('hidden'); - if (this.env !== 'production') { - angular.element('envHeader').removeAttr('hidden'); - } - - this._updateUsernameLabel(); - - this._translate([ - 'navbar.states.JVM_LISTING', - 'navbar.states.MULTICHARTS' - ]).then(translations => { - this.navigationItems = [ - { - title: translations['navbar.states.JVM_LISTING'], - iconClass: 'fa pficon-domain', - uiSref: 'jvmList' - }, - { - title: translations['navbar.states.MULTICHARTS'], - iconClass: 'fa pficon-trend-up', - uiSref: 'multichart' - } - ]; - }); - } - - get loginStatus () { - return this._authService.status(); - } - - logout () { - return this._authService.logout(); - } - - _updateUsernameLabel () { - this.username = this._authService.username; - } - -} - -let name = 'AppController'; -export default angular - .module(name, [authModule]) - .controller(name, AppController) - .name; diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/app.controller.spec.js --- a/src/app/app.controller.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,163 +0,0 @@ -/** - * Copyright 2012-2017 Red Hat, Inc. - * - * Thermostat is distributed under the GNU General Public License, - * version 2 or any later version (with a special exception described - * below, commonly known as the "Classpath Exception"). - * - * A copy of GNU General Public License (GPL) is included in this - * distribution, in the file COPYING. - * - * Linking Thermostat code with other modules is making a combined work - * based on Thermostat. Thus, the terms and conditions of the GPL - * cover the whole combination. - * - * As a special exception, the copyright holders of Thermostat give you - * permission to link this code with independent modules to produce an - * executable, regardless of the license terms of these independent - * modules, and to copy and distribute the resulting executable under - * terms of your choice, provided that you also meet, for each linked - * independent module, the terms and conditions of the license of that - * module. An independent module is a module which is not derived from - * or based on Thermostat code. If you modify Thermostat, you may - * extend this exception to your version of the software, but you are - * not obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ - -describe('AppController', () => { - - beforeEach(angular.mock.module($provide => { - 'ngInject'; - $provide.value('$transitions', { onBefore: angular.noop }); - - let localStorage = { - getItem: sinon.stub(), - hasItem: sinon.stub(), - removeItem: sinon.spy(), - setItem: sinon.spy(), - clear: sinon.spy() - }; - $provide.value('localStorage', localStorage); - })); - - beforeEach(angular.mock.module('AppController')); - - ['testing', 'development', 'production'].forEach(env => { - describe(env, () => { - let ctrl, scope, authService, translate; - beforeEach(inject($controller => { - 'ngInject'; - - scope = { $on: sinon.spy() }; - authService = { - status: sinon.stub().returns(true), - login: sinon.spy(), - logout: sinon.spy() - }; - translate = sinon.stub().returns({ - then: sinon.stub().yields( - { - 'navbar.states.JVM_LISTING': 'JVM Listing', - 'navbar.states.MULTICHARTS': 'Multicharts' - } - ) - }); - - ctrl = $controller('AppController', { - environment: env, - $scope: scope, - authService: authService, - $translate: translate - }); - ctrl.$onInit(); - })); - - it('should set loginStatus', () => { - ctrl.loginStatus.should.be.True(); - authService.status.should.be.calledOnce(); - }); - }); - }); - - describe('logout()', () => { - let ctrl, scope, authService, translate; - beforeEach(inject($controller => { - 'ngInject'; - - scope = { $on: sinon.spy() }; - authService = { - status: sinon.stub().returns(true), - login: sinon.spy(), - logout: sinon.spy() - }; - translate = sinon.stub().returns({ - then: sinon.stub().yields( - { - 'navbar.states.JVM_LISTING': 'JVM Listing', - 'navbar.states.MULTICHARTS': 'Multicharts' - } - ) - }); - - ctrl = $controller('AppController', { - environment: 'testing', - $scope: scope, - authService: authService, - $translate: translate - }); - ctrl.$onInit(); - })); - - it('should delegate to AuthService', () => { - authService.logout.should.not.be.called(); - ctrl.logout(); - authService.logout.should.be.calledOnce(); - }); - }); - - describe('username', () => { - let rootScope, scope, ctrl, authService, translate; - beforeEach(inject(($controller, $rootScope) => { - 'ngInject'; - - rootScope = $rootScope; - scope = $rootScope.$new(); - authService = { - status: sinon.stub().returns(true), - login: sinon.spy(), - logout: sinon.spy(), - username: 'fake-username' - }; - translate = sinon.stub().returns({ - then: sinon.stub().yields( - { - 'navbar.states.JVM_LISTING': 'JVM Listing', - 'navbar.states.MULTICHARTS': 'Multicharts' - } - ) - }); - - ctrl = $controller('AppController', { - $scope: scope, - environment: 'testing', - authService: authService, - $translate: translate - }); - ctrl.$onInit(); - })); - - it('should be set on init', () => { - ctrl.should.have.ownProperty('username'); - ctrl.username.should.equal(authService.username); - }); - - it('should be set on userLoginChanged according to authService username', () => { - authService.username = 'new-username'; - rootScope.$broadcast('userLoginChanged'); - ctrl.should.have.ownProperty('username'); - ctrl.username.should.equal(authService.username); - }); - }); - -}); diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/app.module.js --- a/src/app/app.module.js Fri Oct 13 11:39:51 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/** - * Copyright 2012-2017 Red Hat, Inc. - * - * Thermostat is distributed under the GNU General Public License, - * version 2 or any later version (with a special exception described - * below, commonly known as the "Classpath Exception"). - * - * A copy of GNU General Public License (GPL) is included in this - * distribution, in the file COPYING. - * - * Linking Thermostat code with other modules is making a combined work - * based on Thermostat. Thus, the terms and conditions of the GPL - * cover the whole combination. - * - * As a special exception, the copyright holders of Thermostat give you - * permission to link this code with independent modules to produce an - * executable, regardless of the license terms of these independent - * modules, and to copy and distribute the resulting executable under - * terms of your choice, provided that you also meet, for each linked - * independent module, the terms and conditions of the license of that - * module. An independent module is a module which is not derived from - * or based on Thermostat code. If you modify Thermostat, you may - * extend this exception to your version of the software, but you are - * not obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ - -import 'angular-patternfly'; -import '@uirouter/angularjs'; -import angularTranslate from 'angular-translate'; -import 'angular-translate-interpolation-messageformat'; -import 'oclazyload'; -import 'bootstrap'; -import 'bootstrap-switch'; - -import 'angular-patternfly/node_modules/patternfly/node_modules/jquery/dist/jquery.js'; -import 'angular-patternfly/node_modules/patternfly/node_modules/datatables.net/js/jquery.dataTables.js'; -import 'angular-patternfly/node_modules/patternfly/node_modules/datatables.net-select/js/dataTables.select.js'; -import 'angularjs-datatables/dist/angular-datatables.min.js'; -import 'angularjs-datatables/dist/plugins/select/angular-datatables.select.min.js'; - -import {default as authModule, config as authModBootstrap} from 'components/auth/auth.module.js'; -import authInterceptorFactory from './auth-interceptor.factory.js'; - -require.ensure([], () => { - require('angular-patternfly/node_modules/datatables.net-dt/css/jquery.dataTables.css'); - require('angular-patternfly/node_modules/patternfly/dist/css/patternfly.css'); - require('angular-patternfly/node_modules/patternfly/dist/css/patternfly-additions.css'); - require('bootstrap-switch/dist/css/bootstrap3/bootstrap-switch.css'); - require('scss/app.scss'); -}); - -function initializeApplication () { - return angular - .module('appModule', [ - 'ui.router', - 'ui.bootstrap', - 'patternfly', - 'patternfly.navigation', - 'patternfly.table', - angularTranslate, - authModule, - // non-core modules - require('./app.routing.js').default, - require('./app.controller.js').default, - authInterceptorFactory - ]) - .config($httpProvider => { - 'ngInject'; - $httpProvider.interceptors.push(authInterceptorFactory); - }) - .config($translateProvider => { - 'ngInject'; - $translateProvider - .useSanitizeValueStrategy('escapeParameters') - .addInterpolation('$translateMessageFormatInterpolation') - .registerAvailableLanguageKeys(['en'], { - 'en_*': 'en' - }) - .fallbackLanguage('en') - .determinePreferredLanguage(); - - let req = require.context('./', true, /\/([a-z]{2})\.locale\.yaml$/); - req.keys().map(key => { - let lang = /\/([a-z]{2})\.locale\.yaml$/.exec(key)[1]; - let translations = req(key); - $translateProvider.translations(lang, translations); - }); - }) - .name; -} - -/* istanbul ignore next */ -if (window.tmsGatewayUrl) { - let appModule = initializeApplication(); - authModBootstrap(process.env.NODE_ENV, () => angular.element(() => angular.bootstrap(document, [appModule]))); -} else { - $.get('/gatewayurl') - .done(res => { - window.tmsGatewayUrl = res.gatewayUrl; - }) - .fail(() => { - let url = require('url'); - let parsed = url.parse(window.location.href); - let gateway = { - protocol: parsed.protocol, - host: parsed.host - }; - window.tmsGatewayUrl = url.format(gateway); - }) - .always(() => { - let appModule = initializeApplication(); - authModBootstrap(process.env.NODE_ENV, () => angular.element(() => angular.bootstrap(document, [appModule]))); - }); -} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/app.module.spec.js --- a/src/app/app.module.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/** - * Copyright 2012-2017 Red Hat, Inc. - * - * Thermostat is distributed under the GNU General Public License, - * version 2 or any later version (with a special exception described - * below, commonly known as the "Classpath Exception"). - * - * A copy of GNU General Public License (GPL) is included in this - * distribution, in the file COPYING. - * - * Linking Thermostat code with other modules is making a combined work - * based on Thermostat. Thus, the terms and conditions of the GPL - * cover the whole combination. - * - * As a special exception, the copyright holders of Thermostat give you - * permission to link this code with independent modules to produce an - * executable, regardless of the license terms of these independent - * modules, and to copy and distribute the resulting executable under - * terms of your choice, provided that you also meet, for each linked - * independent module, the terms and conditions of the license of that - * module. An independent module is a module which is not derived from - * or based on Thermostat code. If you modify Thermostat, you may - * extend this exception to your version of the software, but you are - * not obligated to do so. If you do not wish to do so, delete this - * exception statement from your version. - */ - -import {config} from './components/auth/auth.module.js'; - -describe('AppModule', () => { - - beforeEach(angular.mock.module('appModule')); - - let state; - beforeEach(angular.mock.module($provide => { - 'ngInject'; - - state = { - go: sinon.spy(), - href: sinon.spy(), - current: { - name: 'fooState' - }, - params: {} - }; - - $provide.value('$state', state); - })); - - // this is actually provided by the auth.module pseudo-module - see auth.module.spec.js - describe('auth bootstrap', () => { - - let svc; - beforeEach(() => { - let mockKeycloakProvider = require('./components/auth/keycloak.stub.js'); - config('production', () => {}, mockKeycloakProvider()); - - inject(authService => { - 'ngInject'; - svc = authService; - }); - }); - - it('should provide an authService', () => { - should.exist(svc); - - svc.should.have.property('status'); - svc.should.have.property('login'); - svc.should.have.property('logout'); - svc.should.have.property('refresh'); - - svc.status.should.be.a.Function(); - svc.login.should.be.a.Function(); - svc.logout.should.be.a.Function(); - svc.refresh.should.be.a.Function(); - }); - }); - -}); diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/app.module.ts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/app.module.ts Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,68 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import * as angular from "angular"; +import { default as angApp, doInit } from "./ang-app.module.js"; + +import { + NgModule, + Inject, + forwardRef +} from "@angular/core"; + +import { BrowserModule } from "@angular/platform-browser"; +import { HttpClientModule } from "@angular/common/http"; +import { UpgradeModule } from "@angular/upgrade/static"; +import { UpgradeAdapter } from "@angular/upgrade"; + +import { ServicesModule } from "./shared/services/services.module"; +import { FiltersModule } from "./shared/filters/filters.module"; + +const upgradeAdapter = new UpgradeAdapter(forwardRef(() => AppModule)); +@NgModule({ + declarations: [], + imports: [ + // Angular core modules + BrowserModule, + HttpClientModule, + UpgradeModule, + + ServicesModule, + FiltersModule, + ] +}) +export class AppModule { + + constructor(@Inject(UpgradeModule) private upgradeModule: UpgradeModule) {} + + public ngDoBootstrap() { + doInit().then(() => { + this.upgradeModule.bootstrap(document.body, [angApp], { strictDi: true }); + }); + } + +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/app.routing.js --- a/src/app/app.routing.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/app.routing.js Fri Oct 13 14:05:09 2017 -0400 @@ -79,4 +79,4 @@ appRouter.run(transitionHook); export default appRouter.name; -export { errorRouter, errorRouting, transitionHook }; +export { defaultState, errorRouter, errorRouting, transitionHook }; diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/app.routing.spec.js --- a/src/app/app.routing.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/app.routing.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -144,6 +144,14 @@ fn({ name: 'login' }).should.be.false(); }); + it('should match non-auth\'d transitions', () => { + authSvc.status = () => false; + transitions.onBefore.args[1][0].should.have.ownProperty('to'); + let fn = transitions.onBefore.args[1][0].to; + fn.should.be.a.Function(); + fn({ name: 'foo' }).should.be.true(); + }); + it('should provide a transition function', () => { transitions.onBefore.args[1][1].should.be.a.Function(); }); @@ -177,4 +185,13 @@ }); }); + describe('defaultState', () => { + it('should add a \'default\' state which redirects to jvmList', () => { + stateProvider.state.should.be.calledOnce(); + module.defaultState(stateProvider); + stateProvider.state.should.be.calledTwice(); + stateProvider.state.secondCall.should.be.calledWithMatch('default', { redirectTo: 'jvmList' }); + }); + }); + }); diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/auth-interceptor.factory.js --- a/src/app/auth-interceptor.factory.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/auth-interceptor.factory.js Fri Oct 13 14:05:09 2017 -0400 @@ -26,11 +26,15 @@ */ import authModule from 'components/auth/auth.module.js'; +import servicesModule from 'shared/services/services.module.js'; let name = 'authInterceptorFactory'; export default angular - .module(name, [authModule]) + .module(name, [ + authModule, + servicesModule + ]) .factory(name, ($q, authService) => { 'ngInject'; return { diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/auth-interceptor.factory.spec.js --- a/src/app/auth-interceptor.factory.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/auth-interceptor.factory.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -25,10 +25,13 @@ * exception statement from your version. */ +import factoryModule from './auth-interceptor.factory.js'; + describe('authInterceptorFactory', () => { let authSvc, refreshPromise, interceptor; beforeEach(() => { + angular.mock.module(factoryModule); angular.mock.module('authModule', $provide => { 'ngInject'; diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/components/about/about.controller.spec.js --- a/src/app/components/about/about.controller.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/components/about/about.controller.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -26,11 +26,14 @@ */ import controllerModule from './about.controller.js'; +import { default as servicesModule, init as initServices } from 'shared/services/services.module.js'; describe('AboutController', () => { let ctrl, authSvc; beforeEach(() => { + angular.mock.module(servicesModule); + initServices(); angular.mock.module(controllerModule); angular.mock.inject($controller => { 'ngInject'; diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/components/jvm-info/jvm-gc/jvm-gc.controller.spec.js --- a/src/app/components/jvm-info/jvm-gc/jvm-gc.controller.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/components/jvm-info/jvm-gc/jvm-gc.controller.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -25,49 +25,56 @@ * exception statement from your version. */ -describe('JvmGcController', () => { +import controllerModule from './jvm-gc.controller.js'; +import filtersModule from 'shared/filters/filters.module.js'; +import { default as servicesModule, init as initServices } from 'shared/services/services.module.js'; - beforeEach(angular.mock.module('app.filters')); - beforeEach(angular.mock.module('jvmGc.controller')); +describe('JvmGcController', () => { let interval, dateFilterStub, dateFormatSpy, svc, promise, ctrl, translate, sanitizeService; - beforeEach(inject(($controller) => { - 'ngInject'; + beforeEach(() => { + angular.mock.module(filtersModule); + angular.mock.module(servicesModule); + initServices(); + angular.mock.module(controllerModule); + angular.mock.inject(($controller) => { + 'ngInject'; - dateFilterStub = sinon.stub().returns('mockDate'); - dateFormatSpy = { - time: { - medium: sinon.spy() - } - }; + dateFilterStub = sinon.stub().returns('mockDate'); + dateFormatSpy = { + time: { + medium: sinon.spy() + } + }; - interval = sinon.stub().returns('interval-sentinel'); - interval.cancel = sinon.spy(); + interval = sinon.stub().returns('interval-sentinel'); + interval.cancel = sinon.spy(); - promise = { then: sinon.spy() }; - svc = { getJvmGcData: sinon.stub().returns(promise) }; - - sanitizeService = { sanitize: sinon.spy() }; + promise = { then: sinon.spy() }; + svc = { getJvmGcData: sinon.stub().returns(promise) }; - translate = sinon.stub().returns({ - then: sinon.stub().yields({ - 'jvmGc.chart.UNITS': 'microseconds', - 'jvmGc.chart.X_AXIS_LABEL': 'timestamp', - 'jvmGc.chart.Y_AXIS_LABEL': 'elapsed' - }) - }); + sanitizeService = { sanitize: sinon.spy() }; + + translate = sinon.stub().returns({ + then: sinon.stub().yields({ + 'jvmGc.chart.UNITS': 'microseconds', + 'jvmGc.chart.X_AXIS_LABEL': 'timestamp', + 'jvmGc.chart.Y_AXIS_LABEL': 'elapsed' + }) + }); - ctrl = $controller('JvmGcController', { - $stateParams: { jvmId: 'foo-jvmId' }, - $interval: interval, - dateFilter: dateFilterStub, - DATE_FORMAT: dateFormatSpy, - jvmGcService: svc, - sanitizeService: sanitizeService, - $translate: translate + ctrl = $controller('JvmGcController', { + $stateParams: { jvmId: 'foo-jvmId' }, + $interval: interval, + dateFilter: dateFilterStub, + DATE_FORMAT: dateFormatSpy, + jvmGcService: svc, + sanitizeService: sanitizeService, + $translate: translate + }); + ctrl.$onInit(); }); - ctrl.$onInit(); - })); + }); it('should exist', () => { should.exist(ctrl); diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/components/jvm-info/jvm-info.controller.spec.js --- a/src/app/components/jvm-info/jvm-info.controller.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/components/jvm-info/jvm-info.controller.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -25,12 +25,14 @@ * exception statement from your version. */ +import controllerModule from './jvm-info.controller.js'; + describe('JvmInfoController', () => { - beforeEach(angular.mock.module('jvmInfo.controller')); + beforeEach(angular.mock.module(controllerModule)); let state, jvmInfoService, killVmService, ctrl, infoPromise, killPromise, systemInfoService, systemInfoPromise, translate; - beforeEach(inject($controller => { + beforeEach(angular.mock.inject($controller => { 'ngInject'; state = { go: sinon.spy() }; diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/components/jvm-info/jvm-memory/jvm-memory.controller.spec.js --- a/src/app/components/jvm-info/jvm-memory/jvm-memory.controller.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/components/jvm-info/jvm-memory/jvm-memory.controller.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -25,46 +25,54 @@ * exception statement from your version. */ -describe('JvmMemory controller', () => { +import controllerModule from './jvm-memory.controller.js'; +import filtersModule from 'shared/filters/filters.module.js'; +import { default as servicesModule, init as initServices } from 'shared/services/services.module.js'; - beforeEach(angular.mock.module('jvmMemory.controller')); +describe('JvmMemory controller', () => { let interval, memSvc, scaleSvc, promise, ctrl, sanitizeSvc; - beforeEach(inject($controller => { - 'ngInject'; + beforeEach(() => { + angular.mock.module(filtersModule); + angular.mock.module(servicesModule); + initServices(); + angular.mock.module(controllerModule); + angular.mock.inject($controller => { + 'ngInject'; - interval = sinon.stub().returns('interval-sentinel'); - interval.cancel = sinon.spy(); + interval = sinon.stub().returns('interval-sentinel'); + interval.cancel = sinon.spy(); - promise = { - then: sinon.spy() - }; - memSvc = { - getJvmMemory: sinon.stub().returns(promise) - }; - scaleSvc = { - format: sinon.stub().returns({ - scale: 1024 * 1024, - unit: 'MiB' - }) - }; + promise = { + then: sinon.spy() + }; + memSvc = { + getJvmMemory: sinon.stub().returns(promise) + }; + scaleSvc = { + format: sinon.stub().returns({ + scale: 1024 * 1024, + unit: 'MiB' + }) + }; - sanitizeSvc = { - sanitize: sinon.stub().returns('sanitized-mock') - }; + sanitizeSvc = { + sanitize: sinon.stub().returns('sanitized-mock') + }; - ctrl = $controller('JvmMemoryController', { - $stateParams: { jvmId: 'foo-jvmId' }, - $interval: interval, - jvmMemoryService: memSvc, - scaleBytesService: scaleSvc, - sanitizeService: sanitizeSvc + ctrl = $controller('JvmMemoryController', { + $stateParams: { jvmId: 'foo-jvmId' }, + $interval: interval, + jvmMemoryService: memSvc, + scaleBytesService: scaleSvc, + sanitizeService: sanitizeSvc + }); + ctrl.$onInit(); + + sinon.spy(ctrl, '_update'); + sinon.spy(ctrl, '_stop'); }); - ctrl.$onInit(); - - sinon.spy(ctrl, '_update'); - sinon.spy(ctrl, '_stop'); - })); + }); afterEach(() => { ctrl._update.restore(); diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/components/jvm-info/kill-vm.service.spec.js --- a/src/app/components/jvm-info/kill-vm.service.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/components/jvm-info/kill-vm.service.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -25,6 +25,7 @@ * exception statement from your version. */ +import serviceModule from './kill-vm.service.js'; import servicesModule from 'shared/services/services.module.js'; describe('KillVmService', () => { @@ -36,6 +37,7 @@ 'ngInject'; $provide.value('commandChannelService', commandChannel); }); + angular.mock.module(serviceModule); angular.mock.inject((killVmService, $rootScope, $q) => { 'ngInject'; scope = $rootScope; diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/components/jvm-list/jvm-list.controller.spec.js --- a/src/app/components/jvm-list/jvm-list.controller.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/components/jvm-list/jvm-list.controller.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -25,9 +25,11 @@ * exception statement from your version. */ +import controllerModule from './jvm-list.controller.js'; + describe('JvmListController', () => { - beforeEach(angular.mock.module('jvmList.controller')); + beforeEach(angular.mock.module(controllerModule)); let rootScope, controller, jvmListSvc, systemInfoSvc, promise, location, state, timeout, translate; @@ -76,7 +78,7 @@ }; }; - beforeEach(inject(($q, $rootScope, $controller) => { + beforeEach(angular.mock.inject(($q, $rootScope, $controller) => { 'ngInject'; rootScope = $rootScope; sinon.stub(angular, 'element').withArgs('#aliveOnlyState').returns({ diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/index.html --- a/src/app/index.html Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/index.html Fri Oct 13 14:05:09 2017 -0400 @@ -11,102 +11,7 @@ -
- -
- - - -
-
-
-
-
-
- -
- -
-
- - - - - - -
-
-
-
-
-
-
-
- -
+ diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/config/config.module.js --- a/src/app/shared/config/config.module.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/config/config.module.js Fri Oct 13 14:05:09 2017 -0400 @@ -27,7 +27,7 @@ import * as url from 'url'; -export function cmdChanUrl (gatewayUrl) { +export function cmdChanUrl (gatewayUrl = window.tmsGatewayUrl) { if (!gatewayUrl) { throw new Error('gatewayUrl could not be determined'); } @@ -43,10 +43,15 @@ return url.format(parsed); }; -export default angular - .module('configModule', []) - .constant('environment', process.env.NODE_ENV) - .constant('debug', process.env.DEBUG) - .value('gatewayUrl', window.tmsGatewayUrl) - .value('commandChannelUrl', cmdChanUrl(window.tmsGatewayUrl)) - .name; +let modName = 'configModule'; +let mod = angular.module(modName, []); +export default modName; + +/* istanbul ignore next */ +export function init () { + mod + .constant('environment', process.env.NODE_ENV) + .constant('debug', process.env.DEBUG) + .value('gatewayUrl', window.tmsGatewayUrl) + .factory('commandChannelUrl', cmdChanUrl); +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/config/config.module.spec.js --- a/src/app/shared/config/config.module.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/config/config.module.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -27,96 +27,11 @@ describe('ConfigModule', () => { - beforeEach(() => { - angular.mock.module('configModule'); - }); - - describe('environment', () => { - let _environment; - beforeEach(inject(environment => { - 'ngInject'; - - _environment = environment; - })); - - it('should be exported', () => { - should.exist(_environment); - }); - - it('should be readonly', done => { - try { - _environment.foo = 'bar'; - } catch (e) { - e.message.should.equal('Attempted to assign to readonly property.'); - done(); - } - }); - }); - - describe('debug', () => { - let _debug; - beforeEach(inject(debug => { - 'ngInject'; - - _debug = debug; - })); - - it('should be exported', () => { - should.exist(_debug); - }); - - it('should be readonly', done => { - try { - _debug.foo = 'bar'; - } catch (e) { - e.message.should.equal('Attempted to assign to readonly property.'); - done(); - } - }); - }); - - describe('gatewayUrl', () => { - let _gatewayUrl; - beforeEach(inject(gatewayUrl => { - 'ngInject'; - - _gatewayUrl = gatewayUrl; - })); - - it('should be exported', () => { - should.exist(_gatewayUrl); - }); - - it('should be readonly', done => { - try { - _gatewayUrl.foo = 'bar'; - } catch (e) { - e.message.should.equal('Attempted to assign to readonly property.'); - done(); - } - }); - }); - describe('commandChannelUrl', () => { let fn = require('./config.module.js').cmdChanUrl; - let _commandChannelUrl; - beforeEach(inject(commandChannelUrl => { - 'ngInject'; - _commandChannelUrl = commandChannelUrl; - })); - - it('should be exported', () => { - should.exist(_commandChannelUrl); - }); - - it('should be readonly', done => { - try { - _commandChannelUrl.foo = 'bar'; - } catch (e) { - e.message.should.equal('Attempted to assign to readonly property.'); - done(); - } + it('should use window.tmsGatewayUrl if none specified', () => { + fn().should.equal('ws://localhost:8888/'); }); it('should yield ws:// URL when gateway URL is http://', () => { @@ -127,9 +42,9 @@ fn('https://example.com:8888/').should.equal('wss://example.com:8888/'); }); - it('should throw error when gateway URL is undefined', done => { + it('should throw error when gateway URL is falsy', done => { try { - fn(undefined); + fn(null); } catch (e) { e.message.should.equal('gatewayUrl could not be determined'); done(); diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/filters/big-int-to-string.filter.js --- a/src/app/shared/filters/big-int-to-string.filter.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/filters/big-int-to-string.filter.js Fri Oct 13 14:05:09 2017 -0400 @@ -32,7 +32,7 @@ * @param {Number} * @returns {String} */ -function filterProvider () { +export function filterProvider () { return val => { val = val || 0; return val.toFixed(); diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/filters/big-int-to-string.filter.spec.js --- a/src/app/shared/filters/big-int-to-string.filter.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/filters/big-int-to-string.filter.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -26,16 +26,18 @@ */ import big from 'big.js'; +import filtersModule from './filters.module.js'; describe('bigIntToString filter', () => { - beforeEach(angular.mock.module('app.filters')); - let fn; - beforeEach(angular.mock.inject(bigIntToStringFilter => { - 'ngInject'; - fn = bigIntToStringFilter; - })); + beforeEach(() => { + angular.mock.module(filtersModule); + angular.mock.inject(bigIntToStringFilter => { + 'ngInject'; + fn = bigIntToStringFilter; + }); + }); it('should convert big int to string', () => { fn(big(100)).should.equal('100'); @@ -46,7 +48,7 @@ }); it('should fail on object input', () => { - (() => fn({ foo: 'bar' })).should.throw(/undefined is not a constructor/); + (() => fn({ foo: 'bar' })).should.throw(); }); it('should treat undefined as 0', () => { diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/filters/extract-class.pipe.spec.ts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/shared/filters/extract-class.pipe.spec.ts Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,51 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import * as sinon from 'sinon'; + +import { ExtractClassPipe } from './extract-class.pipe'; +import { ExtractClassService } from "../services/extract-class.service"; + +describe('ExtractClassPipe', () => { + + let pipe: ExtractClassPipe; + let svc: ExtractClassService; + beforeEach(() => { + svc = { + extract: sinon.stub().returns('svc-result') + }; + pipe = new ExtractClassPipe(svc); + }); + + it('should delegate to service', () => { + svc.extract.should.not.be.called(); + pipe.transform('foo', true).should.equal('svc-result'); + svc.extract.should.be.calledOnce(); + svc.extract.should.be.calledWith('foo', true); + }); + +}); diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/filters/extract-class.pipe.ts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/shared/filters/extract-class.pipe.ts Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,44 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import { + Inject, + Pipe, + PipeTransform, +} from "@angular/core"; +import { ExtractClassService } from "../services/extract-class.service"; + +@Pipe({ + name: "extractClass", +}) +export class ExtractClassPipe implements PipeTransform { + constructor(@Inject(ExtractClassService) private svc: ExtractClassService) {} + + public transform(value: string, includePkg: boolean): string { + return this.svc.extract(value, includePkg); + } +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/filters/filters.module.ts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/shared/filters/filters.module.ts Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,45 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import { NgModule } from "@angular/core"; +import { ServicesModule } from "../services/services.module"; + +import { ExtractClassPipe } from "./extract-class.pipe"; +import { FormatBytesPipe } from "./format-bytes.pipe"; + +@NgModule({ + declarations: [ + ExtractClassPipe, + FormatBytesPipe, + ], + exports: [ + ExtractClassPipe, + FormatBytesPipe, + ], + imports: [ ServicesModule ], +}) +export class FiltersModule {} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/filters/format-bytes.pipe.spec.ts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/shared/filters/format-bytes.pipe.spec.ts Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,58 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import * as sinon from 'sinon'; + +import { FormatBytesPipe } from './format-bytes.pipe'; +import { Metric } from './metric'; +import { ScaleBytesService } from '../services/scale-bytes.service' + +describe('FormatBytesPipe', () => { + + let pipe: FormatBytesPipe; + let svc: ScaleBytesService; + beforeEach(() => { + svc = { + format: sinon.stub().returns({ + result: 100, + scale: 2, + unit: 'KiB' + }), + metricToBigInt: null, + sizes: ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'], + }; + pipe = new FormatBytesPipe(svc); + }); + + it('should delegate to service', () => { + svc.format.should.not.be.called(); + pipe.transform({ $numberLong: '2' }).should.equal('100 KiB'); + svc.format.should.be.calledOnce(); + svc.format.should.be.calledWithMatch({ $numberLong: '2' }); + }); + +}); diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/filters/format-bytes.pipe.ts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/shared/filters/format-bytes.pipe.ts Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,46 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import { + Inject, + Pipe, + PipeTransform, +} from "@angular/core"; +import { ScaleBytesService } from "../services/scale-bytes.service"; +import { Metric } from "./metric"; + +@Pipe({ + name: "formatBytes", +}) +export class FormatBytesPipe implements PipeTransform { + constructor(@Inject(ScaleBytesService) private svc: ScaleBytesService) {} + + public transform(value: Metric): string { + const scale = this.svc.format(value); + return scale.result + " " + scale.unit; + } +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/filters/metric-to-big-int.filter.spec.js --- a/src/app/shared/filters/metric-to-big-int.filter.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/filters/metric-to-big-int.filter.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -26,12 +26,16 @@ */ import big from 'big.js'; +import { default as servicesModule, init as initServices } from 'shared/services/services.module.js'; +import filtersModule from './filters.module.js'; describe('metricToBigInt filter', () => { let fn; beforeEach(() => { - angular.mock.module('app.filters'); + angular.mock.module(servicesModule); + initServices(); + angular.mock.module(filtersModule); angular.mock.inject(metricToBigIntFilter => { 'ngInject'; fn = metricToBigIntFilter; diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/filters/metric.d.ts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/shared/filters/metric.d.ts Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,32 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +export type Metric = IMongoLong; + +export interface IMongoLong { + $numberLong: string; +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/ajs-upgraded-providers.ts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/shared/services/ajs-upgraded-providers.ts Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,82 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import { CommandChannelService } from "./command-channel.service.js"; +export const commandChannelServiceProvider = { + deps: ["$injector"], + provide: CommandChannelService, + useClass: CommandChannelService, +}; + +import { ExtractClassService } from "./extract-class.service.js"; +export const extractClassServiceProvider = { + deps: ["$injector"], + provide: ExtractClassService, + useClass: ExtractClassService, +}; + +import { LocalStorageService } from "./local-storage.service.js"; +export const localStorageServiceProvider = { + deps: ["$injector"], + provide: LocalStorageService, + useClass: LocalStorageService, +}; + +import { MetricToBigIntService } from "./metric-to-big-int.service.js"; +export const metricToBigIntServiceProvider = { + deps: ["$injector"], + provide: MetricToBigIntService, + useClass: MetricToBigIntService, +}; + +import { MultichartService } from "./multichart.service.js"; +export const multichartServiceProvider = { + deps: ["$injector"], + provide: MultichartService, + useClass: MultichartService, +}; + +import { SanitizeService } from "./sanitize.service.js"; +export const sanitizeServiceProvider = { + deps: ["$injector"], + provide: SanitizeService, + useClass: SanitizeService, +}; + +import { ScaleBytesService } from "./scale-bytes.service.js"; +export const scaleBytesServiceProvider = { + deps: ["$injector"], + provide: ScaleBytesService, + useClass: ScaleBytesService, +}; + +import { WebSocketFactory } from "./websocket-factory.service.js"; +export const webSocketFactoryProvider = { + deps: ["$injector"], + provide: WebSocketFactory, + useClass: WebSocketFactory, +}; diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/command-channel.service.js --- a/src/app/shared/services/command-channel.service.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/services/command-channel.service.js Fri Oct 13 14:05:09 2017 -0400 @@ -30,7 +30,7 @@ const CLIENT_REQUEST_TYPE = 2; -class CommandChannelService { +export class CommandChannelService { constructor ($q, authService, commandChannelUrl, webSocketFactory, $translate) { 'ngInject'; this._sequence = 1; @@ -122,6 +122,8 @@ } } -angular - .module(servicesModule) - .service('commandChannelService', CommandChannelService); +export function init () { + angular + .module(servicesModule) + .service('commandChannelService', CommandChannelService); +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/command-channel.service.spec.js --- a/src/app/shared/services/command-channel.service.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/services/command-channel.service.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -25,7 +25,7 @@ * exception statement from your version. */ -import servicesModule from 'shared/services/services.module.js'; +import { default as servicesModule, init as initServices } from 'shared/services/services.module.js'; import configModule from 'shared/config/config.module.js'; describe('CommandChannelService', () => { @@ -66,6 +66,7 @@ $provide.constant('commandChannelUrl', 'ws://foo-host:1234'); }); angular.mock.module(servicesModule); + initServices(); angular.mock.module($provide => { 'ngInject'; $provide.value('authService', authService); diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/extract-class.service.js --- a/src/app/shared/services/extract-class.service.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/services/extract-class.service.js Fri Oct 13 14:05:09 2017 -0400 @@ -25,7 +25,7 @@ * exception statement from your version. */ -class ExtractClassService { +export class ExtractClassService { extract (fullClassName = '', includePkg = false) { if (fullClassName.indexOf('.') === -1) { @@ -57,6 +57,8 @@ } } -angular - .module('app.services') - .service('extractClassService', ExtractClassService); +export function init () { + angular + .module('app.services') + .service('extractClassService', ExtractClassService); +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/extract-class.service.spec.js --- a/src/app/shared/services/extract-class.service.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/services/extract-class.service.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -25,16 +25,19 @@ * exception statement from your version. */ +import { default as servicesModule, init as initServices } from 'shared/services/services.module.js'; + describe('ExtractClassService', () => { let svc; - - beforeEach(angular.mock.module('app.services')); - - beforeEach(inject(extractClassService => { - 'ngInject'; - svc = extractClassService; - })); + beforeEach(() => { + angular.mock.module(servicesModule); + initServices(); + angular.mock.inject(extractClassService => { + 'ngInject'; + svc = extractClassService; + }); + }); it('should return early if class name is bare', () => { svc.extract('className').should.equal('className'); diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/local-storage.service.js --- a/src/app/shared/services/local-storage.service.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/services/local-storage.service.js Fri Oct 13 14:05:09 2017 -0400 @@ -27,7 +27,7 @@ import servicesModule from 'shared/services/services.module.js'; -class LocalStorageService { +export class LocalStorageService { constructor ($window) { 'ngInject'; @@ -57,6 +57,8 @@ } -angular - .module(servicesModule) - .service('localStorage', LocalStorageService); +export function init () { + angular + .module(servicesModule) + .service('localStorage', LocalStorageService); +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/local-storage.service.spec.js --- a/src/app/shared/services/local-storage.service.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/services/local-storage.service.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -25,7 +25,7 @@ * exception statement from your version. */ -import servicesModule from 'shared/services/services.module.js'; +import { default as servicesModule, init as initServices } from 'shared/services/services.module.js'; describe('localStorage', () => { @@ -47,6 +47,7 @@ }); angular.mock.module(servicesModule); + initServices(); angular.mock.inject(localStorage => { 'ngInject'; diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/metric-to-big-int.service.js --- a/src/app/shared/services/metric-to-big-int.service.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/services/metric-to-big-int.service.js Fri Oct 13 14:05:09 2017 -0400 @@ -34,7 +34,7 @@ * @param {Object} metric e.g., '{ $numberLong: metric }' * @return {Big number Object} */ -class MetricToBigIntService { +export class MetricToBigIntService { constructor () { this.big = big; } @@ -51,6 +51,8 @@ } } -angular - .module('app.services') - .service('metricToBigIntService', MetricToBigIntService); +export function init () { + angular + .module('app.services') + .service('metricToBigIntService', MetricToBigIntService); +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/metric-to-big-int.service.spec.js --- a/src/app/shared/services/metric-to-big-int.service.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/services/metric-to-big-int.service.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -26,18 +26,20 @@ */ import big from 'big.js'; +import { default as servicesModule, init as initServices } from 'shared/services/services.module.js'; describe('MetricToBigIntService', () => { let svc; - - beforeEach(angular.mock.module('app.services')); - - beforeEach(inject(metricToBigIntService => { - 'ngInject'; - svc = metricToBigIntService; - sinon.spy(svc, 'big'); - })); + beforeEach(() => { + angular.mock.module(servicesModule); + initServices(); + angular.mock.inject(metricToBigIntService => { + 'ngInject'; + svc = metricToBigIntService; + sinon.spy(svc, 'big'); + }); + }); afterEach(() => { svc.big.restore(); diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/multichart.service.js --- a/src/app/shared/services/multichart.service.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/services/multichart.service.js Fri Oct 13 14:05:09 2017 -0400 @@ -28,7 +28,7 @@ import servicesModule from 'shared/services/services.module.js'; import _ from 'lodash'; -class MultiChartService { +export class MultichartService { constructor ($q, $translate) { this.q = $q; this.translate = $translate; @@ -174,6 +174,8 @@ } } -angular - .module(servicesModule) - .service('multichartService', MultiChartService); +export function init () { + angular + .module(servicesModule) + .service('multichartService', MultichartService); +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/multichart.service.spec.js --- a/src/app/shared/services/multichart.service.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/services/multichart.service.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -25,13 +25,14 @@ * exception statement from your version. */ -import servicesModule from 'shared/services/services.module.js'; +import { default as servicesModule, init as initServices } from 'shared/services/services.module.js'; describe('MultichartService', () => { let svc, translate; beforeEach(() => { angular.mock.module(servicesModule); + initServices(); translate = sinon.stub().returns({ then: sinon.stub().yields() }); diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/sanitize.service.js --- a/src/app/shared/services/sanitize.service.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/services/sanitize.service.js Fri Oct 13 14:05:09 2017 -0400 @@ -27,7 +27,7 @@ import servicesModule from 'shared/services/services.module.js'; -class SanitizeService { +export class SanitizeService { sanitize (str) { if (!str) { return; @@ -41,6 +41,8 @@ } } -angular - .module(servicesModule) - .service('sanitizeService', SanitizeService); +export function init () { + angular + .module(servicesModule) + .service('sanitizeService', SanitizeService); +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/sanitize.service.spec.js --- a/src/app/shared/services/sanitize.service.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/services/sanitize.service.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -25,13 +25,14 @@ * exception statement from your version. */ -import servicesModule from 'shared/services/services.module.js'; +import { default as servicesModule, init as initServices } from 'shared/services/services.module.js'; describe('SanitizeService', () => { let svc; beforeEach(() => { angular.mock.module(servicesModule); + initServices(); angular.mock.inject(sanitizeService => { 'ngInject'; svc = sanitizeService; diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/scale-bytes.service.js --- a/src/app/shared/services/scale-bytes.service.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/services/scale-bytes.service.js Fri Oct 13 14:05:09 2017 -0400 @@ -25,7 +25,7 @@ * exception statement from your version. */ -class ScaleBytesService { +export class ScaleBytesService { constructor (metricToBigIntService) { 'ngInject'; this.metricToBigInt = metricToBigIntService; @@ -66,6 +66,8 @@ } } -angular - .module('app.services') - .service('scaleBytesService', ScaleBytesService); +export function init () { + angular + .module('app.services') + .service('scaleBytesService', ScaleBytesService); +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/scale-bytes.service.spec.js --- a/src/app/shared/services/scale-bytes.service.spec.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/services/scale-bytes.service.spec.js Fri Oct 13 14:05:09 2017 -0400 @@ -25,15 +25,19 @@ * exception statement from your version. */ -describe('ScaleBytesService', () => { +import { default as servicesModule, init as initServices } from 'shared/services/services.module.js'; - beforeEach(angular.mock.module('app.services')); +describe('ScaleBytesService', () => { let svc; - beforeEach(angular.mock.inject(scaleBytesService => { - 'ngInject'; - svc = scaleBytesService; - })); + beforeEach(() => { + angular.mock.module(servicesModule); + initServices(); + angular.mock.inject(scaleBytesService => { + 'ngInject'; + svc = scaleBytesService; + }); + }); it('should exist', () => { should.exist(svc); diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/services.module.js --- a/src/app/shared/services/services.module.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/services/services.module.js Fri Oct 13 14:05:09 2017 -0400 @@ -35,5 +35,10 @@ ]) .name; -let req = require.context('./', true, /\.service\.js/); -req.keys().map(req); +export function init () { + let req = require.context('./', true, /\.service\.js/); + req.keys().map(key => { + let mod = req(key); + mod.init(); + }); +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/services.module.ts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/shared/services/services.module.ts Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,55 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import { NgModule } from "@angular/core"; + +import { + commandChannelServiceProvider, + extractClassServiceProvider, + localStorageServiceProvider, + metricToBigIntServiceProvider, + multichartServiceProvider, + sanitizeServiceProvider, + scaleBytesServiceProvider, + webSocketFactoryProvider, +} from "./ajs-upgraded-providers"; + +@NgModule({ + declarations: [], + imports: [], + providers: [ + commandChannelServiceProvider, + extractClassServiceProvider, + localStorageServiceProvider, + metricToBigIntServiceProvider, + multichartServiceProvider, + sanitizeServiceProvider, + scaleBytesServiceProvider, + webSocketFactoryProvider, + ], +}) +export class ServicesModule {} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/app/shared/services/websocket-factory.service.js --- a/src/app/shared/services/websocket-factory.service.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/app/shared/services/websocket-factory.service.js Fri Oct 13 14:05:09 2017 -0400 @@ -28,7 +28,7 @@ import servicesModule from './services.module.js'; /* istanbul ignore next */ -class WebSocketFactory { +export class WebSocketFactory { createSocket (connectUrl) { if ('WebSocket' in window) { return new WebSocket(connectUrl); @@ -40,6 +40,8 @@ } } -angular - .module(servicesModule) - .service('webSocketFactory', WebSocketFactory); +export function init () { + angular + .module(servicesModule) + .service('webSocketFactory', WebSocketFactory); +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/gateway-url-helper.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gateway-url-helper.js Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,45 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +export function DetermineGatewayUrl () { + return new Promise(resolve => { + $.get('/gatewayurl') + .done(res => { + window.tmsGatewayUrl = res.gatewayUrl; + }) + .fail(() => { + let url = require('url'); + let parsed = url.parse(window.location.href); + let gateway = { + protocol: parsed.protocol, + host: parsed.host + }; + window.tmsGatewayUrl = url.format(gateway); + }) + .always(() => resolve()); + }); +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/main.ts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main.ts Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,40 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import './rx-subject.stub.ts'; +import 'zone.js'; +import 'reflect-metadata'; + +import { UpgradeModule } from '@angular/upgrade/static'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { AppModule } from './app/app.module'; + +import { DetermineGatewayUrl } from './gateway-url-helper.js'; + +DetermineGatewayUrl().then(() => { + platformBrowserDynamic().bootstrapModule(AppModule); +}); diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/rx-subject.stub.ts --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/rx-subject.stub.ts Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,35 @@ +/** + * Copyright 2012-2017 Red Hat, Inc. + * + * Thermostat is distributed under the GNU General Public License, + * version 2 or any later version (with a special exception described + * below, commonly known as the "Classpath Exception"). + * + * A copy of GNU General Public License (GPL) is included in this + * distribution, in the file COPYING. + * + * Linking Thermostat code with other modules is making a combined work + * based on Thermostat. Thus, the terms and conditions of the GPL + * cover the whole combination. + * + * As a special exception, the copyright holders of Thermostat give you + * permission to link this code with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under + * terms of your choice, provided that you also meet, for each linked + * independent module, the terms and conditions of the license of that + * module. An independent module is a module which is not derived from + * or based on Thermostat code. If you modify Thermostat, you may + * extend this exception to your version of the software, but you are + * not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +import { Operator } from 'rxjs/Operator'; +import { Observable } from 'rxjs/Observable'; + +declare module 'rxjs/Subject' { + interface Subject { + lift(operator: Operator): Observable; + } +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f src/tests.webpack.js --- a/src/tests.webpack.js Fri Oct 13 11:39:51 2017 -0400 +++ b/src/tests.webpack.js Fri Oct 13 14:05:09 2017 -0400 @@ -25,12 +25,36 @@ * exception statement from your version. */ +import 'core-js/client/core.js'; +import 'zone.js/dist/zone.js'; +import 'zone.js/dist/long-stack-trace-zone.js'; +import 'zone.js/dist/proxy.js'; +import 'zone.js/dist/sync-test.js'; +import 'zone.js/dist/mocha-patch.js'; +import 'zone.js/dist/async-test.js'; +import 'zone.js/dist/fake-async-test.js'; + import 'angular'; +import 'angular-patternfly'; +import '@uirouter/angularjs'; +import angularTranslate from 'angular-translate'; +import 'angular-translate-interpolation-messageformat'; +import 'oclazyload'; + import 'angular-mocks/angular-mocks'; -import 'babel-polyfill'; + +import { getTestBed } from "@angular/core/testing"; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from "@angular/platform-browser-dynamic/testing"; + +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); window.tmsGatewayUrl = 'http://localhost:8888/'; -const context = require.context('./app', true, /\.js$/); - -context.keys().forEach(context); +const testsContext = require.context('./app', true, /\.spec\.(js|ts)$/); +testsContext.keys().forEach(testsContext); diff -r 63df0ca94b6b -r 2eb2ae0f3b3f tsconfig.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tsconfig.json Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,22 @@ +{ + "files": [ + "src/rx-subject.stub.ts", + "src/main.ts" + ], + "compilerOptions": { + "outDir": "./dist", + "noImplicitAny": true, + "target": "es5", + "experimentalDecorators": true, + "allowJs": true, + "allowSyntheticDefaultImports": true, + "sourceMap": true, + "lib": [ + "es2015", + "dom" + ] + }, + "exclude": [ + "node_modules" + ] +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f tslint.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tslint.json Fri Oct 13 14:05:09 2017 -0400 @@ -0,0 +1,9 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:recommended" + ], + "jsRules": {}, + "rules": {}, + "rulesDirectory": [] +} diff -r 63df0ca94b6b -r 2eb2ae0f3b3f webpack.config.js --- a/webpack.config.js Fri Oct 13 11:39:51 2017 -0400 +++ b/webpack.config.js Fri Oct 13 14:05:09 2017 -0400 @@ -41,7 +41,7 @@ var config = {}; config.entry = isTest ? void 0 : { - app: './src/app/app.module.js' + app: './src/main.ts' }; config.resolve = { @@ -59,11 +59,12 @@ 'scss': 'assets/scss', 'shared': path.resolve(__dirname, 'src', 'app', 'shared'), 'templates': 'shared/templates' - } + }, + extensions: [ '.ts', '.js' ] }; config.output = isTest ? {} : { - path: __dirname + '/dist', + path: path.resolve(__dirname, 'dist'), filename: '[name].bundle.js', chunkFilename: '[name].bundle.js' }; @@ -82,6 +83,10 @@ loader: 'babel-loader', exclude: /node_modules/ }, { + test: /\.ts$/, + use: 'ts-loader?silent=true', + exclude: /node_modules/ + }, { test: /\.scss$/, loader: ['style-loader', 'css-loader', 'sass-loader'], exclude: /node_modules/ @@ -101,6 +106,15 @@ test: /^(?!.*\.spec\.js$).*\.js$/, include: __dirname + '/src/app/', loaders: ['istanbul-instrumenter-loader', 'babel-loader'] + }, { + test: /^(?!.*\.spec\.ts$).*\.ts$/, + include: __dirname + '/src/app/', + exclude: /(node_modules|\.spec\.ts$)/, + loader: 'istanbul-instrumenter-loader', + enforce: 'post', + options: { + esModules: true + } }] };