Mercurial > hg > thermostat-ng > web-client
changeset 184:81d3963dd455
Add user preferences menu with TLS toggle setting
Reviewed-by: jkang
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-August/024786.html
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-September/024897.html
author | Andrew Azores <aazores@redhat.com> |
---|---|
date | Fri, 08 Sep 2017 08:31:47 -0400 |
parents | cc56f2e71a24 |
children | c10369cb53a6 |
files | src/app/components/user-prefs/en.locale.yaml src/app/components/user-prefs/gateway-decorator.service.js src/app/components/user-prefs/gateway-decorator.service.spec.js src/app/components/user-prefs/user-prefs.component.js src/app/components/user-prefs/user-prefs.controller.js src/app/components/user-prefs/user-prefs.controller.spec.js src/app/components/user-prefs/user-prefs.html src/app/components/user-prefs/user-prefs.routing.js src/app/components/user-prefs/user-prefs.routing.spec.js src/app/components/user-prefs/user-prefs.service.js src/app/components/user-prefs/user-prefs.service.spec.js src/app/en.locale.yaml src/app/index.html src/app/shared/config/config.module.js |
diffstat | 14 files changed, 626 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/user-prefs/en.locale.yaml Fri Sep 08 08:31:47 2017 -0400 @@ -0,0 +1,8 @@ +userPrefs: + USE_TLS: Use TLS + TLS_DESCRIPTION: Use secure connections to the web-gateway and command channel. + + RESTART_NOTE: > + <i>App restart is recommended after changing this setting. + You may refresh the application in your browser, or close the tab + and re-open the Thermostat Web-Client.</i>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/user-prefs/gateway-decorator.service.js Fri Sep 08 08:31:47 2017 -0400 @@ -0,0 +1,73 @@ +/** + * 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 configModule from 'shared/config/config.module.js'; +import service from './user-prefs.service.js'; +import * as url from 'url'; + +function gatewayUrl ($provide) { + 'ngInject'; + $provide.decorator('gatewayUrl', gatewayUrlDecorator); +} + +function gatewayUrlDecorator ($delegate, userPrefsService) { + 'ngInject'; + let protocol = 'http'; + if (userPrefsService.tlsEnabled) { + protocol = 'https'; + } + let parsed = url.parse($delegate); + parsed.protocol = protocol; + return url.format(parsed); +} + +function commandChannelUrl ($provide) { + 'ngInject'; + $provide.decorator('commandChannelUrl', commandChannelUrlDecorator); +} + +function commandChannelUrlDecorator ($delegate, userPrefsService) { + 'ngInject'; + let protocol = 'ws'; + if (userPrefsService.tlsEnabled) { + protocol = 'wss'; + } + let parsed = url.parse($delegate); + parsed.protocol = protocol; + return url.format(parsed); +} + +export { gatewayUrl, gatewayUrlDecorator, commandChannelUrl, commandChannelUrlDecorator }; + +export default angular + .module('userPrefs.gatewayDecorator', [ + configModule, + service + ]) + .config(gatewayUrl) + .config(commandChannelUrl) + .name;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/user-prefs/gateway-decorator.service.spec.js Fri Sep 08 08:31:47 2017 -0400 @@ -0,0 +1,88 @@ +/** + * 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 decorator from './gateway-decorator.service.js'; + +describe('gatewayDecoratorService', () => { + + let provide, userPrefsService; + beforeEach(() => { + provide = { decorator: sinon.spy() }; + userPrefsService = { tlsEnabled: true }; + }); + + describe('gatewayUrl', () => { + it('should provide a gatewayUrl decorator function', () => { + provide.decorator.should.not.be.called(); + decorator.gatewayUrl(provide); + provide.decorator.should.be.calledOnce(); + provide.decorator.should.be.calledWith('gatewayUrl', decorator.gatewayUrlDecorator); + }); + }); + + describe('gatewayUrlDecorator', () => { + it('should enforce https when TLS is enabled', () => { + decorator.gatewayUrlDecorator('http://example.com/', userPrefsService).should.equal('https://example.com/'); + }); + + it('should enforce http when TLS is disabled', () => { + userPrefsService.tlsEnabled = false; + decorator.gatewayUrlDecorator('https://example.com/', userPrefsService).should.equal('http://example.com/'); + }); + + it('should not change protocol if already matching', () => { + userPrefsService.tlsEnabled = false; + decorator.gatewayUrlDecorator('http://example.com/', userPrefsService).should.equal('http://example.com/'); + }); + }); + + describe('commandChannelUrl', () => { + it('should provide a commandChannelUrl decorator function', () => { + provide.decorator.should.not.be.called(); + decorator.commandChannelUrl(provide); + provide.decorator.should.be.calledOnce(); + provide.decorator.should.be.calledWith('commandChannelUrl', decorator.commandChannelUrlDecorator); + }); + }); + + describe('commandChannelUrlDecorator', () => { + it('should enforce wss when TLS is enabled', () => { + decorator.commandChannelUrlDecorator('ws://example.com/', userPrefsService).should.equal('wss://example.com/'); + }); + + it('should enforce ws when TLS is disabled', () => { + userPrefsService.tlsEnabled = false; + decorator.commandChannelUrlDecorator('wss://example.com/', userPrefsService).should.equal('ws://example.com/'); + }); + + it('should not change protocol if already matching', () => { + userPrefsService.tlsEnabled = false; + decorator.commandChannelUrlDecorator('ws://example.com/', userPrefsService).should.equal('ws://example.com/'); + }); + }); + +});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/user-prefs/user-prefs.component.js Fri Sep 08 08:31:47 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 './user-prefs.controller.js'; + +export default angular + .module('userPrefsComponent', [controller]) + .component('userPrefs', { + controller: 'UserPreferencesController', + template: require('./user-prefs.html') + }) + .name;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/user-prefs/user-prefs.controller.js Fri Sep 08 08:31:47 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 service from './user-prefs.service.js'; + +class UserPreferencesController { + constructor (userPrefsService) { + 'ngInject'; + this._userPrefsService = userPrefsService; + + let tlsSwitch = angular.element('#tlsSwitch'); + tlsSwitch.bootstrapSwitch(); + tlsSwitch.bootstrapSwitch('state', userPrefsService.tlsEnabled); + tlsSwitch.on('switchChange.bootstrapSwitch', () => { + this.tlsEnabled = tlsSwitch.bootstrapSwitch('state'); + }); + } + + set tlsEnabled (tlsEnabled) { + this._userPrefsService.tlsEnabled = tlsEnabled; + } + + get tlsEnabled () { + return this._userPrefsService.tlsEnabled; + } +} + +export default angular + .module('userPrefs.controller', [service]) + .controller('UserPreferencesController', UserPreferencesController) + .name;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/user-prefs/user-prefs.controller.spec.js Fri Sep 08 08:31:47 2017 -0400 @@ -0,0 +1,87 @@ +/** + * 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 './user-prefs.controller.js'; + +describe('UserPreferencesController', () => { + + let userPrefsSvc, ctrl, bootstrapSwitch; + beforeEach(() => { + angular.mock.module(controller); + angular.mock.inject($controller => { + 'ngInject'; + userPrefsSvc = { + tlsEnabled: 'fake-state' + }; + + bootstrapSwitch = { + bootstrapSwitch: sinon.stub().returns(false), + on: sinon.spy() + }; + sinon.stub(angular, 'element').returns(bootstrapSwitch); + + ctrl = $controller('UserPreferencesController', { + userPrefsService: userPrefsSvc + }); + }); + }); + + afterEach(() => { + angular.element.restore(); + }); + + it('should exist', () => { + should.exist(ctrl); + }); + + it('should initialize bootstrap switch', () => { + bootstrapSwitch.bootstrapSwitch.should.be.calledTwice(); + bootstrapSwitch.bootstrapSwitch.secondCall.should.be.calledWith('state', 'fake-state'); + }); + + it('should handle switch change event', () => { + bootstrapSwitch.on.should.be.calledOnce(); + bootstrapSwitch.on.should.be.calledWith('switchChange.bootstrapSwitch', sinon.match.func); + let func = bootstrapSwitch.on.args[0][1]; + bootstrapSwitch.bootstrapSwitch.returns('new-state'); + func(); + userPrefsSvc.tlsEnabled.should.equal('new-state'); + }); + + it('should delegate tlsEnabled set to service', () => { + userPrefsSvc.tlsEnabled.should.equal('fake-state'); + ctrl.tlsEnabled = true; + userPrefsSvc.tlsEnabled.should.be.true(); + }); + + it('should delegate tlsEnabled get to service', () => { + ctrl.tlsEnabled.should.equal('fake-state'); + userPrefsSvc.tlsEnabled = 'new-state'; + ctrl.tlsEnabled.should.equal('new-state'); + }); + +});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/user-prefs/user-prefs.html Fri Sep 08 08:31:47 2017 -0400 @@ -0,0 +1,15 @@ +<div class="container-fluid container-cards-pf"> + <div class="form-group"> + <label for="tlsSwitch" class="label label-info pull-left" translate>userPrefs.USE_TLS</label> + <input class="bootstrap-switch pull-right" id="tlsSwitch" name="tlsSwitch" + data-size="mini" + type="checkbox" + ng-checked="$ctrl.tlsEnabled" + /> + <p> + <span translate>userPrefs.TLS_DESCRIPTION</span> + <br/> + <span translate>userPrefs.RESTART_NOTE</span> + </p> + </div> +</div>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/user-prefs/user-prefs.routing.js Fri Sep 08 08:31:47 2017 -0400 @@ -0,0 +1,62 @@ +/** + * 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 service from './user-prefs.service.js'; +import gatewayDecorator from './gateway-decorator.service.js'; + +function config ($stateProvider) { + 'ngInject'; + + $stateProvider.state('user-prefs', { + url: '/user-prefs', + component: 'userPrefs', + resolve: { + lazyLoad: ($q, $ocLazyLoad) => { + 'ngInject'; + return $q(resolve => { + require.ensure(['./user-prefs.component.js'], () => { + let module = require('./user-prefs.component.js'); + $ocLazyLoad.load({ name: module.default }); + resolve(module); + }); + }); + } + } + }); +} + +export { config }; + +export default angular + .module('userPrefs.routing', [ + 'ui.router', + 'ui.bootstrap', + service, + gatewayDecorator + ]) + .config(config) + .name;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/user-prefs/user-prefs.routing.spec.js Fri Sep 08 08:31:47 2017 -0400 @@ -0,0 +1,76 @@ +/** + * 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('UserPrefsRouting', () => { + + let module = require('./user-prefs.routing.js'); + + let stateProvider, args, q, ocLazyLoad; + beforeEach(() => { + stateProvider = { + state: sinon.spy() + }; + module.config(stateProvider); + args = stateProvider.state.args[0]; + q = sinon.spy(); + ocLazyLoad = { + load: sinon.spy() + }; + }); + + describe('stateProvider', () => { + it('should call $stateProvider.state', () => { + stateProvider.state.should.be.calledOnce(); + }); + + it('should define a \'user-prefs\' state', () => { + args[0].should.equal('user-prefs'); + }); + + it('should map to /user-prefs', () => { + args[1].url.should.equal('/user-prefs'); + }); + + it('resolve should load user-prefs component', done => { + let resolveFn = args[1].resolve.lazyLoad[2]; + resolveFn.should.be.a.Function(); + resolveFn(q, ocLazyLoad); + q.should.be.calledOnce(); + + let deferred = q.args[0][0]; + deferred.should.be.a.Function(); + + let resolve = sinon.stub().callsFake(val => { + ocLazyLoad.load.should.be.calledWith({ name: require('./user-prefs.component.js').default}); + val.should.equal(require('./user-prefs.component.js')); + done(); + }); + deferred(resolve); + }); + }); + +});
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/user-prefs/user-prefs.service.js Fri Sep 08 08:31:47 2017 -0400 @@ -0,0 +1,57 @@ +/** + * 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 url from 'url'; + +class UserPreferencesService { + constructor ($cookies) { + 'ngInject'; + this._cookies = $cookies; + } + + set tlsEnabled (tlsEnabled) { + this._cookies.put('tlsEnabled', JSON.parse(tlsEnabled)); + } + + get tlsEnabled () { + let raw = this._cookies.get('tlsEnabled'); + // can't use gatewayUrl value here due to circular reference, but process.env + // is not available in test suite + /* istanbul ignore next */ + if (!angular.isDefined(raw)) { + let protocol = url.parse(process.env.GATEWAY_URL).protocol; + this.tlsEnabled = protocol === 'https:'; + raw = this._cookies.get('tlsEnabled'); + } + return JSON.parse(raw); + } +} + +export default angular + .module('userPrefs.service', ['ngCookies']) + .service('userPrefsService', UserPreferencesService) + .name;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/app/components/user-prefs/user-prefs.service.spec.js Fri Sep 08 08:31:47 2017 -0400 @@ -0,0 +1,64 @@ +/** + * 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 service from './user-prefs.service.js'; + +describe('userPrefsService', () => { + + let svc, cookies; + beforeEach(() => { + cookies = { + get: sinon.stub().returns(), + put: sinon.spy() + }; + angular.mock.module(service); + angular.mock.module($provide => { + 'ngInject'; + $provide.value('$cookies', cookies); + }); + angular.mock.inject(userPrefsService => { + 'ngInject'; + svc = userPrefsService; + }); + }); + + it('should exist', () => { + should.exist(svc); + }); + + it('should store tlsEnabled preference in cookies', () => { + cookies.put.should.not.be.called(); + svc.tlsEnabled = 'false'; + cookies.put.should.be.calledWith('tlsEnabled', false); + }); + + it('should return stored cookie value when present', () => { + cookies.get.returns(true); + svc.tlsEnabled.should.equal(true); + }); + +});
--- a/src/app/en.locale.yaml Thu Sep 07 13:59:42 2017 -0400 +++ b/src/app/en.locale.yaml Fri Sep 08 08:31:47 2017 -0400 @@ -10,3 +10,5 @@ USERNAME: Username LOGOUT: Log Out + + USER_PREFS: Preferences
--- a/src/app/index.html Thu Sep 07 13:59:42 2017 -0400 +++ b/src/app/index.html Fri Sep 08 08:31:47 2017 -0400 @@ -36,6 +36,7 @@ <span translate-attr="{title: 'navbar.USERNAME'}" class="fa pficon-user"></span> {{username}} <span class="caret"></span> </a> <ul class="dropdown-menu" aria-labelledby="userDropwdown"> + <li><a ui-sref="user-prefs" translate>navbar.USER_PREFS</a></li> <li><a id="logoutButton" ng-click="logout()" style="cursor: pointer; cursor: hand" translate>navbar.LOGOUT</a></li> </ul> </li>
--- a/src/app/shared/config/config.module.js Thu Sep 07 13:59:42 2017 -0400 +++ b/src/app/shared/config/config.module.js Fri Sep 08 08:31:47 2017 -0400 @@ -39,6 +39,6 @@ .module('configModule', []) .constant('environment', process.env.NODE_ENV) .constant('debug', process.env.DEBUG) - .constant('gatewayUrl', process.env.GATEWAY_URL) - .constant('commandChannelUrl', cmdChanUrl(process.env.GATEWAY_URL)) + .value('gatewayUrl', process.env.GATEWAY_URL) + .value('commandChannelUrl', cmdChanUrl(process.env.GATEWAY_URL)) .name;