diff --git a/dashboard/src/app/factories/factory-details/information-tab/factory-information/factory-information.controller.ts b/dashboard/src/app/factories/factory-details/information-tab/factory-information/factory-information.controller.ts index 9b741d099ec..ac53d4bc6ce 100644 --- a/dashboard/src/app/factories/factory-details/information-tab/factory-information/factory-information.controller.ts +++ b/dashboard/src/app/factories/factory-details/information-tab/factory-information/factory-information.controller.ts @@ -10,10 +10,10 @@ * Red Hat, Inc. - initial API and implementation */ 'use strict'; -import {CheAPI} from '../../../../../components/api/che-api.factory'; -import {CheNotification} from '../../../../../components/notification/che-notification.factory'; -import {ConfirmDialogService} from '../../../../../components/service/confirm-dialog/confirm-dialog.service'; -import {CheBranding} from '../../../../../components/branding/che-branding.factory'; +import { CheAPI } from '../../../../../components/api/che-api.factory'; +import { CheNotification } from '../../../../../components/notification/che-notification.factory'; +import { ConfirmDialogService } from '../../../../../components/service/confirm-dialog/confirm-dialog.service'; +import { CheBranding } from '../../../../../components/branding/che-branding'; /** * Controller for a factory information. @@ -55,16 +55,16 @@ export class FactoryInformationController { * Default constructor that is using resource injection */ constructor($scope: ng.IScope, - cheAPI: CheAPI, - cheNotification: CheNotification, - $location: ng.ILocationService, - $log: ng.ILogService, - $timeout: ng.ITimeoutService, - lodash: any, - $filter: ng.IFilterService, - $q: ng.IQService, - cheBranding: CheBranding, - confirmDialogService: ConfirmDialogService) { + cheAPI: CheAPI, + cheNotification: CheNotification, + $location: ng.ILocationService, + $log: ng.ILogService, + $timeout: ng.ITimeoutService, + lodash: any, + $filter: ng.IFilterService, + $q: ng.IQService, + cheBranding: CheBranding, + confirmDialogService: ConfirmDialogService) { this.cheAPI = cheAPI; this.cheNotification = cheNotification; this.$location = $location; diff --git a/dashboard/src/app/index.module.ts b/dashboard/src/app/index.module.ts index 12379e47c80..11a632f6ea4 100755 --- a/dashboard/src/app/index.module.ts +++ b/dashboard/src/app/index.module.ts @@ -27,7 +27,6 @@ import {WorkspacesConfig} from './workspaces/workspaces-config'; import {StacksConfig} from './stacks/stacks-config'; import {GetStartedConfig} from './get-started/get-started-config'; import {DemoComponentsController} from './demo-components/demo-components.controller'; -import {CheBranding} from '../components/branding/che-branding.factory'; import {ChePreferences} from '../components/api/che-preferences.factory'; import {RoutingRedirect} from '../components/routing/routing-redirect.factory'; import {RouteHistory} from '../components/routing/route-history.service'; @@ -36,15 +35,21 @@ import {OrganizationsConfig} from './organizations/organizations-config'; import {TeamsConfig} from './teams/teams-config'; import {ProfileConfig} from './profile/profile-config'; import {ResourceFetcherService} from '../components/service/resource-fetcher/resource-fetcher.service'; +import {CheBranding} from '../components/branding/che-branding'; // init module const initModule = angular.module('userDashboard', ['ngAnimate', 'ngCookies', 'ngTouch', 'ngSanitize', 'ngResource', 'ngRoute', 'angular-websocket', 'ui.bootstrap', 'ngMaterial', 'ngMessages', 'angularMoment', 'angular.filter', 'ngLodash', 'uuid4', 'angularFileUpload', 'ui.gravatar']); +// register singletons which can be used before resumeBootstrap +const cheBranding = CheBranding.get(); +initModule.constant('cheBranding', cheBranding); + window.name = 'NG_DEFER_BOOTSTRAP!'; declare const Keycloak: Function; + function buildKeycloakConfig(keycloakSettings: any): any { const theOidcProvider = keycloakSettings['che.keycloak.oidc_provider']; if (!theOidcProvider) { @@ -60,19 +65,31 @@ function buildKeycloakConfig(keycloakSettings: any): any { }; } } + interface IResolveFn { (value?: T | PromiseLike): void; } + interface IRejectFn { (reason?: any): void; } + function keycloakLoad(keycloakSettings: any) { return new Promise((resolve: IResolveFn, reject: IRejectFn) => { const script = document.createElement('script'); script.async = true; script.src = keycloakSettings['che.keycloak.js_adapter_url']; script.addEventListener('load', resolve); - script.addEventListener('error', () => reject('Error loading script.')); + script.addEventListener('error', () => { + return cheBranding.ready.then(() => { + reject(`
Certificate Error
+

Your Che host may be signed with a self-signed certificate. To resolve this issue, try these possible solutions:

+

1.) Import CA certificate info into your browser. You can find instructions on how to do this in you + Che documentation.

+

2.) Open the link for your Che host in a new tab and add an exclusion.

+
After trying each of these solutions, refresh your Dashboard to see if the problem has been resolved.
`); + }); + }); script.addEventListener('abort', () => reject('Script loading aborted.')); document.head.appendChild(script); }); @@ -124,16 +141,16 @@ function getApis(keycloak: any): Promise { if (xhr.status === 200) { resolve(); } else { - reject(xhr.responseText ? xhr.responseText : 'Unknown error'); + reject(xhr.responseText ? xhr.responseText : '
Unknown error
'); } }; }); }); } function showErrorMessage(errorMessage: string) { - const div = document.createElement('p'); - div.className = 'authorization-error'; - div.innerHTML = errorMessage + '
Click here to reload page.'; + const div = document.createElement('div'); + div.className = 'keycloak-error'; + div.innerHTML = errorMessage; document.querySelector('.main-page-loader').appendChild(div); } @@ -148,21 +165,27 @@ angular.element(document).ready(() => { const promise = new Promise((resolve: IResolveFn, reject: IRejectFn) => { angular.element.get('/api/keycloak/settings').then(resolve, reject); }); + let hasCertificateError = false; promise.then((keycloakSettings: any) => { keycloakAuth.config = buildKeycloakConfig(keycloakSettings); // load Keycloak return keycloakLoad(keycloakSettings).then(() => { // init Keycloak - let theUseNonce: boolean; + let theUseNonce = false; if (typeof keycloakSettings['che.keycloak.use_nonce'] === 'string') { theUseNonce = keycloakSettings['che.keycloak.use_nonce'].toLowerCase() === 'true'; } - let initOptions = { + const initOptions = { useNonce: theUseNonce, redirectUrl: keycloakSettings['che.keycloak.redirect_url.dashboard'] }; return keycloakInit(keycloakAuth.config, initOptions); + }).catch((error: any) => { + if (keycloakSettings['che.keycloak.js_adapter_url']) { + hasCertificateError = true; + } + return Promise.reject(error); }).then((keycloak: any) => { keycloakAuth.isPresent = true; keycloakAuth.keycloak = keycloak; @@ -171,6 +194,9 @@ angular.element(document).ready(() => { /* tslint:enable */ }); }).catch((error: any) => { + if (hasCertificateError) { + return Promise.reject(error); + } console.error('Keycloak initialization failed with error: ', error); }).then(() => { const keycloak = (window as any)._keycloak; @@ -178,9 +204,14 @@ angular.element(document).ready(() => { // to check if user is authorized to do that return getApis(keycloak); }).then(() => { - (angular as any).resumeBootstrap(); + cheBranding.ready.then(() => { + (angular as any).resumeBootstrap(); + }); }).catch((error: string) => { console.error(`Can't GET "/api". ${error ? 'Error: ' : ''}`, error); + if (!hasCertificateError) { + error = `${error}
Click here to reload page.
` + } showErrorMessage(error); }); }); @@ -195,7 +226,7 @@ initModule.config(['$routeProvider', ($routeProvider: che.route.IRouteProvider) if (angular.isUndefined(route.resolve)) { route.resolve = {}; } - (route.resolve as any).app = ['cheBranding', '$q', 'chePreferences', (cheBranding: CheBranding, $q: ng.IQService, chePreferences: ChePreferences) => { + (route.resolve as any).app = ['$q', 'chePreferences', ($q: ng.IQService, chePreferences: ChePreferences) => { const deferred = $q.defer(); if (chePreferences.getPreferences()) { deferred.resolve(); @@ -280,11 +311,11 @@ initModule.run([ routeHistory: RouteHistory, routingRedirect: RoutingRedirect, ) => { - $rootScope.hideLoader = false; $rootScope.waitingLoaded = false; $rootScope.showIDE = false; $rootScope.hideNavbar = false; + $rootScope.branding = cheBranding.all; // here only to create instances of these components /* tslint:disable */ diff --git a/dashboard/src/app/index.styl b/dashboard/src/app/index.styl index d9e7b6ccf22..bd9077edb8b 100644 --- a/dashboard/src/app/index.styl +++ b/dashboard/src/app/index.styl @@ -273,10 +273,46 @@ md-tabs-wrapper font-size 12px border-radius 2px -.authorization-error - color: $error-color +.keycloak-error font-weight: 600 - width: 100% - text-align: center + border-radius: 2px + font-size: 16px + color: $black-color + background-color: $white-color position: absolute top: 50% + left: 25%; + width: 50%; + transform: translate(0, -50%) + .error-header + display inline-block + margin 0 + padding 0 + width 100% + height 40px + line-height 40px + text-align center + vertical-align middle + border-radius 2px 2px 0 0 + color $white-color + background $error-color + span + font-size 22px + font-weight 600 + color inherit + a + float right + width 40px + color inherit + font-size 20px + text-align center + .error-body + border-radius 0 0 2px 2px + text-align center + color $black-color + background-color $white-color + margin 15px + p + text-align left + a + color $link-color diff --git a/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.controller.spec.ts b/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.controller.spec.ts index 84359510a63..918dfcf4232 100644 --- a/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.controller.spec.ts +++ b/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.controller.spec.ts @@ -10,11 +10,11 @@ * Red Hat, Inc. - initial API and implementation */ 'use strict'; -import {CheWorkspace} from '../../../components/api/workspace/che-workspace.factory'; -import {CheAPIBuilder} from '../../../components/api/builder/che-api-builder.factory'; -import {CheHttpBackend} from '../../../components/api/test/che-http-backend'; +import { CheWorkspace } from '../../../components/api/workspace/che-workspace.factory'; +import { CheAPIBuilder } from '../../../components/api/builder/che-api-builder.factory'; +import { CheHttpBackend } from '../../../components/api/test/che-http-backend'; import IdeSvc from '../../ide/ide.service'; -import {CheBranding} from '../../../components/branding/che-branding.factory'; +import { CheBranding } from '../../../components/branding/che-branding'; import { NavbarRecentWorkspacesController } from './recent-workspaces.controller'; /** @@ -59,7 +59,13 @@ describe('NavbarRecentWorkspacesController', () => { let scope = $rootScope.$new(); navbarRecentWorkspacesController = $controller('NavbarRecentWorkspacesController', { - ideSvc: IdeSvc, cheWorkspace: cheWorkspace, cheBranding: cheBranding, $window: $window, $log: $log, $scope: scope, $rootScope: $rootScope + ideSvc: IdeSvc, + cheWorkspace: cheWorkspace, + cheBranding: cheBranding, + $window: $window, + $log: $log, + $scope: scope, + $rootScope: $rootScope }); workspaces = []; @@ -68,7 +74,10 @@ describe('NavbarRecentWorkspacesController', () => { let wrkspName = 'testName' + i; let wrkspCreateDate = new Date(2001, 1, 1, i, 1).toString(); let wrkspUpdateDate = new Date(2001, 1, 1, i, 2).toString(); - let wrkspAttr = {'created': Date.parse(wrkspCreateDate), 'updated': Date.parse(wrkspUpdateDate)}; + let wrkspAttr = { + 'created': Date.parse(wrkspCreateDate), + 'updated': Date.parse(wrkspUpdateDate) + }; let workspace = apiBuilder.getWorkspaceBuilder().withId(wrkspId).withAttributes(wrkspAttr).withName(wrkspName).build(); workspaces.push(workspace); } @@ -101,40 +110,40 @@ describe('NavbarRecentWorkspacesController', () => { * Check sorting rule for recent workspaces */ it('Check very recent workspaces', inject(() => { - // get recentWorkspaces - let recentWorkspaces = navbarRecentWorkspacesController.getRecentWorkspaces(); - - // check max length - expect(recentWorkspaces.length).toEqual(navbarRecentWorkspacesController.maxItemsNumber); - - // prepare test objects - let testWorkspaces: Array = angular.copy(workspaces); - testWorkspaces.sort((workspace1: che.IWorkspace, workspace2: che.IWorkspace) => { - return workspace2.attributes.updated - workspace1.attributes.updated; - }); - let veryRecentWorkspaceId = testWorkspaces[testWorkspaces.length - 1].id; - - // check default sorting - let lastPosition = recentWorkspaces.length - 1; - for (let i = 0; i < lastPosition; i++) { - expect(recentWorkspaces[i].id).toEqual(testWorkspaces[i].id); - } - // check the last one workspace is equal to the last test workspace and not equal to the very recent workspace, - // because we are going to update very recent workspace in controller and sorting rule should be changed - expect(recentWorkspaces[lastPosition].id).toEqual(testWorkspaces[lastPosition].id); - expect(recentWorkspaces[lastPosition].id).not.toEqual(veryRecentWorkspaceId); - - // update very recent workspace - navbarRecentWorkspacesController.updateRecentWorkspace(veryRecentWorkspaceId); - recentWorkspaces = navbarRecentWorkspacesController.getRecentWorkspaces(); - - // check sorting with veryRecentWorkspace - for (let i = 0; i < lastPosition; i++) { - expect(recentWorkspaces[i].id).toEqual(testWorkspaces[i].id); - } - // check the last one workspace is equal to the very recent workspace and not equal to the last test workspace - expect(recentWorkspaces[lastPosition].id).not.toEqual(testWorkspaces[lastPosition].id); - expect(recentWorkspaces[lastPosition].id).toEqual(veryRecentWorkspaceId); - }) + // get recentWorkspaces + let recentWorkspaces = navbarRecentWorkspacesController.getRecentWorkspaces(); + + // check max length + expect(recentWorkspaces.length).toEqual(navbarRecentWorkspacesController.maxItemsNumber); + + // prepare test objects + let testWorkspaces: Array = angular.copy(workspaces); + testWorkspaces.sort((workspace1: che.IWorkspace, workspace2: che.IWorkspace) => { + return workspace2.attributes.updated - workspace1.attributes.updated; + }); + let veryRecentWorkspaceId = testWorkspaces[testWorkspaces.length - 1].id; + + // check default sorting + let lastPosition = recentWorkspaces.length - 1; + for (let i = 0; i < lastPosition; i++) { + expect(recentWorkspaces[i].id).toEqual(testWorkspaces[i].id); + } + // check the last one workspace is equal to the last test workspace and not equal to the very recent workspace, + // because we are going to update very recent workspace in controller and sorting rule should be changed + expect(recentWorkspaces[lastPosition].id).toEqual(testWorkspaces[lastPosition].id); + expect(recentWorkspaces[lastPosition].id).not.toEqual(veryRecentWorkspaceId); + + // update very recent workspace + navbarRecentWorkspacesController.updateRecentWorkspace(veryRecentWorkspaceId); + recentWorkspaces = navbarRecentWorkspacesController.getRecentWorkspaces(); + + // check sorting with veryRecentWorkspace + for (let i = 0; i < lastPosition; i++) { + expect(recentWorkspaces[i].id).toEqual(testWorkspaces[i].id); + } + // check the last one workspace is equal to the very recent workspace and not equal to the last test workspace + expect(recentWorkspaces[lastPosition].id).not.toEqual(testWorkspaces[lastPosition].id); + expect(recentWorkspaces[lastPosition].id).toEqual(veryRecentWorkspaceId); + }) ); }); diff --git a/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.controller.ts b/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.controller.ts index 2cf689ffc10..d3d567080d5 100644 --- a/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.controller.ts +++ b/dashboard/src/app/navbar/recent-workspaces/recent-workspaces.controller.ts @@ -12,7 +12,7 @@ 'use strict'; import { CheWorkspace } from '../../../components/api/workspace/che-workspace.factory'; import IdeSvc from '../../../app/ide/ide.service'; -import { CheBranding } from '../../../components/branding/che-branding.factory'; +import { CheBranding } from '../../../components/branding/che-branding'; import { WorkspacesService } from '../../workspaces/workspaces.service'; import { CheNotification } from '../../../components/notification/che-notification.factory'; import { WorkspaceDetailsService } from '../../workspaces/workspace-details/workspace-details.service'; diff --git a/dashboard/src/app/organizations/organizations-config.service.spec.ts b/dashboard/src/app/organizations/organizations-config.service.spec.ts index be0071215c2..5b571d673e8 100644 --- a/dashboard/src/app/organizations/organizations-config.service.spec.ts +++ b/dashboard/src/app/organizations/organizations-config.service.spec.ts @@ -10,9 +10,10 @@ * Red Hat, Inc. - initial API and implementation */ 'use strict'; -import {CheAPIBuilder} from '../../components/api/builder/che-api-builder.factory'; -import {CheHttpBackend} from '../../components/api/test/che-http-backend'; -import {OrganizationsConfigServiceMock} from './organizations-config.service.mock'; +import { CheAPIBuilder } from '../../components/api/builder/che-api-builder.factory'; +import { CheHttpBackend } from '../../components/api/test/che-http-backend'; +import { OrganizationsConfigServiceMock } from './organizations-config.service.mock'; +import { CheBranding } from '../../components/branding/che-branding'; /* tslint:disable:no-empty */ describe('OrganizationsConfig >', () => { @@ -23,12 +24,12 @@ describe('OrganizationsConfig >', () => { let $rootScope; - let $location; - let $httpBackend; let mock; + let setPath: (path: string) => void; + /** * Setup module */ @@ -49,11 +50,15 @@ describe('OrganizationsConfig >', () => { _cheAPIBuilder_: CheAPIBuilder ) => { $injector = _$injector_; - $location = _$location_; $route = _$route_; $rootScope = _$rootScope_; $httpBackend = _cheHttpBackend_.getHttpBackend(); + setPath = path => { + _$location_.path(path); + _$rootScope_.$digest(); + }; + mock = new OrganizationsConfigServiceMock(_cheAPIBuilder_, _cheHttpBackend_); mock.mockData(); })); @@ -83,7 +88,7 @@ describe('OrganizationsConfig >', () => { spyOn(callbacks, 'testResolve'); spyOn(callbacks, 'testReject'); - $location.path('/admin/create-organization'); + setPath('/admin/create-organization'); const service = $injector.invoke(resolveBlock); @@ -136,7 +141,7 @@ describe('OrganizationsConfig >', () => { spyOn(callbacks, 'testResolve').and.callThrough(); spyOn(callbacks, 'testReject'); - $location.path(`/admin/create-organization/${parentOrg.qualifiedName}`); + setPath(`/admin/create-organization/${parentOrg.qualifiedName}`); const service = $injector.invoke(resolveBlock); @@ -168,7 +173,7 @@ describe('OrganizationsConfig >', () => { spyOn(callbacks, 'testResolve'); spyOn(callbacks, 'testReject'); - $location.path(`/admin/create-organization/${parentOrg.qualifiedName}`); + setPath(`/admin/create-organization/${parentOrg.qualifiedName}`); // make response for organizations list fail $httpBackend.expect('GET', /\/api\/organization(\?.*$)?/).respond(500, [], {message: 'response failed'}); @@ -206,8 +211,7 @@ describe('OrganizationsConfig >', () => { spyOn(callbacks, 'testResolve'); spyOn(callbacks, 'testReject'); - $location.path(`/admin/create-organization/${fakeQualifiedName}`); - $rootScope.$digest(); + setPath(`/admin/create-organization/${fakeQualifiedName}`); const service = $injector.invoke(resolveBlock); @@ -252,7 +256,7 @@ describe('OrganizationsConfig >', () => { spyOn(callbacks, 'testResolve').and.callThrough(); spyOn(callbacks, 'testReject'); - $location.path(`/organization/${parentOrg.qualifiedName}`); + setPath(`/organization/${parentOrg.qualifiedName}`); const service = $injector.invoke(resolveBlock); @@ -287,7 +291,7 @@ describe('OrganizationsConfig >', () => { spyOn(callbacks, 'testResolve').and.callThrough(); spyOn(callbacks, 'testReject'); - $location.path(`/organization/${parentOrg.qualifiedName}`); + setPath(`/organization/${parentOrg.qualifiedName}`); // make response for organizations list fail $httpBackend.expect('GET', /\/api\/organization(\?.*$)?/).respond(500, [], {message: 'response failed'}); @@ -344,7 +348,7 @@ describe('OrganizationsConfig >', () => { spyOn(callbacks, 'testResolve').and.callThrough(); spyOn(callbacks, 'testReject'); - $location.path(`/organization/${subOrg.qualifiedName}`); + setPath(`/organization/${subOrg.qualifiedName}`); const service = $injector.invoke(resolveBlock); @@ -379,10 +383,10 @@ describe('OrganizationsConfig >', () => { spyOn(callbacks, 'testResolve').and.callThrough(); spyOn(callbacks, 'testReject'); - $location.path(`/organization/${subOrg.qualifiedName}`); + setPath(`/organization/${subOrg.qualifiedName}`); // make response for organizations list fail - $httpBackend.expect('GET', /\/api\/organization(\?.*$)?/).respond(500, [], {message: 'response failed'}); + $httpBackend.expect('GET', /\/api\/organization(\?.*$)?/).respond(500, [], { message: 'response failed' }); const service = $injector.invoke(resolveBlock); diff --git a/dashboard/src/app/organizations/organizations-config.service.ts b/dashboard/src/app/organizations/organizations-config.service.ts index 244a86ebaa1..270d1d2ac2f 100644 --- a/dashboard/src/app/organizations/organizations-config.service.ts +++ b/dashboard/src/app/organizations/organizations-config.service.ts @@ -333,11 +333,11 @@ export class OrganizationsConfigService { parentQualifiedNameDefer.resolve(this.$route.current.params.parentQualifiedName || ''); parentQualifiedNameDefer.promise.then((name: string) => { - if (name) { - return this.getOrFetchOrganizationByName(name); - } - return this.$q.reject('Cannot get parent for root organization'); + if (name) { + return this.getOrFetchOrganizationByName(name); } + return this.$q.reject('Cannot get parent for root organization'); + } ).then( /* resolve parent organization ID */ (organization: che.IOrganization) => { diff --git a/dashboard/src/app/workspaces/create-workspace/import-custom-stack/import-custom-stack.controller.ts b/dashboard/src/app/workspaces/create-workspace/import-custom-stack/import-custom-stack.controller.ts index da6799e2d71..e70bdd05fc8 100644 --- a/dashboard/src/app/workspaces/create-workspace/import-custom-stack/import-custom-stack.controller.ts +++ b/dashboard/src/app/workspaces/create-workspace/import-custom-stack/import-custom-stack.controller.ts @@ -18,7 +18,7 @@ import {NamespaceSelectorSvc} from '../ready-to-go-stacks/namespace-selector/nam import { CheKubernetesNamespace } from '../../../../components/api/che-kubernetes-namespace.factory'; import { CheWorkspace } from '../../../../components/api/workspace/che-workspace.factory'; import { CheDashboardConfigurationService } from '../../../../components/branding/che-dashboard-configuration.service'; -import { TogglableFeature } from '../../../../components/branding/che-branding.factory'; +import { TogglableFeature } from '../../../../components/branding/branding.constant'; /** * This class is handling the controller for stack importing directive. @@ -114,9 +114,7 @@ export class ImportStackController implements IImportStackScopeBindings { this.cheWorkspace.fetchWorkspaceSettings().then((settings: che.IWorkspaceSettings) => { this.ephemeralMode = settings['che.workspace.persist_volumes.default'] === 'false'; }); - this.cheDashboardConfigurationService.ready.then(() => { - this.enabledKubernetesNamespaceSelector = this.cheDashboardConfigurationService.enabledFeature(TogglableFeature.KUBERNETES_NAMESPACE_SELECTOR); - }); + this.enabledKubernetesNamespaceSelector = this.cheDashboardConfigurationService.enabledFeature(TogglableFeature.KUBERNETES_NAMESPACE_SELECTOR); } updateDevfileFromRemote(devfile: che.IWorkspaceDevfile, attrs: { factoryurl?: string } | undefined): void { diff --git a/dashboard/src/app/workspaces/create-workspace/ready-to-go-stacks/project-source-selector/add-import-project/import-github-project/import-github-project.controller.ts b/dashboard/src/app/workspaces/create-workspace/ready-to-go-stacks/project-source-selector/add-import-project/import-github-project/import-github-project.controller.ts index 0e4c40fe442..91a9519fa33 100644 --- a/dashboard/src/app/workspaces/create-workspace/ready-to-go-stacks/project-source-selector/add-import-project/import-github-project/import-github-project.controller.ts +++ b/dashboard/src/app/workspaces/create-workspace/ready-to-go-stacks/project-source-selector/add-import-project/import-github-project/import-github-project.controller.ts @@ -11,7 +11,7 @@ */ 'use strict'; -import { CheBranding } from '../../../../../../../components/branding/che-branding.factory'; +import { CheBranding } from '../../../../../../../components/branding/che-branding'; import { ImportGithubProjectService, LoadingState } from './import-github-project.service'; import { ProjectSource } from '../../project-source.enum'; import { IGithubRepository } from './github-repository-interface'; diff --git a/dashboard/src/app/workspaces/create-workspace/ready-to-go-stacks/ready-to-go-stacks.controller.ts b/dashboard/src/app/workspaces/create-workspace/ready-to-go-stacks/ready-to-go-stacks.controller.ts index 2d16b2dcad3..bd9f1cda23c 100644 --- a/dashboard/src/app/workspaces/create-workspace/ready-to-go-stacks/ready-to-go-stacks.controller.ts +++ b/dashboard/src/app/workspaces/create-workspace/ready-to-go-stacks/ready-to-go-stacks.controller.ts @@ -19,7 +19,7 @@ import { ProjectSourceSelectorService } from './project-source-selector/project- import { CheKubernetesNamespace } from '../../../../components/api/che-kubernetes-namespace.factory'; import { CheWorkspace } from '../../../../components/api/workspace/che-workspace.factory'; import { CheDashboardConfigurationService } from '../../../../components/branding/che-dashboard-configuration.service'; -import { TogglableFeature } from '../../../../components/branding/che-branding.factory'; +import { TogglableFeature } from '../../../../components/branding/branding.constant'; /** * This class is handling the controller for predefined stacks. @@ -138,9 +138,7 @@ export class ReadyToGoStacksController implements IReadyToGoStacksScopeBindings this.cheWorkspace.fetchWorkspaceSettings().then((settings: che.IWorkspaceSettings) => { this.ephemeralMode = settings['che.workspace.persist_volumes.default'] === 'false'; }); - this.cheDashboardConfigurationService.ready.then(() => { - this.enabledKubernetesNamespaceSelector = this.cheDashboardConfigurationService.enabledFeature(TogglableFeature.KUBERNETES_NAMESPACE_SELECTOR); - }); + this.enabledKubernetesNamespaceSelector = this.cheDashboardConfigurationService.enabledFeature(TogglableFeature.KUBERNETES_NAMESPACE_SELECTOR); } /** diff --git a/dashboard/src/app/workspaces/list-workspaces/list-workspaces.controller.ts b/dashboard/src/app/workspaces/list-workspaces/list-workspaces.controller.ts index fc20d9b477e..ccdf91c3a69 100644 --- a/dashboard/src/app/workspaces/list-workspaces/list-workspaces.controller.ts +++ b/dashboard/src/app/workspaces/list-workspaces/list-workspaces.controller.ts @@ -10,12 +10,12 @@ * Red Hat, Inc. - initial API and implementation */ 'use strict'; -import {CheAPI} from '../../../components/api/che-api.factory'; -import {CheNotification} from '../../../components/notification/che-notification.factory'; -import {CheWorkspace} from '../../../components/api/workspace/che-workspace.factory'; -import {CheNamespaceRegistry} from '../../../components/api/namespace/che-namespace-registry.factory'; -import {ConfirmDialogService} from '../../../components/service/confirm-dialog/confirm-dialog.service'; -import {CheBranding} from '../../../components/branding/che-branding.factory'; +import { CheAPI } from '../../../components/api/che-api.factory'; +import { CheNotification } from '../../../components/notification/che-notification.factory'; +import { CheWorkspace } from '../../../components/api/workspace/che-workspace.factory'; +import { CheNamespaceRegistry } from '../../../components/api/namespace/che-namespace-registry.factory'; +import { ConfirmDialogService } from '../../../components/service/confirm-dialog/confirm-dialog.service'; +import { CheBranding } from '../../../components/branding/che-branding'; /** * @ngdoc controller @@ -26,7 +26,7 @@ import {CheBranding} from '../../../components/branding/che-branding.factory'; export class ListWorkspacesCtrl { static $inject = ['$log', '$mdDialog', '$q', 'lodash', 'cheAPI', 'cheNotification', 'cheBranding', 'cheWorkspace', 'cheNamespaceRegistry', - 'confirmDialogService', '$scope', 'cheListHelperFactory']; + 'confirmDialogService', '$scope', 'cheListHelperFactory']; $q: ng.IQService; $log: ng.ILogService; @@ -46,7 +46,7 @@ export class ListWorkspacesCtrl { workspaceUsedResources: Map; isExactMatch: boolean = false; - namespaceFilter: {namespace: string}; + namespaceFilter: { namespace: string }; namespaceLabels: string[]; onFilterChanged: Function; onSearchChanged: Function; @@ -59,9 +59,9 @@ export class ListWorkspacesCtrl { * Default constructor that is using resource */ constructor($log: ng.ILogService, $mdDialog: ng.material.IDialogService, $q: ng.IQService, lodash: any, - cheAPI: CheAPI, cheNotification: CheNotification, cheBranding: CheBranding, - cheWorkspace: CheWorkspace, cheNamespaceRegistry: CheNamespaceRegistry, - confirmDialogService: ConfirmDialogService, $scope: ng.IScope, cheListHelperFactory: che.widget.ICheListHelperFactory) { + cheAPI: CheAPI, cheNotification: CheNotification, cheBranding: CheBranding, + cheWorkspace: CheWorkspace, cheNamespaceRegistry: CheNamespaceRegistry, + confirmDialogService: ConfirmDialogService, $scope: ng.IScope, cheListHelperFactory: che.widget.ICheListHelperFactory) { this.cheAPI = cheAPI; this.$q = $q; this.$log = $log; @@ -83,7 +83,7 @@ export class ListWorkspacesCtrl { this.state = 'loading'; this.isInfoLoading = true; this.isExactMatch = false; - this.namespaceFilter = {namespace: ''}; + this.namespaceFilter = { namespace: '' }; // map of all workspaces with additional info by id: this.workspacesById = new Map(); @@ -102,7 +102,7 @@ export class ListWorkspacesCtrl { }; // callback when namespace is changed - this.onFilterChanged = (label : string) => { + this.onFilterChanged = (label: string) => { if (label === this.ALL_NAMESPACES) { this.namespaceFilter.namespace = ''; } else { @@ -140,7 +140,7 @@ export class ListWorkspacesCtrl { return this.$q.reject(error); }).then(() => { this.cheListHelper.setList(this.userWorkspaces, 'id'); - }).finally(()=> { + }).finally(() => { this.isInfoLoading = false; }); } @@ -190,9 +190,9 @@ export class ListWorkspacesCtrl { let promise = stoppedStatusPromise.then(() => { return this.cheWorkspace.deleteWorkspace(workspace.id); }).then(() => { - this.workspacesById.delete(workspace.id); - queueLength--; - }, + this.workspacesById.delete(workspace.id); + queueLength--; + }, (error: any) => { isError = true; this.$log.error('Cannot delete workspace: ', error); diff --git a/dashboard/src/app/workspaces/list-workspaces/workspace-item/workspace-item.controller.ts b/dashboard/src/app/workspaces/list-workspaces/workspace-item/workspace-item.controller.ts index 7cbc260de86..3fa935e38e1 100644 --- a/dashboard/src/app/workspaces/list-workspaces/workspace-item/workspace-item.controller.ts +++ b/dashboard/src/app/workspaces/list-workspaces/workspace-item/workspace-item.controller.ts @@ -10,10 +10,10 @@ * Red Hat, Inc. - initial API and implementation */ 'use strict'; -import {CheWorkspace, WorkspaceStatus} from '../../../../components/api/workspace/che-workspace.factory'; -import {CheBranding} from '../../../../components/branding/che-branding.factory'; -import {WorkspacesService} from '../../workspaces.service'; -import {WorkspaceDataManager} from '../../../../components/api/workspace/workspace-data-manager'; +import { CheWorkspace, WorkspaceStatus } from '../../../../components/api/workspace/che-workspace.factory'; +import { CheBranding } from '../../../../components/branding/che-branding'; +import { WorkspacesService } from '../../workspaces.service'; +import { WorkspaceDataManager } from '../../../../components/api/workspace/workspace-data-manager'; const BLUR_TIMEOUT = 5000; @@ -128,7 +128,7 @@ export class WorkspaceItemCtrl { * @param tab {string} */ redirectToWorkspaceDetails(tab: string = 'Overview'): void { - this.$location.path(`/workspace/${this.workspace.namespace}/${this.workspaceName}`).search({tab}); + this.$location.path(`/workspace/${this.workspace.namespace}/${this.workspaceName}`).search({ tab }); } getMemoryLimit(): string { @@ -176,7 +176,7 @@ export class WorkspaceItemCtrl { } isCheckboxEnable(): boolean { - const status = WorkspaceStatus[this.getWorkspaceStatus()]; + const status = WorkspaceStatus[this.getWorkspaceStatus()]; return status === WorkspaceStatus.RUNNING || status === WorkspaceStatus.STOPPED; } } diff --git a/dashboard/src/app/workspaces/workspace-details/devfile/workspace-devfile-editor.controller.ts b/dashboard/src/app/workspaces/workspace-details/devfile/workspace-devfile-editor.controller.ts index e2e4450601b..5efcca46db8 100644 --- a/dashboard/src/app/workspaces/workspace-details/devfile/workspace-devfile-editor.controller.ts +++ b/dashboard/src/app/workspaces/workspace-details/devfile/workspace-devfile-editor.controller.ts @@ -11,7 +11,7 @@ */ 'use strict'; -import {CheBranding} from '../../../../components/branding/che-branding.factory'; +import { CheBranding } from '../../../../components/branding/che-branding'; import { CheAPI } from '../../../../components/api/che-api.factory'; /** @@ -154,14 +154,14 @@ export class WorkspaceDevfileEditorController { return; } - const devfile = jsyaml.safeLoad(this.devfileYaml); + const devfile = jsyaml.safeLoad(this.devfileYaml); Object.keys(this.workspaceDevfile).forEach((key: string) => { if (!devfile[key]) { delete this.workspaceDevfile[key]; } }); angular.extend(this.workspaceDevfile, devfile); - this.workspaceDevfileOnChange({devfile}); + this.workspaceDevfileOnChange({ devfile }); }, 500); } diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-details.controller.ts b/dashboard/src/app/workspaces/workspace-details/workspace-details.controller.ts index 93364c80564..c6093f8906a 100644 --- a/dashboard/src/app/workspaces/workspace-details/workspace-details.controller.ts +++ b/dashboard/src/app/workspaces/workspace-details/workspace-details.controller.ts @@ -10,15 +10,15 @@ * Red Hat, Inc. - initial API and implementation */ 'use strict'; -import {CheWorkspace, WorkspaceStatus} from '../../../components/api/workspace/che-workspace.factory'; -import {CheNotification} from '../../../components/notification/che-notification.factory'; -import {WorkspaceDetailsService} from './workspace-details.service'; -import {WorkspacesService} from '../workspaces.service'; -import {ICheEditModeOverlayConfig} from '../../../components/widget/edit-mode-overlay/che-edit-mode-overlay.directive'; -import {CheBranding} from '../../../components/branding/che-branding.factory'; -import {WorkspaceDataManager} from '../../../components/api/workspace/workspace-data-manager'; - -export interface IInitData { +import { CheWorkspace, WorkspaceStatus } from '../../../components/api/workspace/che-workspace.factory'; +import { CheNotification } from '../../../components/notification/che-notification.factory'; +import { WorkspaceDetailsService } from './workspace-details.service'; +import { WorkspacesService } from '../workspaces.service'; +import { ICheEditModeOverlayConfig } from '../../../components/widget/edit-mode-overlay/che-edit-mode-overlay.directive'; +import { CheBranding } from '../../../components/branding/che-branding'; +import { WorkspaceDataManager } from '../../../components/api/workspace/workspace-data-manager'; + +export interface IInitData { namespaceId: string; workspaceName: string; workspaceDetails: che.IWorkspace; diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-details.service.ts b/dashboard/src/app/workspaces/workspace-details/workspace-details.service.ts index 80bb4ac2b8b..8bb2657c0e6 100644 --- a/dashboard/src/app/workspaces/workspace-details/workspace-details.service.ts +++ b/dashboard/src/app/workspaces/workspace-details/workspace-details.service.ts @@ -20,7 +20,7 @@ import {PluginRegistry} from '../../../components/api/plugin-registry.factory'; import {WorkspaceDataManager} from '../../../components/api/workspace/workspace-data-manager'; import { ConfirmDialogService } from '../../../components/service/confirm-dialog/confirm-dialog.service'; import { CheDashboardConfigurationService } from '../../../components/branding/che-dashboard-configuration.service'; -import { TogglableFeature } from '../../../components/branding/che-branding.factory'; +import { TogglableFeature } from '../../../components/branding/branding.constant'; interface IPage { title: string; diff --git a/dashboard/src/app/workspaces/workspace-details/workspace-overview/workspace-details-overview.controller.ts b/dashboard/src/app/workspaces/workspace-details/workspace-overview/workspace-details-overview.controller.ts index e850e223dab..0165bde10a4 100644 --- a/dashboard/src/app/workspaces/workspace-details/workspace-overview/workspace-details-overview.controller.ts +++ b/dashboard/src/app/workspaces/workspace-details/workspace-overview/workspace-details-overview.controller.ts @@ -17,7 +17,7 @@ import {NamespaceSelectorSvc} from '../../create-workspace/ready-to-go-stacks/na import {WorkspaceDetailsService} from '../workspace-details.service'; import { CheKubernetesNamespace } from '../../../../components/api/che-kubernetes-namespace.factory'; import { CheDashboardConfigurationService } from '../../../../components/branding/che-dashboard-configuration.service'; -import { TogglableFeature } from '../../../../components/branding/che-branding.factory'; +import { TogglableFeature } from '../../../../components/branding/branding.constant'; const STARTING = WorkspaceStatus[WorkspaceStatus.STARTING]; const RUNNING = WorkspaceStatus[WorkspaceStatus.RUNNING]; @@ -128,9 +128,7 @@ export class WorkspaceDetailsOverviewController { deRegistrationFn(); }); - this.cheDashboardConfigurationService.ready.then(() => { - this.enabledKubernetesNamespaceSelector = this.cheDashboardConfigurationService.enabledFeature(TogglableFeature.KUBERNETES_NAMESPACE_SELECTOR); - }); + this.enabledKubernetesNamespaceSelector = this.cheDashboardConfigurationService.enabledFeature(TogglableFeature.KUBERNETES_NAMESPACE_SELECTOR); this.init(); } diff --git a/dashboard/src/assets/branding/product.json b/dashboard/src/assets/branding/product.json index a65158e886b..44760f51648 100644 --- a/dashboard/src/assets/branding/product.json +++ b/dashboard/src/assets/branding/product.json @@ -11,19 +11,25 @@ "supportEmail": "che-dev@eclipse.org", "oauthDocs": "Configure OAuth in the che.properties file.", "workspace": { - "priorityStacks": ["Java", "Java-MySQL", "Blank"], - "defaultStack": "java-mysql" + "priorityStacks": [ + "Java", + "Java-MySQL", + "Blank" + ], + "defaultStack": "java-mysql", + "creationLink": "#/create-workspace" }, - "cli" : { - "configName" : "che.env", - "name" : "CHE" + "cli": { + "configName": "che.env", + "name": "CHE" }, - "docs" : { - "devfile" : "/docs/che-7/using-developer-environments-workspaces.html#making-a-workspace-portable-using-a-devfile_using-developer-environments-workspaces", - "workspace" : "/docs/che-7/workspaces-overview/", - "factory" : "/docs/factories-getting-started.html", + "docs": { + "devfile": "/docs/che-7/using-developer-environments-workspaces.html#making-a-workspace-portable-using-a-devfile_using-developer-environments-workspaces", + "workspace": "/docs/che-7/workspaces-overview/", + "factory": "/docs/factories-getting-started.html", "organization": "/docs/organizations.html", "converting": "/docs/che-7/converting-a-che-6-workspace-to-a-che-7-devfile/", + "certificate": "/docs/che-7/setup-che-in-tls-mode-with-self-signed-certificate/", "general": "/docs/che-7" } -} +} \ No newline at end of file diff --git a/dashboard/src/components/api/che-service.factory.ts b/dashboard/src/components/api/che-service.factory.ts index d7cde6d630f..eb8107544bc 100644 --- a/dashboard/src/components/api/che-service.factory.ts +++ b/dashboard/src/components/api/che-service.factory.ts @@ -17,7 +17,7 @@ */ export class CheService { - static $inject = ['$http']; + static $inject = ['$http', '$rootScope']; /** * Service for performing HTTP requests. @@ -32,21 +32,22 @@ export class CheService { /** * Information about services. */ - private servicesInfo: any; + private servicesInfo: { [propName: string]: string; } = {}; /** * Default constructor that is using resource */ - constructor ($http: ng.IHttpService) { + constructor($http: ng.IHttpService, $rootScope: ng.IRootScopeService) { this.$http = $http; this.fetchServices(); + this.fetchServicesInfo().then(() => { + ($rootScope as any).productVersion = this.servicesInfo.buildInfo || ''; + }); } /** * Fetches all available services. - * - * @returns {ng.IPromise} */ fetchServices(): ng.IPromise { if (this.servicesPromise) { @@ -68,7 +69,6 @@ export class CheService { /** * Checks whether service is available. * @param name service name - * @returns {Boolean|*} */ isServiceAvailable(name: string): boolean { if (!this.services) { @@ -84,7 +84,7 @@ export class CheService { * @returns {IHttpPromise} */ fetchServicesInfo(): ng.IPromise { - let promise = this.$http({'method': 'OPTIONS', 'url': '/api/'}); + let promise = this.$http({ 'method': 'OPTIONS', 'url': '/api/' }); let infoPromise = promise.then((response: any) => { this.servicesInfo = response.data; }); @@ -93,10 +93,8 @@ export class CheService { /** * Returns services information. - * - * @returns {any} servies information */ - getServicesInfo(): any { + getServicesInfo(): { [propName: string]: string; } { return this.servicesInfo; } } diff --git a/dashboard/src/components/api/workspace/che-workspace.factory.ts b/dashboard/src/components/api/workspace/che-workspace.factory.ts index 4f6972ac07a..17775362134 100644 --- a/dashboard/src/components/api/workspace/che-workspace.factory.ts +++ b/dashboard/src/components/api/workspace/che-workspace.factory.ts @@ -11,12 +11,12 @@ */ 'use strict'; -import {CheJsonRpcMasterApi} from '../json-rpc/che-json-rpc-master-api'; -import {CheJsonRpcApi} from '../json-rpc/che-json-rpc-api.factory'; -import {IObservableCallbackFn, Observable} from '../../utils/observable'; -import {CheBranding} from '../../branding/che-branding.factory'; -import {CheNotification} from '../../notification/che-notification.factory'; -import {WorkspaceDataManager} from './workspace-data-manager'; +import { CheJsonRpcMasterApi } from '../json-rpc/che-json-rpc-master-api'; +import { CheJsonRpcApi } from '../json-rpc/che-json-rpc-api.factory'; +import { IObservableCallbackFn, Observable } from '../../utils/observable'; +import { CheBranding } from '../../branding/che-branding'; +import { CheNotification } from '../../notification/che-notification.factory'; +import { WorkspaceDataManager } from './workspace-data-manager'; interface ICHELicenseResource extends ng.resource.IResourceClass { createDevfile: any; @@ -98,16 +98,16 @@ export class CheWorkspace { * Default constructor that is using resource */ constructor($resource: ng.resource.IResourceService, - $http: ng.IHttpService, - $q: ng.IQService, - cheJsonRpcApi: CheJsonRpcApi, - cheNotification: CheNotification, - $websocket: any, - $location: ng.ILocationService, - proxySettings: string, - userDashboardConfig: any, - lodash: any, - cheBranding: CheBranding + $http: ng.IHttpService, + $q: ng.IQService, + cheJsonRpcApi: CheJsonRpcApi, + cheNotification: CheNotification, + $websocket: any, + $location: ng.ILocationService, + proxySettings: string, + userDashboardConfig: any, + lodash: any, + cheBranding: CheBranding ) { this.$q = $q; this.$resource = $resource; @@ -135,26 +135,20 @@ export class CheWorkspace { // remote call this.remoteWorkspaceAPI = >this.$resource('/api/workspace', {}, { - createDevfile: {method: 'POST', url: '/api/workspace/devfile'}, - deleteWorkspace: {method: 'DELETE', url: '/api/workspace/:workspaceId'}, - updateWorkspace: {method: 'PUT', url: '/api/workspace/:workspaceId'}, - addProject: {method: 'POST', url: '/api/workspace/:workspaceId/project'}, - deleteProject: {method: 'DELETE', url: '/api/workspace/:workspaceId/project/:path'}, - stopWorkspace: {method: 'DELETE', url: '/api/workspace/:workspaceId/runtime'}, - startWorkspace: {method: 'POST', url: '/api/workspace/:workspaceId/runtime?environment=:envName'}, - startWorkspaceWithNoEnvironment: {method: 'POST', url: '/api/workspace/:workspaceId/runtime'}, - startTemporaryWorkspace: {method: 'POST', url: '/api/workspace/runtime?temporary=true'}, - getSettings: {method: 'GET', url: '/api/workspace/settings'} - } + createDevfile: { method: 'POST', url: '/api/workspace/devfile' }, + deleteWorkspace: { method: 'DELETE', url: '/api/workspace/:workspaceId' }, + updateWorkspace: { method: 'PUT', url: '/api/workspace/:workspaceId' }, + addProject: { method: 'POST', url: '/api/workspace/:workspaceId/project' }, + deleteProject: { method: 'DELETE', url: '/api/workspace/:workspaceId/project/:path' }, + stopWorkspace: { method: 'DELETE', url: '/api/workspace/:workspaceId/runtime' }, + startWorkspace: { method: 'POST', url: '/api/workspace/:workspaceId/runtime?environment=:envName' }, + startWorkspaceWithNoEnvironment: { method: 'POST', url: '/api/workspace/:workspaceId/runtime' }, + startTemporaryWorkspace: { method: 'POST', url: '/api/workspace/runtime?temporary=true' }, + getSettings: { method: 'GET', url: '/api/workspace/settings' } + } ); - - const CONTEXT_FETCHER_ID = 'websocketContextFetcher'; - const callback = () => { - this.jsonRpcApiLocation = this.formJsonRpcApiLocation($location, proxySettings, userDashboardConfig.developmentMode) + cheBranding.getWebsocketContext(); - this.cheJsonRpcMasterApi = cheJsonRpcApi.getJsonRpcMasterApi(this.jsonRpcApiLocation); - cheBranding.unregisterCallback(CONTEXT_FETCHER_ID); - }; - cheBranding.registerCallback(CONTEXT_FETCHER_ID, callback.bind(this)); + this.jsonRpcApiLocation = this.formJsonRpcApiLocation($location, proxySettings, userDashboardConfig.developmentMode) + cheBranding.getWebsocketContext(); + this.cheJsonRpcMasterApi = cheJsonRpcApi.getJsonRpcMasterApi(this.jsonRpcApiLocation); this.checkWorkspaceLoader(userDashboardConfig.developmentMode, proxySettings); } @@ -285,7 +279,7 @@ export class CheWorkspace { * If there are no changes, it's not updated */ fetchWorkspaces(): ng.IPromise> { - const promise = this.remoteWorkspaceAPI.query({'maxItems': 256}).$promise; + const promise = this.remoteWorkspaceAPI.query({ 'maxItems': 256 }).$promise; return promise.then((workspaces: Array) => { this.workspaceIds.length = 0; @@ -380,7 +374,7 @@ export class CheWorkspace { * @returns {ng.IPromise} */ addProject(workspaceId: string, project: che.IProject): ng.IPromise { - return this.remoteWorkspaceAPI.addProject({workspaceId: workspaceId}, project).$promise; + return this.remoteWorkspaceAPI.addProject({ workspaceId: workspaceId }, project).$promise; } /** @@ -390,7 +384,7 @@ export class CheWorkspace { * @returns {ng.IPromise} */ deleteProject(workspaceId: string, path: string): ng.IPromise { - return this.remoteWorkspaceAPI.deleteProject({workspaceId: workspaceId, path: path}).$promise; + return this.remoteWorkspaceAPI.deleteProject({ workspaceId: workspaceId, path: path }).$promise; } createWorkspaceFromDevfile(cheNamespaceId: string, infrastructureNamespaceId: string, devfile: che.IWorkspaceDevfile, attributes: any): ng.IPromise { @@ -417,7 +411,10 @@ export class CheWorkspace { return this.workspacePromises.get(workspacePromisesKey); } - const promise = envName ? this.remoteWorkspaceAPI.startWorkspace({workspaceId: workspaceId, envName: envName}, {}).$promise : this.remoteWorkspaceAPI.startWorkspaceWithNoEnvironment({workspaceId: workspaceId}, {}).$promise; + const promise = envName ? this.remoteWorkspaceAPI.startWorkspace({ + workspaceId: workspaceId, + envName: envName + }, {}).$promise : this.remoteWorkspaceAPI.startWorkspaceWithNoEnvironment({ workspaceId: workspaceId }, {}).$promise; this.workspacePromises.set(workspacePromisesKey, promise); promise.finally(() => { this.workspacePromises.delete(workspacePromisesKey); @@ -475,7 +472,7 @@ export class CheWorkspace { * @param data {che.IWorkspace} the new workspace details */ updateWorkspace(workspaceId: string, data: che.IWorkspace): ng.IPromise { - const promise = this.remoteWorkspaceAPI.updateWorkspace({workspaceId: workspaceId}, data).$promise; + const promise = this.remoteWorkspaceAPI.updateWorkspace({ workspaceId: workspaceId }, data).$promise; return promise.then(data => { this.updateWorkspacesList(data); @@ -496,7 +493,7 @@ export class CheWorkspace { */ deleteWorkspace(workspaceId: string): ng.IPromise { let defer = this.$q.defer(); - let promise = this.remoteWorkspaceAPI.deleteWorkspace({workspaceId: workspaceId}).$promise; + let promise = this.remoteWorkspaceAPI.deleteWorkspace({ workspaceId: workspaceId }).$promise; promise.then(() => { const onDeleteHandlers = this.handlers['onDeleteWorkspace']; if (onDeleteHandlers) { @@ -613,6 +610,7 @@ export class CheWorkspace { return this.$q.reject(error); }); } + /** * Returns the system settings for workspaces. * @@ -679,7 +677,7 @@ export class CheWorkspace { let url = '/workspace-loader/'; let promise = this.$http.get(url); - promise.then((response: {data: any}) => { + promise.then((response: { data: any }) => { this.workspaceLoaderUrl = devmode ? proxySettings + url : url; }, (error: any) => { if (error.status !== 304) { diff --git a/dashboard/src/components/branding/branding.constant.ts b/dashboard/src/components/branding/branding.constant.ts new file mode 100644 index 00000000000..ce8e6384e87 --- /dev/null +++ b/dashboard/src/components/branding/branding.constant.ts @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2015-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +'use strict'; + +export type IBranding = { + title: string, + name: string, + logoFile: string, + logoTextFile: string, + favicon: string, + loader: string, + websocketContext: string, + helpPath: string, + helpTitle: string, + supportEmail: string, + oauthDocs: string, + cli: { + configName: string; + name: string; + }, + docs: IBrandingDocs, + workspace: IBrandingWorkspace, + footer: IBrandingFooter, + configuration: IBrandingConfiguration, +} + +export type IBrandingDocs = { + devfile: string, + workspace: string, + factory: string, + organization: string, + general: string, + converting: string, + certificate: string, + faq?: string, +} + +export type IBrandingWorkspace = { + priorityStacks: Array, + defaultStack: string, + creationLink: string +} + +export type IBrandingFooter = { + content: string, + links: Array<{ title: string, location: string }>, + email: { title: string, address: string, subject: string } | null +} + +export type IBrandingConfiguration = { + menu: { + disabled: che.ConfigurableMenuItem[]; + }, + prefetch: { + cheCDN?: string; + resources: string[]; + }, + features: { + disabled: TogglableFeature[]; + } +} + +export enum TogglableFeature { + WORKSPACE_SHARING = 'workspaceSharing', + KUBERNETES_NAMESPACE_SELECTOR = 'kubernetesNamespaceSelector', +} + +export const BRANDING_DEFAULT: IBranding = { + title: 'Eclipse Che 456456', + name: 'Eclipse Che', + logoFile: 'che-logo456456.svg', + logoTextFile: 'che-logo-text.svg', + favicon: 'favicon.ico', + loader: 'loader.svg', + websocketContext: '/api/websocket', + helpPath: 'https://www.eclipse.org/che/', + helpTitle: 'Community', + supportEmail: 'che-dev@eclipse.org', + oauthDocs: 'Configure OAuth in the che.properties file.', + workspace: { + priorityStacks: [ + 'Java', + 'Java-MySQL', + 'Blank' + ], + defaultStack: 'java-mysql', + creationLink: '#/create-workspace' + }, + cli: { + configName: 'che.env', + name: 'CHE' + }, + docs: { + devfile: '/docs/che-7/using-developer-environments-workspaces.html#making-a-workspace-portable-using-a-devfile_using-developer-environments-workspaces', + workspace: '/docs/che-7/workspaces-overview/', + factory: '/docs/factories-getting-started.html', + organization: '/docs/organizations.html', + converting: '/docs/che-7/converting-a-che-6-workspace-to-a-che-7-devfile/', + certificate: '/docs/che-7/setup-che-in-tls-mode-with-self-signed-certificate/', + general: '/docs/che-7' + }, + configuration: { + menu: { + disabled: [] + }, + features: { + disabled: [] + }, + prefetch: { + resources: [] + } + }, + footer: { + content: '', + links: [], + email: null + } +}; diff --git a/dashboard/src/components/branding/che-branding-config.ts b/dashboard/src/components/branding/che-branding-config.ts index fd5bd08915e..f2321d9d2e5 100644 --- a/dashboard/src/components/branding/che-branding-config.ts +++ b/dashboard/src/components/branding/che-branding-config.ts @@ -11,14 +11,11 @@ */ 'use strict'; -import {CheBranding} from './che-branding.factory'; import { CheDashboardConfigurationService } from './che-dashboard-configuration.service'; export class CheBrandingConfig { constructor(register: che.IRegisterService) { - // register this factory - register.factory('cheBranding', CheBranding); register.service('cheDashboardConfigurationService', CheDashboardConfigurationService); } diff --git a/dashboard/src/components/branding/che-branding.factory.ts b/dashboard/src/components/branding/che-branding.factory.ts deleted file mode 100644 index ee304d1c6d0..00000000000 --- a/dashboard/src/components/branding/che-branding.factory.ts +++ /dev/null @@ -1,385 +0,0 @@ -/* - * Copyright (c) 2015-2018 Red Hat, Inc. - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Red Hat, Inc. - initial API and implementation - */ -'use strict'; -import {CheService} from '../api/che-service.factory'; - -interface IBranding { - title?: string; - name?: string; - logoFile?: string; - logoTextFile?: string; - favicon?: string; - loader?: string; - websocketContext?: string; - helpPath?: string; - helpTitle?: string; - supportEmail?: string; - oauthDocs?: string; - cli?: { - configName?: string; - name?: string; - }; - docs?: IBrandingDocs; - workspace?: IBrandingWorkspace; - footer?: IBrandingFooter; - configuration?: IBrandingConfiguration; -} - -interface IBrandingDocs { - devfile?: string; - workspace?: string; - factory?: string; - organization?: string; - general?: string; - converting?: string; - faq?: string; -} -interface IBrandingWorkspace { - priorityStacks?: Array; - defaultStack?: string; - creationLink?: string; -} -interface IBrandingFooter { - content?: string; - links?: Array<{ title: string, location: string }>; - email?: { title: string, address: string, subject: string }; -} -interface IBrandingConfiguration { - menu: { - disabled: che.ConfigurableMenuItem[]; - }; - prefetch: { - cheCDN: string; - resources: string[]; - }; - features: { - disabled: TogglableFeature[]; - }; -} - -export enum TogglableFeature { - WORKSPACE_SHARING = 'workspaceSharing', - KUBERNETES_NAMESPACE_SELECTOR = 'kubernetesNamespaceSelector', -} - -const ASSET_PREFIX = 'assets/branding/'; -const DEFAULT_PRODUCT_NAME = 'Eclipse Che'; -const DEFAULT_NAME = 'Eclipse Che'; -const DEFAULT_PRODUCT_FAVICON = 'favicon.ico'; -const DEFAULT_LOADER = 'loader.svg'; -const DEFAULT_PRODUCT_LOGO = 'che-logo.svg'; -const DEFAULT_PRODUCT_LOGO_TEXT = 'che-logo-text.svg'; -const DEFAULT_OAUTH_DOCS = 'Configure OAuth in the che.properties file.'; -const DEFAULT_CLI_NAME = 'che.env'; -const DEFAULT_CLI_CONFIG_NAME = 'CHE'; -const DEFAULT_DOCS_DEVFILE = '/docs/che-7/making-a-workspace-portable-using-a-devfile/'; -const DEFAULT_DOCS_WORKSPACE = '/docs/che-7/workspaces-overview/'; -const DEFAULT_DOCS_ORGANIZATION = '/docs/organizations.html'; -const DEFAULT_DOCS_FACTORY = '/docs/factories-getting-started.html'; -const DEFAULT_DOCS_GENERAL = '/docs/che-7'; -const DEFAULT_DOCS_CONVERTING = '/docs/che-7/converting-a-che-6-workspace-to-a-che-7-devfile/'; -const DEFAULT_WORKSPACE_PRIORITY_STACKS = ['Java', 'Java-MySQL', 'Blank']; -const DEFAULT_WORKSPACE_DEFAULT_STACK = 'java-mysql'; -const DEFAULT_WORKSPACE_CREATION_LINK = '#/create-workspace'; -const DEFAULT_WEBSOCKET_CONTEXT = '/api/websocket'; - -/** - * This class is handling the branding data in Che. - * @author Florent Benoit - * @author Oleksii Orel - */ -export class CheBranding { - - static $inject = [ - '$http', - '$q', - '$rootScope', - 'cheService' - ]; - - private $http: ng.IHttpService; - private $q: ng.IQService; - private $rootScope: che.IRootScopeService; - private cheService: CheService; - - private branding: IBranding; - private callbacks: Map = new Map(); - private _readyDeferred: ng.IDeferred; - - /** - * Default constructor that is using resource - */ - constructor( - $http: ng.IHttpService, - $q: ng.IQService, - $rootScope: che.IRootScopeService, - cheService: CheService - ) { - this.$http = $http; - this.$q = $q; - this.$rootScope = $rootScope; - this.cheService = cheService; - - this.branding = {}; - this._readyDeferred = this.$q.defer(); - - this.initialize(); - this.updateData(); - this.updateVersion(); - } - - get ready(): ng.IPromise { - return this._readyDeferred.promise; - } - - initialize(): void { - this.$rootScope.branding = { - title: this.getProductName(), - name: this.getName(), - logoURL: this.getProductLogo(), - logoText: this.getProductLogoText(), - favicon: this.getProductFavicon(), - loaderURL: this.getLoaderUrl(), - websocketContext: this.getWebsocketContext(), - helpPath: this.getProductHelpPath(), - helpTitle: this.getProductHelpTitle(), - footer: this.getFooter(), - supportEmail: this.getProductSupportEmail(), - oauthDocs: this.getOauthDocs(), - cli: this.getCLI(), - docs: this.getDocs(), - workspace: this.getWorkspace(), - configuration: this.getConfiguration(), - }; - } - - /** - * Update product version. - */ - updateVersion(): void { - this.cheService.fetchServicesInfo().then(() => { - let info = this.cheService.getServicesInfo(); - this.$rootScope.productVersion = (info && info.buildInfo) ? info.buildInfo : ''; - }); - } - - /** - * Update branding data. - */ - updateData(): void { - this.$http.get(ASSET_PREFIX + 'product.json').then(res => res.data).then((branding: IBranding) => { - this.branding = branding; - this.initialize(); - this.callbacks.forEach(callback => { - if (angular.isFunction(callback)) { - callback(this.$rootScope.branding); - } - }); - this._readyDeferred.resolve(); - }); - } - - /** - * Registers a callback function. - * @param callbackId {string} - * @param callback {Function} - */ - registerCallback(callbackId: string, callback: Function): void { - this.callbacks.set(callbackId, callback); - if (Object.keys(this.branding).length !== 0) { - callback(this.$rootScope.branding); - } - } - - /** - * Unregisters the callback function by Id. - * @param callbackId {string} - */ - unregisterCallback(callbackId: string): void { - if (!this.callbacks.has(callbackId)) { - return; - } - this.callbacks.delete(callbackId); - } - - /** - * Gets name. - * @returns {string} - */ - getName(): string { - return this.branding.name ? this.branding.name : DEFAULT_NAME; - } - - /** - * Gets product name. - * @returns {string} - */ - getProductName(): string { - return this.branding.title ? this.branding.title : DEFAULT_PRODUCT_NAME; - } - - /** - * Gets product logo. - * @returns {string} - */ - getProductLogo(): string { - return this.branding.logoFile ? ASSET_PREFIX + this.branding.logoFile : ASSET_PREFIX + DEFAULT_PRODUCT_LOGO; - } - - /** - * Gets product favicon. - * @returns {string} - */ - getProductFavicon(): string { - return this.branding.favicon ? ASSET_PREFIX + this.branding.favicon : ASSET_PREFIX + DEFAULT_PRODUCT_FAVICON; - } - - /** - * Gets product loader. - * @returns {string} - */ - getLoaderUrl(): string { - return this.branding.loader ? ASSET_PREFIX + this.branding.loader : ASSET_PREFIX + DEFAULT_LOADER; - } - - /** - * Gets ide resources path. - * @returns {string} - */ - getWebsocketContext(): string { - return this.branding.websocketContext ? this.branding.websocketContext : DEFAULT_WEBSOCKET_CONTEXT; - } - - /** - * Gets product help path. - * @returns {string} - */ - getProductHelpPath(): string { - return this.branding.helpPath ? this.branding.helpPath : null; - } - - /** - * Gets product help title. - * @returns {string} - */ - getProductHelpTitle(): string { - return this.branding.helpTitle ? this.branding.helpTitle : null; - } - - /** - * Gets product logo text. - * @returns {string} - */ - getProductLogoText(): string { - return this.branding.logoTextFile ? ASSET_PREFIX + this.branding.logoTextFile : ASSET_PREFIX + DEFAULT_PRODUCT_LOGO_TEXT; - } - - /** - * Gets oauth docs. - * @returns {string} - */ - getOauthDocs(): string { - return this.branding.oauthDocs ? this.branding.oauthDocs : DEFAULT_OAUTH_DOCS; - } - - /** - * Gets product support email. - * @returns {string} - */ - getProductSupportEmail(): string { - return this.branding.supportEmail ? this.branding.supportEmail : null; - } - - /** - * Returns footer additional elements (email button, content, button links). - */ - getFooter(): IBrandingFooter { - return { - content: this.branding.footer && this.branding.footer.content ? this.branding.footer.content : '', - links: this.branding.footer && this.branding.footer.links ? this.branding.footer.links : [], - email: this.branding.footer && this.branding.footer.email ? this.branding.footer.email : null - }; - } - - /** - * Returns object with configName and name. - */ - getCLI(): { configName: string; name: string } { - return { - configName: this.branding.cli && this.branding.cli.configName ? this.branding.cli.configName : DEFAULT_CLI_CONFIG_NAME, - name: this.branding.cli && this.branding.cli.name ? this.branding.cli.name : DEFAULT_CLI_NAME - }; - } - - /** - * Returns object with docs URLs. - */ - getDocs(): IBrandingDocs { - return { - devfile: this.branding.docs && this.branding.docs.devfile ? this.branding.docs.devfile : DEFAULT_DOCS_DEVFILE, - workspace: this.branding.docs && this.branding.docs.workspace ? this.branding.docs.workspace : DEFAULT_DOCS_WORKSPACE, - factory: this.branding.docs && this.branding.docs.factory ? this.branding.docs.factory : DEFAULT_DOCS_FACTORY, - organization: this.branding.docs && this.branding.docs.organization ? this.branding.docs.organization : DEFAULT_DOCS_ORGANIZATION, - general: this.branding.docs && this.branding.docs.general ? this.branding.docs.general : DEFAULT_DOCS_GENERAL, - converting: this.branding.docs && this.branding.docs.converting ? this.branding.docs.converting : DEFAULT_DOCS_CONVERTING, - faq: this.branding.docs && this.branding.docs.faq ? this.branding.docs.faq : undefined - }; - } - - /** - * Returns object with workspace dedicated data. - */ - getWorkspace(): IBrandingWorkspace { - return { - priorityStacks: this.branding.workspace && this.branding.workspace.priorityStacks ? this.branding.workspace.priorityStacks : DEFAULT_WORKSPACE_PRIORITY_STACKS, - defaultStack: this.branding.workspace && this.branding.workspace.defaultStack ? this.branding.workspace.defaultStack : DEFAULT_WORKSPACE_DEFAULT_STACK, - creationLink: this.branding.workspace && this.branding.workspace.creationLink ? this.branding.workspace.creationLink : DEFAULT_WORKSPACE_CREATION_LINK - }; - } - - /** - * Returns object with UD configuration options. - */ - getConfiguration(): IBrandingConfiguration { - return { - menu: { - disabled: - this.branding.configuration && - this.branding.configuration.menu && this.branding.configuration.menu.disabled - ? this.branding.configuration.menu.disabled - : [] - }, - features: { - disabled: - this.branding.configuration && - this.branding.configuration.features && - this.branding.configuration.features.disabled - ? this.branding.configuration.features.disabled - : [] - }, - prefetch: { - cheCDN: this.branding.configuration && - this.branding.configuration.prefetch && - this.branding.configuration.prefetch.cheCDN - ? this.branding.configuration.prefetch.cheCDN - : undefined, - resources: - this.branding.configuration && - this.branding.configuration.prefetch && - this.branding.configuration.prefetch.resources - ? this.branding.configuration.prefetch.resources - : [] - } - }; - } - -} diff --git a/dashboard/src/components/branding/che-branding.ts b/dashboard/src/components/branding/che-branding.ts new file mode 100644 index 00000000000..beb9af9aae9 --- /dev/null +++ b/dashboard/src/components/branding/che-branding.ts @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2015-2018 Red Hat, Inc. + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + */ +'use strict'; +import { + BRANDING_DEFAULT, + IBrandingConfiguration, + IBrandingDocs, + IBrandingFooter, + IBrandingWorkspace +} from './branding.constant' + +const BRANDING_SERVICE_SYMBOL = Symbol('CheBranding'); +const ASSET_PREFIX = 'assets/branding/'; + +/** + * This class is handling the branding data. + * @author Oleksii Orel + */ +export class CheBranding { + private branding = BRANDING_DEFAULT; + private callbacks: Map = new Map(); + private readonly readyPromise: Promise; + + static get(): CheBranding { + const global = window as any; // tslint:disable-line + return global[BRANDING_SERVICE_SYMBOL] || new CheBranding(); + } + + protected constructor() { + const global = window as any; // tslint:disable-line + global[BRANDING_SERVICE_SYMBOL] = this; + + this.readyPromise = this.updateData(); + } + + get ready(): Promise { + return this.readyPromise; + } + + /** + * Update branding data. + */ + private updateData(): Promise { + return angular.element.get(`${ASSET_PREFIX}product.json`).then(branding => { + if (branding) { + this.branding = angular.extend(BRANDING_DEFAULT, branding); + this.callbacks.forEach(callback => { + if (angular.isFunction(callback)) { + callback(this.branding); + } + }); + } + }).catch(error => { + console.error(`Can't GET "${ASSET_PREFIX}product.json". ${error ? 'Error: ' : ''}`, error); + }); + } + + get all(): { [key: string]: string | Object } { + return { + title: this.getProductName(), + name: this.getName(), + logoURL: this.getProductLogo(), + logoText: this.getProductLogoText(), + favicon: this.getProductFavicon(), + loaderURL: this.getLoaderUrl(), + websocketContext: this.getWebsocketContext(), + helpPath: this.getProductHelpPath(), + helpTitle: this.getProductHelpTitle(), + footer: this.getFooter(), + supportEmail: this.getProductSupportEmail(), + oauthDocs: this.getOauthDocs(), + cli: this.getCLI(), + docs: this.getDocs(), + workspace: this.getWorkspace(), + configuration: this.getConfiguration(), + }; + } + + /** + * Gets name. + */ + getName(): string { + return this.branding.name; + } + + /** + * Gets product name. + */ + getProductName(): string { + return this.branding.title; + } + + /** + * Gets product logo. + */ + getProductLogo(): string { + return ASSET_PREFIX + this.branding.logoFile; + } + + /** + * Gets product favicon. + */ + getProductFavicon(): string { + return ASSET_PREFIX + this.branding.favicon; + } + + /** + * Gets product loader. + */ + getLoaderUrl(): string { + return ASSET_PREFIX + this.branding.loader; + } + + /** + * Gets ide resources path. + */ + getWebsocketContext(): string { + return this.branding.websocketContext; + } + + /** + * Gets product help path. + */ + getProductHelpPath(): string { + return this.branding.helpPath; + } + + /** + * Gets product help title. + */ + getProductHelpTitle(): string { + return this.branding.helpTitle; + } + + /** + * Gets product logo text. + */ + getProductLogoText(): string { + return ASSET_PREFIX + this.branding.logoTextFile; + } + + /** + * Gets oauth docs. + */ + getOauthDocs(): string { + return this.branding.oauthDocs; + } + + /** + * Gets product support email. + */ + getProductSupportEmail(): string { + return this.branding.supportEmail; + } + + /** + * Returns footer additional elements (email button, content, button links). + */ + getFooter(): IBrandingFooter { + return this.branding.footer; + } + + /** + * Returns object with configName and name. + */ + getCLI(): { configName: string; name: string } { + return this.branding.cli; + } + + /** + * Returns object with docs URLs. + */ + getDocs(): IBrandingDocs { + return this.branding.docs; + } + + /** + * Returns object with workspace dedicated data. + */ + getWorkspace(): IBrandingWorkspace { + return this.branding.workspace; + } + + /** + * Returns object with UD configuration options. + */ + getConfiguration(): IBrandingConfiguration { + return this.branding.configuration; + } +} diff --git a/dashboard/src/components/branding/che-dashboard-configuration.service.ts b/dashboard/src/components/branding/che-dashboard-configuration.service.ts index 2804742cc70..00dfca6b31e 100644 --- a/dashboard/src/components/branding/che-dashboard-configuration.service.ts +++ b/dashboard/src/components/branding/che-dashboard-configuration.service.ts @@ -11,7 +11,8 @@ */ 'use strict'; -import { CheBranding, TogglableFeature } from './che-branding.factory'; +import { TogglableFeature } from './branding.constant'; +import { CheBranding } from './che-branding'; export type FooterLink = { title: string; @@ -40,21 +41,20 @@ export class CheDashboardConfigurationService { this.cheBranding = cheBranding; } - get ready(): ng.IPromise { - return this.cheBranding.ready; - } - allowedMenuItem(menuItem: che.ConfigurableMenuItem | string): boolean { const disabledItems = this.cheBranding.getConfiguration().menu.disabled; return (disabledItems as string[]).indexOf(menuItem) === -1; } allowRoutes(menuItem: che.ConfigurableMenuItem): ng.IPromise { - return this.cheBranding.ready.then(() => { - if (this.allowedMenuItem(menuItem) === false) { - return this.$q.reject(); + const defer = this.$q.defer(); + if (this.allowedMenuItem(menuItem)) { + defer.resolve(); + } else { + defer.reject(); } - }); + + return defer.promise; } enabledFeature(feature: TogglableFeature): boolean { diff --git a/dashboard/src/components/service/resource-fetcher/resource-fetcher.service.ts b/dashboard/src/components/service/resource-fetcher/resource-fetcher.service.ts index d60da015454..4e5dc95cde6 100644 --- a/dashboard/src/components/service/resource-fetcher/resource-fetcher.service.ts +++ b/dashboard/src/components/service/resource-fetcher/resource-fetcher.service.ts @@ -11,9 +11,7 @@ */ 'use strict'; -import { CheBranding } from '../../branding/che-branding.factory'; - -const IDE_FETCHER_CALLBACK_ID = 'cheIdeFetcherCallback'; +import { CheBranding } from '../../branding/che-branding'; /** * Provides a way to download IDE .js and then cache it before trying to load the IDE @@ -45,13 +43,9 @@ export class ResourceFetcherService { this.$http = $http; this.cheBranding = cheBranding; - const callback = () => { - const prefetch = this.cheBranding.getConfiguration().prefetch; - this.prefetchCheCDNResources(prefetch.cheCDN); - this.prefetchResources(prefetch.resources); - this.cheBranding.unregisterCallback(IDE_FETCHER_CALLBACK_ID); - }; - this.cheBranding.registerCallback(IDE_FETCHER_CALLBACK_ID, callback.bind(this)); + const prefetch = this.cheBranding.getConfiguration().prefetch; + this.prefetchCheCDNResources(prefetch.cheCDN); + this.prefetchResources(prefetch.resources); } /** diff --git a/dashboard/src/components/validator/unique-project-name-validator.spec.ts b/dashboard/src/components/validator/unique-project-name-validator.spec.ts index 52f94ab8fb2..1ccc538fb3c 100644 --- a/dashboard/src/components/validator/unique-project-name-validator.spec.ts +++ b/dashboard/src/components/validator/unique-project-name-validator.spec.ts @@ -62,7 +62,7 @@ describe('unique-project-name-validator', function() { describe('Validate Project Name', function() { - it('projectAlready exists', function() { + it('project already exists', function() { // setup tests objects let idWorkspace1 = 'idOfMyWorkspace1'; diff --git a/dashboard/src/components/widget/footer/che-footer.controller.ts b/dashboard/src/components/widget/footer/che-footer.controller.ts index 431d29c70cf..7e1adc63eab 100644 --- a/dashboard/src/components/widget/footer/che-footer.controller.ts +++ b/dashboard/src/components/widget/footer/che-footer.controller.ts @@ -35,9 +35,7 @@ export class CheFooterController { } $onInit(): void { - this.cheDashboardConfigurationService.ready.then(() => { - this.links = this.cheDashboardConfigurationService.getFooterLinks(); - }); + this.links = this.cheDashboardConfigurationService.getFooterLinks(); } /**