From 81ba34b9aa627d728d70e847a3bf23633ffee4ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Agneray?= <francois.agneray@lam.fr> Date: Fri, 23 Jul 2021 22:12:26 +0200 Subject: [PATCH] The configuration is now in a file loaded at init --- client/src/app/admin/admin-auth.guard.ts | 69 ++++----- client/src/app/admin/admin-routing.module.ts | 8 +- client/src/app/admin/admin.component.html | 2 + client/src/app/admin/admin.component.ts | 11 +- .../attribute/add-attribute.component.ts | 9 ++ .../generate-option-list.component.ts | 9 ++ .../criteria/option-form.component.ts | 9 ++ .../criteria/option-list.component.ts | 9 ++ .../criteria/table-criteria.component.ts | 9 ++ .../criteria/tr-criteria.component.ts | 11 +- .../components/attribute/design/index.ts | 9 ++ .../design/table-design.component.ts | 9 ++ .../attribute/design/tr-design.component.ts | 11 +- .../components/attribute/detail/index.ts | 9 ++ .../detail/table-detail.component.ts | 9 ++ .../attribute/detail/tr-detail.component.ts | 11 +- .../app/admin/components/attribute/index.ts | 9 ++ .../components/attribute/output/index.ts | 9 ++ .../output/table-output.component.ts | 9 ++ .../attribute/output/tr-output.component.ts | 11 +- .../components/attribute/result/index.ts | 9 ++ .../renderers/detail-renderer.component.ts | 9 ++ .../renderers/download-renderer.component.ts | 9 ++ .../renderers/image-renderer.component.ts | 9 ++ .../attribute/result/renderers/index.ts | 9 ++ .../renderers/link-renderer.component.ts | 9 ++ .../result/renderers/renderer-form-factory.ts | 9 ++ .../result/table-result.component.ts | 9 ++ .../attribute/result/tr-result.component.ts | 11 +- .../{tr.component.css => tr.component.scss} | 0 .../admin/components/attribute/vo/index.ts | 9 ++ .../attribute/vo/table-vo.component.ts | 9 ++ .../attribute/vo/tr-vo.component.ts | 11 +- client/src/app/app-config.service.ts | 13 ++ client/src/app/app-init.ts | 29 ++++ client/src/app/app.module.ts | 6 + client/src/app/auth/auth.effects.ts | 11 +- client/src/app/auth/auth.module.ts | 9 +- client/src/app/auth/init.keycloak.ts | 59 ++++---- .../src/app/core/containers/app.component.ts | 6 +- .../components/object-data.component.ts | 5 +- .../spectra/spectra-object.component.ts | 5 +- .../documentation/documentation.component.ts | 10 +- .../src/app/instance/instance.component.html | 2 + client/src/app/instance/instance.component.ts | 11 +- .../between-date.component.spec.ts | 75 ---------- .../search-type/between.component.spec.ts | 94 ------------- .../search-type/checkbox.component.spec.ts | 86 ------------ .../search-type/datalist.component.spec.ts | 106 -------------- .../search-type/date.component.spec.ts | 105 -------------- .../search-type/datetime.component.spec.ts | 131 ------------------ .../search-type/field.component.spec.ts | 117 ---------------- .../search-type/help-like.component.spec.ts | 20 --- .../search-type/json.component.spec.ts | 75 ---------- .../search-type/list.component.spec.ts | 73 ---------- .../search-type/operator.component.spec.ts | 83 ----------- .../search-type/radio.component.spec.ts | 73 ---------- .../select-multiple.component.spec.ts | 79 ----------- .../search-type/select.component.spec.ts | 98 ------------- .../search-type/time.component.spec.ts | 99 ------------- .../components/result/download.component.ts | 7 +- .../result/url-display.component.ts | 5 +- .../renderer/download-renderer.component.ts | 5 +- .../renderer/image-renderer.component.ts | 7 +- .../instance/store/services/detail.service.ts | 11 +- .../instance/store/services/samp.service.ts | 6 +- .../instance/store/services/search.service.ts | 10 +- .../services/attribute-distinct.service.ts | 8 +- .../metamodel/services/attribute.service.ts | 14 +- .../app/metamodel/services/column.service.ts | 8 +- .../services/criteria-family.service.ts | 14 +- .../metamodel/services/database.service.ts | 14 +- .../services/dataset-family.service.ts | 14 +- .../app/metamodel/services/dataset.service.ts | 14 +- .../app/metamodel/services/group.service.ts | 14 +- .../metamodel/services/instance.service.ts | 14 +- .../services/output-category.service.ts | 14 +- .../services/output-family.service.ts | 14 +- .../services/root-directory.service.ts | 8 +- .../services/select-option.service.ts | 14 +- .../app/metamodel/services/select.service.ts | 14 +- .../app/metamodel/services/survey.service.ts | 14 +- .../app/metamodel/services/table.service.ts | 8 +- .../containers/portal-home.component.html | 2 + .../containers/portal-home.component.ts | 16 ++- .../app/shared/components/navbar.component.ts | 6 +- client/src/app/shared/utils.ts | 10 +- client/src/assets/app.config.json | 10 ++ client/src/environments/environment.prod.ts | 10 +- client/src/environments/environment.ts | 10 +- 90 files changed, 560 insertions(+), 1589 deletions(-) rename client/src/app/admin/components/attribute/{tr.component.css => tr.component.scss} (100%) create mode 100644 client/src/app/app-config.service.ts create mode 100644 client/src/app/app-init.ts delete mode 100644 client/src/app/instance/search/components/criteria/search-type/between-date.component.spec.ts delete mode 100644 client/src/app/instance/search/components/criteria/search-type/between.component.spec.ts delete mode 100644 client/src/app/instance/search/components/criteria/search-type/checkbox.component.spec.ts delete mode 100644 client/src/app/instance/search/components/criteria/search-type/datalist.component.spec.ts delete mode 100644 client/src/app/instance/search/components/criteria/search-type/date.component.spec.ts delete mode 100644 client/src/app/instance/search/components/criteria/search-type/datetime.component.spec.ts delete mode 100644 client/src/app/instance/search/components/criteria/search-type/field.component.spec.ts delete mode 100644 client/src/app/instance/search/components/criteria/search-type/help-like.component.spec.ts delete mode 100644 client/src/app/instance/search/components/criteria/search-type/json.component.spec.ts delete mode 100644 client/src/app/instance/search/components/criteria/search-type/list.component.spec.ts delete mode 100644 client/src/app/instance/search/components/criteria/search-type/operator.component.spec.ts delete mode 100644 client/src/app/instance/search/components/criteria/search-type/radio.component.spec.ts delete mode 100644 client/src/app/instance/search/components/criteria/search-type/select-multiple.component.spec.ts delete mode 100644 client/src/app/instance/search/components/criteria/search-type/select.component.spec.ts delete mode 100644 client/src/app/instance/search/components/criteria/search-type/time.component.spec.ts create mode 100644 client/src/assets/app.config.json diff --git a/client/src/app/admin/admin-auth.guard.ts b/client/src/app/admin/admin-auth.guard.ts index fb9fab7f..02ac7a5e 100644 --- a/client/src/app/admin/admin-auth.guard.ts +++ b/client/src/app/admin/admin-auth.guard.ts @@ -8,47 +8,52 @@ */ import { Injectable } from '@angular/core'; -import { - ActivatedRouteSnapshot, - Router, - RouterStateSnapshot, -} from '@angular/router'; -import { Store } from '@ngrx/store'; +import { CanActivate, Router } from '@angular/router'; +import { Store, select } from '@ngrx/store'; -import { KeycloakAuthGuard, KeycloakService } from 'keycloak-angular'; +import { combineLatest, Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; import * as authActions from 'src/app/auth/auth.actions'; -import { environment } from 'src/environments/environment'; +import * as authSelector from 'src/app/auth/auth.selector'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable({ providedIn: 'root', }) -export class AdminAuthGuard extends KeycloakAuthGuard { +export class AdminAuthGuard implements CanActivate { constructor( protected readonly router: Router, - protected readonly keycloak: KeycloakService, - private store: Store<{ }> - ) { - super(router, keycloak); - } + private store: Store<{ }>, + private config: AppConfigService + ) { } + + canActivate(): Observable<boolean> { + return combineLatest([ + this.store.pipe(select(authSelector.selectUserRoles)), + this.store.pipe(select(authSelector.selectIsAuthenticated)) + ]).pipe( + map(([userRoles, isAuthenticated]) => { + // Auth disabled + if (!this.config.authenticationEnabled) { + return true; + } + + // Force the user to log in if currently unauthenticated. + if (!isAuthenticated) { + this.store.dispatch(authActions.login()); + return false; + } + + // If authenticated but not admin go to unauthorized page. + if (!userRoles.includes(this.config.adminRole)) { + this.router.navigateByUrl('/unauthorized'); + return false; + } - public async isAccessAllowed( - route: ActivatedRouteSnapshot, - state: RouterStateSnapshot - ) { - // Force the user to log in if currently unauthenticated. - if (!this.authenticated) { - this.store.dispatch(authActions.login()); - return false; - } - - // If authenticated but not admin go to unauthorized page. - if (!this.roles.includes(environment.adminRole)) { - this.router.navigateByUrl('/unauthorized'); - return false; - } - - // Else return true; - return true; + // Let "Router" allow user entering the page + return true; + }) + ); } } diff --git a/client/src/app/admin/admin-routing.module.ts b/client/src/app/admin/admin-routing.module.ts index 7fc65a51..d3aef6a6 100644 --- a/client/src/app/admin/admin-routing.module.ts +++ b/client/src/app/admin/admin-routing.module.ts @@ -29,11 +29,10 @@ import { DatabaseListComponent } from './containers/database/database-list.compo import { NewDatabaseComponent } from './containers/database/new-database.component'; import { EditDatabaseComponent } from './containers/database/edit-database.component'; import { SettingsComponent } from './containers/settings/settings.component'; -import { environment } from 'src/environments/environment'; const routes: Routes = [ { - path: '', component: AdminComponent, children: [ + path: '', component: AdminComponent, canActivate: [AdminAuthGuard], children: [ { path: '', redirectTo: 'instance-list', pathMatch: 'full' }, { path: 'instance-list', component: InstanceListComponent }, { path: 'new-instance', component: NewInstanceComponent }, @@ -57,11 +56,6 @@ const routes: Routes = [ } ]; -// Add auth guard if authentication is activated -if (environment.authenticationEnabled) { - routes[0].canActivate = [ AdminAuthGuard ]; -} - @NgModule({ imports: [RouterModule.forChild(routes)], exports: [RouterModule] diff --git a/client/src/app/admin/admin.component.html b/client/src/app/admin/admin.component.html index 979df50e..61101934 100644 --- a/client/src/app/admin/admin.component.html +++ b/client/src/app/admin/admin.component.html @@ -3,6 +3,8 @@ [links]="links" [isAuthenticated]="isAuthenticated | async" [userProfile]="userProfile | async" + [baseHref]="getBaseHref()" + [authenticationEnabled]="getAuthenticationEnabled()" (login)="login()" (logout)="logout()" (openEditProfile)="openEditProfile()"> diff --git a/client/src/app/admin/admin.component.ts b/client/src/app/admin/admin.component.ts index 18364e14..93e97de1 100644 --- a/client/src/app/admin/admin.component.ts +++ b/client/src/app/admin/admin.component.ts @@ -14,6 +14,7 @@ import { Store } from '@ngrx/store'; import { UserProfile } from 'src/app/auth/user-profile.model'; import * as authActions from 'src/app/auth/auth.actions'; import * as authSelector from 'src/app/auth/auth.selector'; +import { AppConfigService } from 'src/app/app-config.service'; @Component({ selector: 'app-admin', @@ -37,12 +38,20 @@ export class AdminComponent { public userProfile: Observable<UserProfile>; public userRoles: Observable<string[]>; - constructor(private store: Store<{ }>) { + constructor(private store: Store<{ }>, private config: AppConfigService) { this.isAuthenticated = store.select(authSelector.selectIsAuthenticated); this.userProfile = store.select(authSelector.selectUserProfile); this.userRoles = store.select(authSelector.selectUserRoles); } + getBaseHref() { + return this.config.baseHref; + } + + getAuthenticationEnabled() { + return this.config.authenticationEnabled; + } + login(): void { this.store.dispatch(authActions.login()); } diff --git a/client/src/app/admin/components/attribute/add-attribute.component.ts b/client/src/app/admin/components/attribute/add-attribute.component.ts index f7934d61..fc050468 100644 --- a/client/src/app/admin/components/attribute/add-attribute.component.ts +++ b/client/src/app/admin/components/attribute/add-attribute.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component, ChangeDetectionStrategy, Input, Output, EventEmitter, TemplateRef } from '@angular/core'; import { BsModalService } from 'ngx-bootstrap/modal'; diff --git a/client/src/app/admin/components/attribute/criteria/generate-option-list.component.ts b/client/src/app/admin/components/attribute/criteria/generate-option-list.component.ts index 1b6905a2..cc0899ce 100644 --- a/client/src/app/admin/components/attribute/criteria/generate-option-list.component.ts +++ b/client/src/app/admin/components/attribute/criteria/generate-option-list.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component, ChangeDetectionStrategy, Input, Output, EventEmitter, TemplateRef } from '@angular/core'; import { BsModalService } from 'ngx-bootstrap/modal'; diff --git a/client/src/app/admin/components/attribute/criteria/option-form.component.ts b/client/src/app/admin/components/attribute/criteria/option-form.component.ts index 5e2a620d..cff2bdcd 100644 --- a/client/src/app/admin/components/attribute/criteria/option-form.component.ts +++ b/client/src/app/admin/components/attribute/criteria/option-form.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component, Input, ChangeDetectionStrategy } from '@angular/core'; import { FormGroup } from '@angular/forms'; diff --git a/client/src/app/admin/components/attribute/criteria/option-list.component.ts b/client/src/app/admin/components/attribute/criteria/option-list.component.ts index 492bac06..c3e643a5 100644 --- a/client/src/app/admin/components/attribute/criteria/option-list.component.ts +++ b/client/src/app/admin/components/attribute/criteria/option-list.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component, Input, OnInit, Output, EventEmitter } from '@angular/core'; import { FormArray, FormControl, FormGroup, Validators } from '@angular/forms'; diff --git a/client/src/app/admin/components/attribute/criteria/table-criteria.component.ts b/client/src/app/admin/components/attribute/criteria/table-criteria.component.ts index fe5c7db6..9cf5e6de 100644 --- a/client/src/app/admin/components/attribute/criteria/table-criteria.component.ts +++ b/client/src/app/admin/components/attribute/criteria/table-criteria.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; @Component({ diff --git a/client/src/app/admin/components/attribute/criteria/tr-criteria.component.ts b/client/src/app/admin/components/attribute/criteria/tr-criteria.component.ts index 87109e23..9c1f559f 100644 --- a/client/src/app/admin/components/attribute/criteria/tr-criteria.component.ts +++ b/client/src/app/admin/components/attribute/criteria/tr-criteria.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, OnInit } from '@angular/core'; import { FormArray, FormControl, FormGroup } from '@angular/forms'; @@ -6,7 +15,7 @@ import { Attribute, Option, CriteriaFamily, SelectOption } from 'src/app/metamod @Component({ selector: '[criteria]', templateUrl: 'tr-criteria.component.html', - styleUrls: [ '../tr.component.css' ], + styleUrls: [ '../tr.component.scss' ], changeDetection: ChangeDetectionStrategy.OnPush }) export class TrCriteriaComponent implements OnInit { diff --git a/client/src/app/admin/components/attribute/design/index.ts b/client/src/app/admin/components/attribute/design/index.ts index 97b51ae6..e2a18cde 100644 --- a/client/src/app/admin/components/attribute/design/index.ts +++ b/client/src/app/admin/components/attribute/design/index.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { TableDesignComponent } from './table-design.component'; import { TrDesignComponent } from './tr-design.component'; diff --git a/client/src/app/admin/components/attribute/design/table-design.component.ts b/client/src/app/admin/components/attribute/design/table-design.component.ts index ece9403e..4ca4666d 100644 --- a/client/src/app/admin/components/attribute/design/table-design.component.ts +++ b/client/src/app/admin/components/attribute/design/table-design.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; @Component({ diff --git a/client/src/app/admin/components/attribute/design/tr-design.component.ts b/client/src/app/admin/components/attribute/design/tr-design.component.ts index 72d1dced..f9a42f6f 100644 --- a/client/src/app/admin/components/attribute/design/tr-design.component.ts +++ b/client/src/app/admin/components/attribute/design/tr-design.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, OnInit } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; @@ -6,7 +15,7 @@ import { Attribute, SelectOption } from 'src/app/metamodel/models'; @Component({ selector: '[design]', templateUrl: 'tr-design.component.html', - styleUrls: [ '../tr.component.css' ], + styleUrls: [ '../tr.component.scss' ], changeDetection: ChangeDetectionStrategy.OnPush }) export class TrDesignComponent implements OnInit { diff --git a/client/src/app/admin/components/attribute/detail/index.ts b/client/src/app/admin/components/attribute/detail/index.ts index 41a27ae4..d1581ea5 100644 --- a/client/src/app/admin/components/attribute/detail/index.ts +++ b/client/src/app/admin/components/attribute/detail/index.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { TableDetailComponent } from './table-detail.component'; import { TrDetailComponent } from './tr-detail.component'; diff --git a/client/src/app/admin/components/attribute/detail/table-detail.component.ts b/client/src/app/admin/components/attribute/detail/table-detail.component.ts index 5ff070ee..f13fc516 100644 --- a/client/src/app/admin/components/attribute/detail/table-detail.component.ts +++ b/client/src/app/admin/components/attribute/detail/table-detail.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; @Component({ diff --git a/client/src/app/admin/components/attribute/detail/tr-detail.component.ts b/client/src/app/admin/components/attribute/detail/tr-detail.component.ts index 2f268277..d485de9d 100644 --- a/client/src/app/admin/components/attribute/detail/tr-detail.component.ts +++ b/client/src/app/admin/components/attribute/detail/tr-detail.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, OnInit } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; @@ -6,7 +15,7 @@ import { Attribute, SelectOption } from 'src/app/metamodel/models'; @Component({ selector: '[detail]', templateUrl: 'tr-detail.component.html', - styleUrls: [ '../tr.component.css' ], + styleUrls: [ '../tr.component.scss' ], changeDetection: ChangeDetectionStrategy.OnPush }) export class TrDetailComponent implements OnInit { diff --git a/client/src/app/admin/components/attribute/index.ts b/client/src/app/admin/components/attribute/index.ts index 4d35bcb4..fc2f19be 100644 --- a/client/src/app/admin/components/attribute/index.ts +++ b/client/src/app/admin/components/attribute/index.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { AddAttributeComponent } from './add-attribute.component'; import { designComponents } from './design'; import { criteriaComponents } from './criteria'; diff --git a/client/src/app/admin/components/attribute/output/index.ts b/client/src/app/admin/components/attribute/output/index.ts index b5f11cda..1c915eff 100644 --- a/client/src/app/admin/components/attribute/output/index.ts +++ b/client/src/app/admin/components/attribute/output/index.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { TableOutputComponent } from "./table-output.component"; import { TrOutputComponent } from "./tr-output.component"; diff --git a/client/src/app/admin/components/attribute/output/table-output.component.ts b/client/src/app/admin/components/attribute/output/table-output.component.ts index 30c36b2b..a2aefb31 100644 --- a/client/src/app/admin/components/attribute/output/table-output.component.ts +++ b/client/src/app/admin/components/attribute/output/table-output.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; @Component({ diff --git a/client/src/app/admin/components/attribute/output/tr-output.component.ts b/client/src/app/admin/components/attribute/output/tr-output.component.ts index a2a7afc9..f75c8452 100644 --- a/client/src/app/admin/components/attribute/output/tr-output.component.ts +++ b/client/src/app/admin/components/attribute/output/tr-output.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, OnInit } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; @@ -6,7 +15,7 @@ import { Attribute, OutputCategory } from 'src/app/metamodel/models'; @Component({ selector: '[output]', templateUrl: 'tr-output.component.html', - styleUrls: [ '../tr.component.css' ], + styleUrls: [ '../tr.component.scss' ], changeDetection: ChangeDetectionStrategy.OnPush }) export class TrOutputComponent implements OnInit { diff --git a/client/src/app/admin/components/attribute/result/index.ts b/client/src/app/admin/components/attribute/result/index.ts index 4b25f427..3517973a 100644 --- a/client/src/app/admin/components/attribute/result/index.ts +++ b/client/src/app/admin/components/attribute/result/index.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { TableResultComponent } from './table-result.component'; import { TrResultComponent } from './tr-result.component'; import { renderers } from './renderers'; diff --git a/client/src/app/admin/components/attribute/result/renderers/detail-renderer.component.ts b/client/src/app/admin/components/attribute/result/renderers/detail-renderer.component.ts index 2939aecf..4dfc1917 100644 --- a/client/src/app/admin/components/attribute/result/renderers/detail-renderer.component.ts +++ b/client/src/app/admin/components/attribute/result/renderers/detail-renderer.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component, Input, ChangeDetectionStrategy } from '@angular/core'; import { FormGroup } from '@angular/forms'; diff --git a/client/src/app/admin/components/attribute/result/renderers/download-renderer.component.ts b/client/src/app/admin/components/attribute/result/renderers/download-renderer.component.ts index ef1fc0d8..f3ccfee5 100644 --- a/client/src/app/admin/components/attribute/result/renderers/download-renderer.component.ts +++ b/client/src/app/admin/components/attribute/result/renderers/download-renderer.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component, Input, ChangeDetectionStrategy } from '@angular/core'; import { FormGroup } from '@angular/forms'; diff --git a/client/src/app/admin/components/attribute/result/renderers/image-renderer.component.ts b/client/src/app/admin/components/attribute/result/renderers/image-renderer.component.ts index 87067115..1441a6a8 100644 --- a/client/src/app/admin/components/attribute/result/renderers/image-renderer.component.ts +++ b/client/src/app/admin/components/attribute/result/renderers/image-renderer.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component, Input, ChangeDetectionStrategy } from '@angular/core'; import { FormGroup } from '@angular/forms'; diff --git a/client/src/app/admin/components/attribute/result/renderers/index.ts b/client/src/app/admin/components/attribute/result/renderers/index.ts index bf18afa1..89c8ed9d 100644 --- a/client/src/app/admin/components/attribute/result/renderers/index.ts +++ b/client/src/app/admin/components/attribute/result/renderers/index.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { DetailRendererComponent } from './detail-renderer.component'; import { DownloadRendererComponent } from './download-renderer.component'; import { ImageRendererComponent } from './image-renderer.component'; diff --git a/client/src/app/admin/components/attribute/result/renderers/link-renderer.component.ts b/client/src/app/admin/components/attribute/result/renderers/link-renderer.component.ts index a67b8803..d8d13637 100644 --- a/client/src/app/admin/components/attribute/result/renderers/link-renderer.component.ts +++ b/client/src/app/admin/components/attribute/result/renderers/link-renderer.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component, Input, ChangeDetectionStrategy } from '@angular/core'; import { FormGroup } from '@angular/forms'; diff --git a/client/src/app/admin/components/attribute/result/renderers/renderer-form-factory.ts b/client/src/app/admin/components/attribute/result/renderers/renderer-form-factory.ts index 8a6e7ef3..22c2f5e3 100644 --- a/client/src/app/admin/components/attribute/result/renderers/renderer-form-factory.ts +++ b/client/src/app/admin/components/attribute/result/renderers/renderer-form-factory.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { FormControl } from "@angular/forms"; export abstract class RendererFormFactory { diff --git a/client/src/app/admin/components/attribute/result/table-result.component.ts b/client/src/app/admin/components/attribute/result/table-result.component.ts index d4aa1103..86ce85cb 100644 --- a/client/src/app/admin/components/attribute/result/table-result.component.ts +++ b/client/src/app/admin/components/attribute/result/table-result.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; @Component({ diff --git a/client/src/app/admin/components/attribute/result/tr-result.component.ts b/client/src/app/admin/components/attribute/result/tr-result.component.ts index 38ae0028..fe0aa76e 100644 --- a/client/src/app/admin/components/attribute/result/tr-result.component.ts +++ b/client/src/app/admin/components/attribute/result/tr-result.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, OnInit } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; @@ -7,7 +16,7 @@ import { RendererFormFactory } from './renderers/renderer-form-factory'; @Component({ selector: '[result]', templateUrl: 'tr-result.component.html', - styleUrls: [ '../tr.component.css' ], + styleUrls: [ '../tr.component.scss' ], changeDetection: ChangeDetectionStrategy.OnPush }) export class TrResultComponent implements OnInit { diff --git a/client/src/app/admin/components/attribute/tr.component.css b/client/src/app/admin/components/attribute/tr.component.scss similarity index 100% rename from client/src/app/admin/components/attribute/tr.component.css rename to client/src/app/admin/components/attribute/tr.component.scss diff --git a/client/src/app/admin/components/attribute/vo/index.ts b/client/src/app/admin/components/attribute/vo/index.ts index 8b6aa3b6..80eb8323 100644 --- a/client/src/app/admin/components/attribute/vo/index.ts +++ b/client/src/app/admin/components/attribute/vo/index.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { TableVoComponent } from './table-vo.component'; import { TrVoComponent } from './tr-vo.component'; diff --git a/client/src/app/admin/components/attribute/vo/table-vo.component.ts b/client/src/app/admin/components/attribute/vo/table-vo.component.ts index ba4352e0..57df81c8 100644 --- a/client/src/app/admin/components/attribute/vo/table-vo.component.ts +++ b/client/src/app/admin/components/attribute/vo/table-vo.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component } from '@angular/core'; @Component({ diff --git a/client/src/app/admin/components/attribute/vo/tr-vo.component.ts b/client/src/app/admin/components/attribute/vo/tr-vo.component.ts index 52172506..e0dd9bb2 100644 --- a/client/src/app/admin/components/attribute/vo/tr-vo.component.ts +++ b/client/src/app/admin/components/attribute/vo/tr-vo.component.ts @@ -1,3 +1,12 @@ +/** + * This file is part of Anis Client. + * + * @copyright Laboratoire d'Astrophysique de Marseille / CNRS + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, OnInit } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; @@ -6,7 +15,7 @@ import { Attribute } from 'src/app/metamodel/models'; @Component({ selector: '[vo]', templateUrl: 'tr-vo.component.html', - styleUrls: [ '../tr.component.css' ], + styleUrls: [ '../tr.component.scss' ], changeDetection: ChangeDetectionStrategy.OnPush }) export class TrVoComponent implements OnInit { diff --git a/client/src/app/app-config.service.ts b/client/src/app/app-config.service.ts new file mode 100644 index 00000000..5944e78a --- /dev/null +++ b/client/src/app/app-config.service.ts @@ -0,0 +1,13 @@ +import { Injectable } from '@angular/core'; + +@Injectable() +export class AppConfigService { + public apiUrl: string; + public servicesUrl: string; + public baseHref: string; + public authenticationEnabled: boolean; + public ssoAuthUrl: string; + public ssoRealm: string; + public ssoClientId: string; + public adminRole: string; +} diff --git a/client/src/app/app-init.ts b/client/src/app/app-init.ts new file mode 100644 index 00000000..b3dc0426 --- /dev/null +++ b/client/src/app/app-init.ts @@ -0,0 +1,29 @@ +import { APP_INITIALIZER } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; + +import { KeycloakService } from 'keycloak-angular'; +import { Store } from '@ngrx/store'; + +import { AppConfigService } from './app-config.service'; +import { initializeKeycloak } from 'src/app/auth/init.keycloak'; + +function appInit(http: HttpClient, appConfigService: AppConfigService, keycloak: KeycloakService, store: Store<{ }>) { + return () => { + return http.get('/assets/app.config.json') + .toPromise() + .then(data => { + Object.assign(appConfigService, data); + return appConfigService; + }) + .then(appConfigService => { + return initializeKeycloak(keycloak, store, appConfigService) + }); + } +} + +export const appInitializer = { + provide: APP_INITIALIZER, + useFactory: appInit, + multi: true, + deps: [ HttpClient, AppConfigService, KeycloakService, Store ] +}; diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index 981c03d2..cca4aece 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts @@ -25,6 +25,8 @@ import { CoreModule } from './core/core.module'; import { AuthModule } from './auth/auth.module'; import { MetamodelModule } from './metamodel/metamodel.module'; import { AppComponent } from './core/containers/app.component'; +import { AppConfigService } from './app-config.service'; +import { appInitializer } from './app-init'; @NgModule({ imports: [ @@ -56,6 +58,10 @@ import { AppComponent } from './core/containers/app.component'; logOnly: environment.production }) ], + providers: [ + AppConfigService, + appInitializer + ], bootstrap: [AppComponent] }) export class AppModule { } diff --git a/client/src/app/auth/auth.effects.ts b/client/src/app/auth/auth.effects.ts index 0f7c6b9c..69cefb0e 100644 --- a/client/src/app/auth/auth.effects.ts +++ b/client/src/app/auth/auth.effects.ts @@ -15,7 +15,7 @@ import { tap, switchMap } from 'rxjs/operators'; import { KeycloakService } from 'keycloak-angular'; import * as authActions from './auth.actions'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() export class AuthEffects { @@ -35,8 +35,8 @@ export class AuthEffects { ofType(authActions.logout), tap(_ => { let redirectUri = window.location.origin; - if (environment.baseHref !== '/') { - redirectUri += environment.baseHref; + if (this.config.baseHref !== '/') { + redirectUri += this.config.baseHref; } this.keycloak.logout(redirectUri); }) @@ -61,13 +61,14 @@ export class AuthEffects { openEditProfile$ = createEffect(() => this.actions$.pipe( ofType(authActions.openEditProfile), - tap(_ => window.open(environment.ssoAuthUrl + '/realms/' + environment.ssoRealm + '/account', '_blank')) + tap(_ => window.open(this.config.ssoAuthUrl + '/realms/' + this.config.ssoRealm + '/account', '_blank')) ), { dispatch: false } ); constructor( private actions$: Actions, - private keycloak: KeycloakService + private keycloak: KeycloakService, + private config: AppConfigService ) {} } diff --git a/client/src/app/auth/auth.module.ts b/client/src/app/auth/auth.module.ts index 1c04b526..5f928302 100644 --- a/client/src/app/auth/auth.module.ts +++ b/client/src/app/auth/auth.module.ts @@ -13,19 +13,14 @@ import { KeycloakAngularModule } from 'keycloak-angular'; import { StoreModule } from '@ngrx/store'; import { EffectsModule } from '@ngrx/effects'; -import { initializeKeycloakAnis } from './init.keycloak'; import { authReducer } from './auth.reducer'; import { AuthEffects } from './auth.effects'; -import { environment } from 'src/environments/environment'; @NgModule({ imports: [ - environment.authenticationEnabled ? KeycloakAngularModule : [], + KeycloakAngularModule, StoreModule.forFeature('auth', authReducer), - environment.authenticationEnabled ? EffectsModule.forFeature([ AuthEffects ]): [] - ], - providers: [ - environment.authenticationEnabled ? initializeKeycloakAnis: [] + EffectsModule.forFeature([ AuthEffects ]) ] }) export class AuthModule { } diff --git a/client/src/app/auth/init.keycloak.ts b/client/src/app/auth/init.keycloak.ts index f0509a31..de6c1bc3 100644 --- a/client/src/app/auth/init.keycloak.ts +++ b/client/src/app/auth/init.keycloak.ts @@ -7,48 +7,41 @@ * file that was distributed with this source code. */ -import { APP_INITIALIZER } from '@angular/core'; import { from } from 'rxjs'; import { KeycloakService, KeycloakEventType } from 'keycloak-angular'; import { Store } from '@ngrx/store'; import * as keycloakActions from './auth.actions'; -import * as fromKeycloak from './auth.reducer'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from '../app-config.service'; -function initializeKeycloak(keycloak: KeycloakService, store: Store<{ keycloak: fromKeycloak.State }>) { - return async () => { - from(keycloak.keycloakEvents$).subscribe(event => { - if (event.type === KeycloakEventType.OnAuthSuccess) { - store.dispatch(keycloakActions.authSuccess()); - } - }) +export function initializeKeycloak(keycloak: KeycloakService, store: Store<{ }>, appConfigService: AppConfigService) { + if (!appConfigService.authenticationEnabled) { + return true; + } - let silentCheckSsoRedirectUri = window.location.origin; - if (environment.baseHref != '/') { - silentCheckSsoRedirectUri += environment.baseHref; + from(keycloak.keycloakEvents$).subscribe(event => { + if (event.type === KeycloakEventType.OnAuthSuccess) { + store.dispatch(keycloakActions.authSuccess()); } - silentCheckSsoRedirectUri += '/assets/silent-check-sso.html'; + }) - return keycloak.init({ - config: { - url: environment.ssoAuthUrl, - realm: environment.ssoRealm, - clientId: environment.ssoClientId, - }, - initOptions: { - onLoad: 'check-sso', - silentCheckSsoRedirectUri - }, - loadUserProfileAtStartUp: true - }); + let silentCheckSsoRedirectUri = window.location.origin; + if (appConfigService.baseHref != '/') { + silentCheckSsoRedirectUri += appConfigService.baseHref; } -} + silentCheckSsoRedirectUri += '/assets/silent-check-sso.html'; -export const initializeKeycloakAnis = { - provide: APP_INITIALIZER, - useFactory: initializeKeycloak, - multi: true, - deps: [ KeycloakService, Store ], -}; + return keycloak.init({ + config: { + url: appConfigService.ssoAuthUrl, + realm: appConfigService.ssoRealm, + clientId: appConfigService.ssoClientId, + }, + initOptions: { + onLoad: 'check-sso', + silentCheckSsoRedirectUri + }, + loadUserProfileAtStartUp: true + }); +} diff --git a/client/src/app/core/containers/app.component.ts b/client/src/app/core/containers/app.component.ts index c265196b..0de038c0 100644 --- a/client/src/app/core/containers/app.component.ts +++ b/client/src/app/core/containers/app.component.ts @@ -17,7 +17,7 @@ import * as fromAuth from '../../auth/auth.reducer'; import * as authActions from '../../auth/auth.actions'; import * as authSelector from '../../auth/auth.selector'; import { UserProfile } from '../../auth/user-profile.model'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Component({ selector: 'app-root', @@ -30,14 +30,14 @@ export class AppComponent { public userProfile: Observable<UserProfile>; public userRoles: Observable<string[]>; - constructor(private store: Store<{ auth: fromAuth.State }>) { + constructor(private store: Store<{ auth: fromAuth.State }>, private config: AppConfigService) { this.isAuthenticated = store.select(authSelector.selectIsAuthenticated); this.userProfile = store.select(authSelector.selectUserProfile); this.userRoles = store.select(authSelector.selectUserRoles); } authenticationEnabled(): boolean { - return environment.authenticationEnabled; + return this.config.authenticationEnabled; } login(): void { diff --git a/client/src/app/instance/detail/components/object-data.component.ts b/client/src/app/instance/detail/components/object-data.component.ts index d834874b..16de054f 100644 --- a/client/src/app/instance/detail/components/object-data.component.ts +++ b/client/src/app/instance/detail/components/object-data.component.ts @@ -11,6 +11,7 @@ import { Component, Input, ChangeDetectionStrategy } from '@angular/core'; import { Attribute, OutputCategory, OutputFamily } from 'src/app/metamodel/models'; import { getHost } from 'src/app/shared/utils'; +import { AppConfigService } from 'src/app/app-config.service'; @Component({ selector: 'app-object-data', @@ -28,6 +29,8 @@ export class ObjectDataComponent { @Input() attributeList: Attribute[]; @Input() object: any; + constructor(private appConfig: AppConfigService) { } + /** * Returns category list sorted by display, for the given output family ID. * @@ -78,6 +81,6 @@ export class ObjectDataComponent { } getDownloadHref(value: string) { - return getHost() + '/download-file/' + this.datasetSelected + '/' + value; + return getHost(this.appConfig.apiUrl) + '/download-file/' + this.datasetSelected + '/' + value; } } diff --git a/client/src/app/instance/detail/components/spectra/spectra-object.component.ts b/client/src/app/instance/detail/components/spectra/spectra-object.component.ts index df397e7e..9c7095f2 100644 --- a/client/src/app/instance/detail/components/spectra/spectra-object.component.ts +++ b/client/src/app/instance/detail/components/spectra/spectra-object.component.ts @@ -11,6 +11,7 @@ import { Component, Input, ChangeDetectionStrategy, Output, EventEmitter, OnInit import { Attribute, OutputCategory, OutputFamily } from 'src/app/metamodel/models'; import { getHost } from 'src/app/shared/utils'; +import { AppConfigService } from 'src/app/app-config.service'; @Component({ selector: 'app-spectra-object', @@ -35,6 +36,8 @@ export class SpectraObjectComponent implements OnInit { @Input() spectraCSV: string; @Output() getSpectraCSV: EventEmitter<string> = new EventEmitter(); + constructor(private appConfig: AppConfigService) { } + ngOnInit() { const attributeSpectraGraph = this.getAttributeSpectraGraph(); if (attributeSpectraGraph) { @@ -51,7 +54,7 @@ export class SpectraObjectComponent implements OnInit { const spectraAttribute: Attribute = this.attributeList .filter(a => a.detail) .find(attribute => attribute.search_flag === 'SPECTRUM_1D'); - return getHost() + '/download-file/' + this.datasetSelected + '/' + this.object[spectraAttribute.label]; + return getHost(this.appConfig.apiUrl) + '/download-file/' + this.datasetSelected + '/' + this.object[spectraAttribute.label]; } /** diff --git a/client/src/app/instance/documentation/documentation.component.ts b/client/src/app/instance/documentation/documentation.component.ts index 7a414850..ef1e591e 100644 --- a/client/src/app/instance/documentation/documentation.component.ts +++ b/client/src/app/instance/documentation/documentation.component.ts @@ -15,7 +15,7 @@ import { Observable } from 'rxjs'; import * as datasetActions from 'src/app/metamodel/actions/dataset.actions'; import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector'; import { Dataset } from 'src/app/metamodel/models'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Component({ selector: 'app-documentation', @@ -33,7 +33,7 @@ export class DocumentationComponent implements OnInit { public datasetListIsLoaded: Observable<boolean>; public datasetList: Observable<Dataset[]>; - constructor(private store: Store<{ }>) { + constructor(private store: Store<{ }>, private config: AppConfigService) { this.datasetListIsLoading = store.select(datasetSelector.selectDatasetListIsLoading); this.datasetListIsLoaded = store.select(datasetSelector.selectDatasetListIsLoaded); this.datasetList = store.select(datasetSelector.selectAllDatasets); @@ -49,10 +49,10 @@ export class DocumentationComponent implements OnInit { * @return string */ getUrlServer(): string { - if (!environment.apiUrl.startsWith('http')) { + if (!this.config.apiUrl.startsWith('http')) { const url = window.location; - return url.protocol + '//' + url.host + environment.apiUrl; + return url.protocol + '//' + url.host + this.config.apiUrl; } - return environment.apiUrl; + return this.config.apiUrl; } } diff --git a/client/src/app/instance/instance.component.html b/client/src/app/instance/instance.component.html index 979df50e..61101934 100644 --- a/client/src/app/instance/instance.component.html +++ b/client/src/app/instance/instance.component.html @@ -3,6 +3,8 @@ [links]="links" [isAuthenticated]="isAuthenticated | async" [userProfile]="userProfile | async" + [baseHref]="getBaseHref()" + [authenticationEnabled]="getAuthenticationEnabled()" (login)="login()" (logout)="logout()" (openEditProfile)="openEditProfile()"> diff --git a/client/src/app/instance/instance.component.ts b/client/src/app/instance/instance.component.ts index 6d2d3146..53fc798c 100644 --- a/client/src/app/instance/instance.component.ts +++ b/client/src/app/instance/instance.component.ts @@ -15,6 +15,7 @@ import { UserProfile } from 'src/app/auth/user-profile.model'; import * as authActions from 'src/app/auth/auth.actions'; import * as authSelector from 'src/app/auth/auth.selector'; import * as metamodelActions from './store/actions/metamodel.actions'; +import { AppConfigService } from 'src/app/app-config.service'; @Component({ selector: 'app-instance', @@ -35,7 +36,7 @@ export class InstanceComponent implements OnInit { public userProfile: Observable<UserProfile>; public userRoles: Observable<string[]>; - constructor(private store: Store<{ }>) { + constructor(private store: Store<{ }>, private config: AppConfigService) { this.isAuthenticated = store.select(authSelector.selectIsAuthenticated); this.userProfile = store.select(authSelector.selectUserProfile); this.userRoles = store.select(authSelector.selectUserRoles); @@ -46,6 +47,14 @@ export class InstanceComponent implements OnInit { Promise.resolve(null).then(() => this.store.dispatch(metamodelActions.loadInstanceMetamodel())); } + getBaseHref() { + return this.config.baseHref; + } + + getAuthenticationEnabled() { + return this.config.authenticationEnabled; + } + login(): void { this.store.dispatch(authActions.login()); } diff --git a/client/src/app/instance/search/components/criteria/search-type/between-date.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/between-date.component.spec.ts deleted file mode 100644 index 72ebd410..00000000 --- a/client/src/app/instance/search/components/criteria/search-type/between-date.component.spec.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { Component, ViewChild } from '@angular/core'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms'; - -import { BsDatepickerModule } from 'ngx-bootstrap/datepicker'; - -import { BetweenDateComponent } from './between-date.component'; -import { BetweenCriterion } from '../../../store/model'; - -describe('[Search][Criteria][SearchType] Component: BetweenDateComponent', () => { - @Component({ - selector: `app-host`, - template: `<app-between-date [criterion]='criterion'></app-between-date>` - }) - class TestHostComponent { - @ViewChild(BetweenDateComponent, { static: false }) - public testedComponent: BetweenDateComponent; - public criterion: BetweenCriterion = undefined; - } - - let testHostComponent: TestHostComponent; - let testHostFixture: ComponentFixture<TestHostComponent>; - let testedComponent: BetweenDateComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [BetweenDateComponent, TestHostComponent], - imports: [BsDatepickerModule.forRoot(), FormsModule, ReactiveFormsModule] - }); - testHostFixture = TestBed.createComponent(TestHostComponent); - testHostComponent = testHostFixture.componentInstance; - testHostFixture.detectChanges(); - testedComponent = testHostComponent.testedComponent; - })); - - it('should create the component', () => { - expect(testedComponent).toBeTruthy(); - }); - - it('#getDateString() should format a datetime object into a string', () => { - const dateObject = new Date('February 08, 2019 15:47:00'); - const expectedDateString = '2019-02-08'; - const formatedDate = testedComponent.getDateString(dateObject); - expect(formatedDate).toEqual(expectedDateString); - }); - - it('#getDefault() should enable and not fill form as criterion not defined in host component', () => { - expect(testedComponent.field.value).toBeNull(); - expect(testedComponent.field.enabled).toBeTruthy(); - }); - - it('#getDefault() should fill and disable form if criterion is defined', () => { - const criterion = { id: 1, type: 'between', min: '2019-02-08', max: '2019-02-17' } as BetweenCriterion; - const expectedFieldValue = [new Date(criterion.min), new Date(criterion.max)]; - testedComponent.getDefault(criterion); - expect(testedComponent.field.value).toEqual(expectedFieldValue); - expect(testedComponent.field.disabled).toBeTruthy(); - }); - - it('raises the add criterion event when clicked', () => { - testedComponent.id = 1; - const dateMin = '2019-02-08'; - const dateMax = '2019-02-17'; - testedComponent.field = new FormControl([new Date(dateMin), new Date(dateMax)]); - const expectedCriterion = { id: testedComponent.id, type: 'between', min: dateMin, max: dateMax } as BetweenCriterion; - testedComponent.addCriterion.subscribe((event: BetweenCriterion) => expect(event).toEqual(expectedCriterion)); - testedComponent.emitAdd(); - }); - - it('raises the delete criterion event when clicked', () => { - testedComponent.id = 1; - testedComponent.deleteCriterion.subscribe((event: number) => expect(event).toEqual(1)); - testedComponent.emitDelete(); - }); -}); diff --git a/client/src/app/instance/search/components/criteria/search-type/between.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/between.component.spec.ts deleted file mode 100644 index 80df0b7b..00000000 --- a/client/src/app/instance/search/components/criteria/search-type/between.component.spec.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { Component, ViewChild } from '@angular/core'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms'; - -import { BetweenComponent } from './between.component'; -import { BetweenCriterion } from '../../../store/model'; - -describe('[Search][Criteria][SearchType] Component: BetweenComponent', () => { - @Component({ - selector: `app-host`, - template: `<app-between [criterion]='criterion'></app-between>` - }) - class TestHostComponent { - @ViewChild(BetweenComponent, { static: false }) - public testedComponent: BetweenComponent; - public criterion: BetweenCriterion = undefined; - } - - let testHostComponent: TestHostComponent; - let testHostFixture: ComponentFixture<TestHostComponent>; - let testedComponent: BetweenComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [BetweenComponent, TestHostComponent], - imports: [FormsModule, ReactiveFormsModule] - }); - testHostFixture = TestBed.createComponent(TestHostComponent); - testHostComponent = testHostFixture.componentInstance; - testHostFixture.detectChanges(); - testedComponent = testHostComponent.testedComponent; - })); - - it('should create the component', () => { - expect(testedComponent).toBeTruthy(); - }); - - it('#getDefault() should enable and not fill form as criterion not defined in host component', () => { - expect(testedComponent.fieldMin.value).toBeNull(); - expect(testedComponent.fieldMin.enabled).toBeTruthy(); - expect(testedComponent.fieldMax.value).toBeNull(); - expect(testedComponent.fieldMax.enabled).toBeTruthy(); - }); - - it('#getDefault() should fill and disable form if criterion is defined', () => { - const min = '10'; - const max = '20'; - const criterion = { id: 1, type: 'between', min, max } as BetweenCriterion; - const expectedFieldMinValue = min; - const expectedFieldMaxValue = max; - testedComponent.getDefault(criterion); - expect(testedComponent.fieldMin.value).toEqual(expectedFieldMinValue); - expect(testedComponent.fieldMin.disabled).toBeTruthy(); - expect(testedComponent.fieldMax.value).toEqual(expectedFieldMaxValue); - expect(testedComponent.fieldMax.disabled).toBeTruthy(); - }); - - it('#getPlaceholderMin() should fill the placeholder if defined', () => { - const placeholder = '10'; - testedComponent.placeholderMin = placeholder; - expect(testedComponent.getPlaceholderMin()).toEqual(placeholder); - }); - - it('#getPlaceholderMin() should not fill the placeholder if not defined', () => { - expect(testedComponent.getPlaceholderMin()).toEqual(''); - }); - - it('#getPlaceholderMax() should fill the placeholder if defined', () => { - const placeholder = '10'; - testedComponent.placeholderMax = placeholder; - expect(testedComponent.getPlaceholderMax()).toEqual(placeholder); - }); - - it('#getPlaceholderMax() should not fill the placeholder if not defined', () => { - expect(testedComponent.getPlaceholderMax()).toEqual(''); - }); - - it('raises the add criterion event when clicked', () => { - testedComponent.id = 1; - const min = '10'; - const max = '20'; - testedComponent.fieldMin = new FormControl(min); - testedComponent.fieldMax = new FormControl(max); - const expectedCriterion = { id: testedComponent.id, type: 'between', min, max } as BetweenCriterion; - testedComponent.addCriterion.subscribe((event: BetweenCriterion) => expect(event).toEqual(expectedCriterion)); - testedComponent.emitAdd(); - }); - - it('raises the delete criterion event when clicked', () => { - testedComponent.id = 1; - testedComponent.deleteCriterion.subscribe((event: number) => expect(event).toEqual(1)); - testedComponent.emitDelete(); - }); -}); diff --git a/client/src/app/instance/search/components/criteria/search-type/checkbox.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/checkbox.component.spec.ts deleted file mode 100644 index 0c10c5ec..00000000 --- a/client/src/app/instance/search/components/criteria/search-type/checkbox.component.spec.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { Component, ViewChild } from '@angular/core'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { FormsModule, ReactiveFormsModule, FormControl, FormArray } from '@angular/forms'; - -import { CheckboxComponent } from './checkbox.component'; -import { SelectMultipleCriterion } from '../../../store/model'; -import { Option } from '../../../../metamodel/model'; - -describe('[Search][Criteria][SearchType] Component: CheckboxComponent', () => { - @Component({ - selector: `app-host`, - template: `<app-checkbox [options]='options' [criterion]='criterion'></app-checkbox>` - }) - class TestHostComponent { - @ViewChild(CheckboxComponent, { static: false }) - public testedComponent: CheckboxComponent; - public criterion: SelectMultipleCriterion = undefined; - public options: Option[] = [ - { label: 'One', value: 'one', display: 1 }, - { label: 'Two', value: 'two', display: 2 }, - { label: 'Three', value: 'three', display: 3 } - ]; - } - - let testHostComponent: TestHostComponent; - let testHostFixture: ComponentFixture<TestHostComponent>; - let testedComponent: CheckboxComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [CheckboxComponent, TestHostComponent], - imports: [FormsModule, ReactiveFormsModule] - }); - testHostFixture = TestBed.createComponent(TestHostComponent); - testHostComponent = testHostFixture.componentInstance; - testHostFixture.detectChanges(); - testedComponent = testHostComponent.testedComponent; - })); - - it('should create the component', () => { - expect(testedComponent).toBeTruthy(); - }); - - it('#getDefault() should not fill and enable form if criterion not defined', () => { - expect(testedComponent.checkboxes.length).toEqual(3); - expect(testedComponent.isChecked()).toBeFalsy(); - expect(testedComponent.checkboxes.enabled).toBeTruthy(); - }); - - it('#getDefault() should fill and disable form if criterion is defined', () => { - const options: Option[] = [ - { label: 'One', value: 'one', display: 1 }, - { label: 'Two', value: 'two', display: 2 } - ]; - const criterion = { id: 1, type: 'multiple', options} as SelectMultipleCriterion; - testedComponent.getDefault(criterion); - expect(testedComponent.isChecked()).toBeTruthy(); - const values = testedComponent.checkboxes.value as boolean[]; - expect(values.filter(v => v).length).toEqual(2); - }); - - it('raises the add criterion event when clicked', () => { - testedComponent.id = 1; - testedComponent.checkboxes = new FormArray([ - new FormControl(false), - new FormControl(true), - new FormControl(true) - ]) - const expectedCriterion = { - id: 1, - type: 'multiple', - options: [ - { label: 'Two', value: 'two', display: 2 }, - { label: 'Three', value: 'three', display: 3 } - ] - }; - testedComponent.addCriterion.subscribe((event: SelectMultipleCriterion) => expect(event).toEqual(expectedCriterion)); - testedComponent.emitAdd(); - }); - - it('raises the delete criterion event when clicked', () => { - testedComponent.id = 1; - testedComponent.deleteCriterion.subscribe((event: number) => expect(event).toEqual(1)); - testedComponent.emitDelete(); - }); -}); diff --git a/client/src/app/instance/search/components/criteria/search-type/datalist.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/datalist.component.spec.ts deleted file mode 100644 index 588ac8c5..00000000 --- a/client/src/app/instance/search/components/criteria/search-type/datalist.component.spec.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core'; -import { FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms'; - -import { DatalistComponent } from './datalist.component'; -import { FieldCriterion } from '../../../store/model'; - -describe('[Search][Criteria][SearchType] Component: DatalistComponent', () => { - @Component({ - selector: `app-host`, - template: `<app-datalist [criterion]='criterion'></app-datalist>` - }) - class TestHostComponent { - @ViewChild(DatalistComponent, { static: false }) - public testedComponent: DatalistComponent; - public criterion: FieldCriterion = undefined; - } - - @Component({ selector: 'app-operator', template: '' }) - class OperatorStubComponent { - @Input() operator: string; - @Input() searchType: string; - @Input() advancedForm: boolean; - @Input() disabled: boolean; - @Output() changeOperator: EventEmitter<string> = new EventEmitter(); - } - - @Component({ selector: 'app-help-like', template: '' }) - class HelpLikeStubComponent { } - - let testHostComponent: TestHostComponent; - let testHostFixture: ComponentFixture<TestHostComponent>; - let testedComponent: DatalistComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [ - DatalistComponent, - TestHostComponent, - OperatorStubComponent, - HelpLikeStubComponent - ], - imports: [FormsModule, ReactiveFormsModule] - }); - testHostFixture = TestBed.createComponent(TestHostComponent); - testHostComponent = testHostFixture.componentInstance; - testHostFixture.detectChanges(); - testedComponent = testHostComponent.testedComponent; - })); - - it('should create the component', () => { - expect(testedComponent).toBeTruthy(); - }); - - it('#getDefault() should enable and not fill form as criterion not defined in host component', () => { - expect(testedComponent.field.value).toBeNull(); - expect(testedComponent.field.enabled).toBeTruthy(); - }); - - it('#getDefault() should fill and disable form if criterion is defined', () => { - const value = '10'; - const criterion = { id: 1, type: 'field', operator: 'eq', value } as FieldCriterion; - const expectedFieldValue = value; - testedComponent.getDefault(criterion); - expect(testedComponent.field.value).toEqual(expectedFieldValue); - expect(testedComponent.field.disabled).toBeTruthy(); - }); - - it('#getPlaceholder() should fill the placeholder if defined', () => { - const placeholder = '10'; - testedComponent.placeholder = placeholder; - expect(testedComponent.getPlaceholder()).toEqual(placeholder); - }); - - it('#getPlaceholder() should not fill the placeholder if not defined', () => { - expect(testedComponent.getPlaceholder()).toEqual(''); - }); - - it('#getDatalistId() should return an id', () => { - testedComponent.id = 1; - expect(testedComponent.getDatalistId()).toEqual('datalist_' + 1); - }); - - it('#changeOperator() should change the operator', () => { - expect(testedComponent.operator).toBeUndefined(); - testedComponent.changeOperator('toto'); - expect(testedComponent.operator).toBe('toto'); - }); - - it('raises the add criterion event when clicked', () => { - testedComponent.id = 1; - const operator = '='; - const value = '10'; - testedComponent.field = new FormControl(value); - testedComponent.operator = operator; - const expectedCriterion = { id: testedComponent.id, type: 'field', operator, value } as FieldCriterion; - testedComponent.addCriterion.subscribe((event: FieldCriterion) => expect(event).toEqual(expectedCriterion)); - testedComponent.emitAdd(); - }); - - it('raises the delete criterion event when clicked', () => { - testedComponent.id = 1; - testedComponent.deleteCriterion.subscribe((event: number) => expect(event).toEqual(1)); - testedComponent.emitDelete(); - }); -}); diff --git a/client/src/app/instance/search/components/criteria/search-type/date.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/date.component.spec.ts deleted file mode 100644 index a67b65f6..00000000 --- a/client/src/app/instance/search/components/criteria/search-type/date.component.spec.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms'; - -import { BsDatepickerModule } from 'ngx-bootstrap/datepicker'; - -import { DateComponent } from './date.component'; -import { FieldCriterion } from '../../../store/model'; - -describe('[Search][Criteria][SearchType] Component: DateComponent', () => { - @Component({ - selector: `app-host`, - template: `<app-date [criterion]='criterion'></app-date>` - }) - class TestHostComponent { - @ViewChild(DateComponent, { static: false }) - public testedComponent: DateComponent; - public criterion: FieldCriterion = undefined; - } - - @Component({ selector: 'app-operator', template: '' }) - class OperatorStubComponent { - @Input() operator: string; - @Input() searchType: string; - @Input() advancedForm: boolean; - @Input() disabled: boolean; - @Output() changeOperator: EventEmitter<string> = new EventEmitter(); - } - - let testHostComponent: TestHostComponent; - let testHostFixture: ComponentFixture<TestHostComponent>; - let testedComponent: DateComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [ - DateComponent, - TestHostComponent, - OperatorStubComponent - ], - imports: [BsDatepickerModule.forRoot(), FormsModule, ReactiveFormsModule] - }); - testHostFixture = TestBed.createComponent(TestHostComponent); - testHostComponent = testHostFixture.componentInstance; - testHostFixture.detectChanges(); - testedComponent = testHostComponent.testedComponent; - })); - - it('should create the component', () => { - expect(testedComponent).toBeTruthy(); - }); - - it('#getDefault() should enable and not fill form as criterion not defined in host component', () => { - expect(testedComponent.field.value).toBeNull(); - expect(testedComponent.field.enabled).toBeTruthy(); - }); - - it('#getDefault() should fill and disable form if criterion is defined', () => { - const value = '2019-02-17'; - const criterion = { id: 1, type: 'field', operator: 'eq', value } as FieldCriterion; - const expectedFieldValue = new Date(value); - testedComponent.getDefault(criterion); - expect(testedComponent.field.value).toEqual(expectedFieldValue); - expect(testedComponent.field.disabled).toBeTruthy(); - }); - - it('#getPlaceholder() should fill the placeholder if defined', () => { - const placeholder = '2019-02-17'; - testedComponent.placeholder = placeholder; - expect(testedComponent.getPlaceholder()).toEqual(placeholder); - }); - - it('#getPlaceholder() should not fill the placeholder if not defined', () => { - expect(testedComponent.getPlaceholder()).toEqual(''); - }); - - it('#getDateString() should return a date as string', () => { - const dateString = '2019-02-17'; - const date = new Date(dateString); - expect(testedComponent.getDateString(date)).toEqual(dateString); - }); - - it('#changeOperator() should change the operator', () => { - expect(testedComponent.operator).toBeUndefined(); - testedComponent.changeOperator('toto'); - expect(testedComponent.operator).toBe('toto'); - }); - - it('raises the add criterion event when clicked', () => { - testedComponent.id = 1; - const operator = '='; - testedComponent.operator = operator; - const date = '2019-02-17'; - testedComponent.field = new FormControl(new Date(date)); - const expectedCriterion = { id: testedComponent.id, type: 'field', operator, value: date } as FieldCriterion; - testedComponent.addCriterion.subscribe((event: FieldCriterion) => expect(event).toEqual(expectedCriterion)); - testedComponent.emitAdd(); - }); - - it('raises the delete criterion event when clicked', () => { - testedComponent.id = 1; - testedComponent.deleteCriterion.subscribe((event: number) => expect(event).toEqual(1)); - testedComponent.emitDelete(); - }); -}); diff --git a/client/src/app/instance/search/components/criteria/search-type/datetime.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/datetime.component.spec.ts deleted file mode 100644 index 045aeeee..00000000 --- a/client/src/app/instance/search/components/criteria/search-type/datetime.component.spec.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms'; - -import { BsDatepickerModule } from 'ngx-bootstrap/datepicker'; -import { NgSelectModule } from '@ng-select/ng-select'; - -import { DatetimeComponent } from './datetime.component'; -import { FieldCriterion } from '../../../store/model'; - -describe('[Search][Criteria][SearchType] Component: DatetimeComponent', () => { - @Component({ - selector: `app-host`, - template: `<app-datetime [criterion]='criterion'></app-datetime>` - }) - class TestHostComponent { - @ViewChild(DatetimeComponent, { static: false }) - public testedComponent: DatetimeComponent; - public criterion: FieldCriterion = undefined; - } - - @Component({ selector: 'app-operator', template: '' }) - class OperatorStubComponent { - @Input() operator: string; - @Input() searchType: string; - @Input() advancedForm: boolean; - @Input() disabled: boolean; - @Output() changeOperator: EventEmitter<string> = new EventEmitter(); - } - - let testHostComponent: TestHostComponent; - let testHostFixture: ComponentFixture<TestHostComponent>; - let testedComponent: DatetimeComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [ - DatetimeComponent, - TestHostComponent, - OperatorStubComponent - ], - imports: [BsDatepickerModule.forRoot(), NgSelectModule, FormsModule, ReactiveFormsModule] - }); - testHostFixture = TestBed.createComponent(TestHostComponent); - testHostComponent = testHostFixture.componentInstance; - testHostFixture.detectChanges(); - testedComponent = testHostComponent.testedComponent; - })); - - it('should create the component', () => { - expect(testedComponent).toBeTruthy(); - }); - - it('#getDefault() should enable and not fill form as criterion not defined in host component', () => { - expect(testedComponent.date.value).toBeNull(); - expect(testedComponent.date.enabled).toBeTruthy(); - expect(testedComponent.hh.value).toBeNull(); - expect(testedComponent.hh.enabled).toBeTruthy(); - expect(testedComponent.mm.value).toBeNull(); - expect(testedComponent.mm.enabled).toBeTruthy(); - expect(testedComponent.isValidFields).toBeFalsy(); - }); - - it('#getDefault() should fill and disable form if criterion is defined', () => { - const value = '2019-02-17 15:47'; - const criterion = { id: 1, type: 'field', operator: 'eq', value } as FieldCriterion; - const expectedDate = new Date('2019-02-17'); - const expectedHour = '15'; - const expectedMinute = '47'; - testedComponent.getDefault(criterion); - expect(testedComponent.date.value).toEqual(expectedDate); - expect(testedComponent.date.disabled).toBeTruthy(); - expect(testedComponent.hh.value).toEqual(expectedHour); - expect(testedComponent.hh.disabled).toBeTruthy(); - expect(testedComponent.mm.value).toEqual(expectedMinute); - expect(testedComponent.mm.disabled).toBeTruthy(); - expect(testedComponent.isValidFields).toBeTruthy(); - }); - - it('#initTime(t) should return an array of string with 2 digits from 0 to t', () => { - const n = 10; - expect(testedComponent.initTime(n).length).toEqual(n); - expect(testedComponent.initTime(n)[5]).toEqual('05'); - }); - - it('#change() should set #isValidFields to false if one or more fields are not defined', () => { - testedComponent.change(); - expect(testedComponent.isValidFields).toBeFalsy(); - testedComponent.hh = new FormControl('15'); - testedComponent.change(); - expect(testedComponent.isValidFields).toBeFalsy(); - testedComponent.mm = new FormControl('47'); - testedComponent.change(); - expect(testedComponent.isValidFields).toBeFalsy(); - testedComponent.date = new FormControl(new Date('2019-02-17')); - testedComponent.change(); - expect(testedComponent.isValidFields).toBeTruthy(); - }); - - it('#change() should set #datetime with fields value when defined', () => { - testedComponent.date = new FormControl(new Date('2019-02-17')); - testedComponent.hh = new FormControl('15'); - testedComponent.mm = new FormControl('47'); - testedComponent.change(); - expect(testedComponent.datetime).toEqual(new Date('2019-02-17 15:47')); - }); - - it('#changeOperator() should change the operator', () => { - expect(testedComponent.operator).toBeUndefined(); - testedComponent.changeOperator('toto'); - expect(testedComponent.operator).toBe('toto'); - }); - - it('raises the add criterion event when clicked', () => { - testedComponent.id = 1; - const operator = '='; - testedComponent.operator = operator; - testedComponent.datetime = new Date('2019-02-17 15:47'); - testedComponent.hh = new FormControl('15'); - testedComponent.mm = new FormControl('47'); - const expectedCriterion = { id: testedComponent.id, type: 'field', operator, value: '2019-02-17 15:47' } as FieldCriterion; - testedComponent.addCriterion.subscribe((event: FieldCriterion) => expect(event).toEqual(expectedCriterion)); - testedComponent.emitAdd(); - }); - - it('raises the delete criterion event when clicked', () => { - testedComponent.id = 1; - testedComponent.deleteCriterion.subscribe((event: number) => expect(event).toEqual(1)); - testedComponent.emitDelete(); - }); -}); diff --git a/client/src/app/instance/search/components/criteria/search-type/field.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/field.component.spec.ts deleted file mode 100644 index 4c7d5512..00000000 --- a/client/src/app/instance/search/components/criteria/search-type/field.component.spec.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms'; - -import { FieldComponent } from './field.component'; -import { FieldCriterion } from '../../../store/model'; - -describe('[Search][Criteria][SearchType] Component: FieldComponent', () => { - @Component({ - selector: `app-host`, - template: `<app-field [criterion]='criterion'></app-field>` - }) - class TestHostComponent { - @ViewChild(FieldComponent, { static: false }) - public testedComponent: FieldComponent; - public criterion: FieldCriterion = undefined; - } - - @Component({ selector: 'app-operator', template: '' }) - class OperatorStubComponent { - @Input() operator: string; - @Input() searchType: string; - @Input() advancedForm: boolean; - @Input() disabled: boolean; - @Output() changeOperator: EventEmitter<string> = new EventEmitter(); - } - - @Component({ selector: 'app-help-like', template: '' }) - class HelpLikeStubComponent { } - - let testHostComponent: TestHostComponent; - let testHostFixture: ComponentFixture<TestHostComponent>; - let testedComponent: FieldComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [ - FieldComponent, - TestHostComponent, - OperatorStubComponent, - HelpLikeStubComponent - ], - imports: [FormsModule, ReactiveFormsModule] - }); - testHostFixture = TestBed.createComponent(TestHostComponent); - testHostComponent = testHostFixture.componentInstance; - testHostFixture.detectChanges(); - testedComponent = testHostComponent.testedComponent; - })); - - it('should create the component', () => { - expect(testedComponent).toBeTruthy(); - }); - - it('#getDefault() should enable and not fill form as criterion not defined in host component', () => { - expect(testedComponent.field.value).toBeNull(); - expect(testedComponent.field.enabled).toBeTruthy(); - }); - - it('#getDefault() should fill and disable form if criterion is defined', () => { - const value = 'test'; - const criterion = { id: 1, type: 'field', operator: 'eq', value } as FieldCriterion; - const expectedFieldValue = value; - testedComponent.getDefault(criterion); - expect(testedComponent.field.value).toEqual(expectedFieldValue); - expect(testedComponent.field.disabled).toBeTruthy(); - }); - - it('#getType() should return `number` if criterion is a number type', () => { - testedComponent.attributeType = 'smallint'; - expect(testedComponent.getType()).toEqual('number'); - testedComponent.attributeType = 'integer'; - expect(testedComponent.getType()).toEqual('number'); - testedComponent.attributeType = 'decimal'; - expect(testedComponent.getType()).toEqual('number'); - testedComponent.attributeType = 'float'; - expect(testedComponent.getType()).toEqual('number'); - }); - - it('#getType() should return `text` if criterion is not a number type', () => { - testedComponent.attributeType = 'char'; - expect(testedComponent.getType()).toEqual('text'); - }); - - it('#getPlaceholder() should fill the placeholder if defined', () => { - const placeholder = 'placeholder'; - testedComponent.placeholder = placeholder; - expect(testedComponent.getPlaceholder()).toEqual(placeholder); - }); - - it('#getPlaceholder() should not fill the placeholder if not defined', () => { - expect(testedComponent.getPlaceholder()).toEqual(''); - }); - - it('#changeOperator() should change the operator', () => { - expect(testedComponent.operator).toBeUndefined(); - testedComponent.changeOperator('toto'); - expect(testedComponent.operator).toBe('toto'); - }); - - it('raises the add criterion event when clicked', () => { - testedComponent.id = 1; - const operator = '='; - testedComponent.operator = operator; - const value = 'test'; - testedComponent.field = new FormControl(value); - const expectedCriterion = { id: testedComponent.id, type: 'field', operator, value } as FieldCriterion; - testedComponent.addCriterion.subscribe((event: FieldCriterion) => expect(event).toEqual(expectedCriterion)); - testedComponent.emitAdd(); - }); - - it('raises the delete criterion event when clicked', () => { - testedComponent.id = 1; - testedComponent.deleteCriterion.subscribe((event: number) => expect(event).toEqual(1)); - testedComponent.emitDelete(); - }); -}); diff --git a/client/src/app/instance/search/components/criteria/search-type/help-like.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/help-like.component.spec.ts deleted file mode 100644 index 62a5a611..00000000 --- a/client/src/app/instance/search/components/criteria/search-type/help-like.component.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { HelpLikeComponent } from './help-like.component'; - -describe('[Search][Criteria][SearchType] Component: HelpLikeComponent', () => { - let component: HelpLikeComponent; - let fixture: ComponentFixture<HelpLikeComponent>; - - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [HelpLikeComponent] - }); - fixture = TestBed.createComponent(HelpLikeComponent); - component = fixture.componentInstance; - }); - - it('should create the component', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/client/src/app/instance/search/components/criteria/search-type/json.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/json.component.spec.ts deleted file mode 100644 index 29767ff5..00000000 --- a/client/src/app/instance/search/components/criteria/search-type/json.component.spec.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { Component, ViewChild } from '@angular/core'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; - -import { JsonComponent } from './json.component'; -import { JsonCriterion } from '../../../store/model'; - -describe('[Search][Criteria][SearchType] Component: JsonComponent', () => { - @Component({ - selector: `app-host`, - template: `<app-json-criteria [criterion]='criterion'></app-json-criteria>` - }) - class TestHostComponent { - @ViewChild(JsonComponent, { static: false }) - public testedComponent: JsonComponent; - public criterion: JsonCriterion = undefined; - } - - let testHostComponent: TestHostComponent; - let testHostFixture: ComponentFixture<TestHostComponent>; - let testedComponent: JsonComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [JsonComponent, TestHostComponent], - imports: [FormsModule, ReactiveFormsModule] - }); - testHostFixture = TestBed.createComponent(TestHostComponent); - testHostComponent = testHostFixture.componentInstance; - testHostFixture.detectChanges(); - testedComponent = testHostComponent.testedComponent; - })); - - it('should create the component', () => { - expect(testedComponent).toBeTruthy(); - }); - - it('#getDefault() should enable and not fill form as criterion not defined in host component', () => { - expect(testedComponent.jsonForm.controls.path.value).toBeNull(); - expect(testedComponent.jsonForm.controls.operator.value).toBeNull(); - expect(testedComponent.jsonForm.controls.value.value).toBeNull(); - expect(testedComponent.jsonForm.enabled).toBeTruthy(); - }); - - it('#getDefault() should fill and disable form if criterion is defined', () => { - const path = 'path'; - const operator = '='; - const value = 'test'; - const criterion = { id: 1, type: 'json', path, operator, value } as JsonCriterion; - testedComponent.getDefault(criterion); - expect(testedComponent.jsonForm.controls.path.value).toEqual(path); - expect(testedComponent.jsonForm.controls.operator.value).toEqual(operator); - expect(testedComponent.jsonForm.controls.value.value).toEqual(value); - expect(testedComponent.jsonForm.disabled).toBeTruthy(); - }); - - it('raises the add criterion event when clicked', () => { - testedComponent.id = 1; - const path = 'path'; - const operator = '='; - const value = 'test'; - testedComponent.jsonForm.controls.path.setValue(path); - testedComponent.jsonForm.controls.operator.setValue(operator); - testedComponent.jsonForm.controls.value.setValue(value); - const expectedCriterion = { id: testedComponent.id, type: 'json', path, operator, value } as JsonCriterion; - testedComponent.addCriterion.subscribe((event: JsonCriterion) => expect(event).toEqual(expectedCriterion)); - testedComponent.emitAdd(); - }); - - it('raises the delete criterion event when clicked', () => { - testedComponent.id = 1; - testedComponent.deleteCriterion.subscribe((event: number) => expect(event).toEqual(1)); - testedComponent.emitDelete(); - }); -}); diff --git a/client/src/app/instance/search/components/criteria/search-type/list.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/list.component.spec.ts deleted file mode 100644 index d08f64b7..00000000 --- a/client/src/app/instance/search/components/criteria/search-type/list.component.spec.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { Component, ViewChild } from '@angular/core'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms'; - -import { ListComponent } from './list.component'; -import { ListCriterion } from '../../../store/model'; - -describe('[Search][Criteria][SearchType] Component: ListComponent', () => { - @Component({ - selector: `app-host`, - template: `<app-list [criterion]='criterion'></app-list>` - }) - class TestHostComponent { - @ViewChild(ListComponent, { static: false }) - public testedComponent: ListComponent; - public criterion: ListComponent = undefined; - } - - let testHostComponent: TestHostComponent; - let testHostFixture: ComponentFixture<TestHostComponent>; - let testedComponent: ListComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [ - ListComponent, - TestHostComponent - ], - imports: [FormsModule, ReactiveFormsModule] - }); - testHostFixture = TestBed.createComponent(TestHostComponent); - testHostComponent = testHostFixture.componentInstance; - testHostFixture.detectChanges(); - testedComponent = testHostComponent.testedComponent; - })); - - it('should create the component', () => { - expect(testedComponent).toBeTruthy(); - }); - - it('#getDefault() should enable and not fill form as criterion not defined in host component', () => { - expect(testedComponent.list.value).toBeNull(); - expect(testedComponent.list.enabled).toBeTruthy(); - }); - - it('#getDefault() should fill and disable form if criterion is defined', () => { - const values = ['1', '2']; - const criterion = { id: 1, type: 'list', values } as ListCriterion; - const expectedListValues = values.join('\n'); - testedComponent.getDefault(criterion); - expect(testedComponent.list.value).toBe(expectedListValues); - expect(testedComponent.list.disabled).toBeTruthy(); - }); - - it('#getPlaceholder() should fill the placeholder if defined', () => { - const placeholder = 'placeholder'; - testedComponent.placeholder = placeholder; - expect(testedComponent.getPlaceholder()).toBe(placeholder); - }); - - it('#getPlaceholder() should not fill the placeholder if not defined', () => { - expect(testedComponent.getPlaceholder()).toBe(''); - }); - - it('raises the add criterion event when clicked', () => { - testedComponent.id = 1; - const values = '1\n2'; - testedComponent.list = new FormControl(values); - const expectedCriterion = { id: testedComponent.id, type: 'list', values: ['1', '2'] } as ListCriterion; - testedComponent.addCriterion.subscribe((event: ListCriterion) => expect(event).toEqual(expectedCriterion)); - testedComponent.emitAdd(); - }); -}); diff --git a/client/src/app/instance/search/components/criteria/search-type/operator.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/operator.component.spec.ts deleted file mode 100644 index cec4db09..00000000 --- a/client/src/app/instance/search/components/criteria/search-type/operator.component.spec.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { Component, ViewChild } from '@angular/core'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; - -import { OperatorComponent } from './operator.component'; - -describe('[Search][Criteria][SearchType] Component: OperatorComponent', () => { - @Component({ - selector: `app-host`, - template: ` - <app-operator - [operator]='operator' - [searchType]='searchType' - [advancedForm]='advancedForm' - [disabled]='disabled'> - </app-operator>` - }) - class TestHostComponent { - @ViewChild(OperatorComponent, { static: false }) - testedComponent: OperatorComponent; - operator = 'eq'; - searchType: string = undefined; - advancedForm: boolean = undefined; - disabled: boolean = undefined; - } - - let testHostComponent: TestHostComponent; - let testHostFixture: ComponentFixture<TestHostComponent>; - let testedComponent: OperatorComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [OperatorComponent, TestHostComponent], - imports: [FormsModule, ReactiveFormsModule] - }); - testHostFixture = TestBed.createComponent(TestHostComponent); - testHostComponent = testHostFixture.componentInstance; - testHostFixture.detectChanges(); - testedComponent = testHostComponent.testedComponent; - })); - - it('should create the component', () => { - expect(testedComponent).toBeTruthy(); - }); - - it('#getLabel() should return the correct operator form label', () => { - expect(testedComponent.getLabel('eq')).toBe('='); - expect(testedComponent.getLabel('neq')).toBe('≠'); - expect(testedComponent.getLabel('gt')).toBe('>'); - expect(testedComponent.getLabel('gte')).toBe('>='); - expect(testedComponent.getLabel('lt')).toBe('<'); - expect(testedComponent.getLabel('lte')).toBe('<='); - expect(testedComponent.getLabel('lk')).toBe('like'); - expect(testedComponent.getLabel('nlk')).toBe('not like'); - }); - - it('raises the changeOperator event when the value change', () => { - testedComponent.changeOperator.subscribe((event: string) => expect(event).toEqual('eq')); - testedComponent.emitChange('eq'); - }); - - it('should display the select box when it\'s an enabled advanced form', () => { - testHostComponent.advancedForm = true; - testHostComponent.disabled = false; - testHostFixture.detectChanges(); - const template = testHostFixture.nativeElement; - expect(template.querySelector('select')).toBeTruthy(); - expect(template.querySelector('.readonly')).toBeFalsy(); - }); - - it('should display the readonly field when it\'s not an advanced form or not enabled advanced form', () => { - testHostComponent.advancedForm = true; - testHostComponent.disabled = true; - testHostFixture.detectChanges(); - const template = testHostFixture.nativeElement; - expect(template.querySelector('select')).toBeFalsy(); - expect(template.querySelector('.readonly')).toBeTruthy(); - testHostComponent.advancedForm = true; - testHostFixture.detectChanges(); - expect(template.querySelector('select')).toBeFalsy(); - expect(template.querySelector('.readonly')).toBeTruthy(); - }); -}); diff --git a/client/src/app/instance/search/components/criteria/search-type/radio.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/radio.component.spec.ts deleted file mode 100644 index e6b5658f..00000000 --- a/client/src/app/instance/search/components/criteria/search-type/radio.component.spec.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { Component, ViewChild } from '@angular/core'; -import { FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms'; - -import { RadioComponent } from './radio.component'; -import { FieldCriterion } from '../../../store/model'; - -describe('[Search][Criteria][SearchType] Component: RadioComponent', () => { - @Component({ - selector: `app-host`, - template: `<app-radio [criterion]='criterion'></app-radio>` - }) - class TestHostComponent { - @ViewChild(RadioComponent, { static: false }) - public testedComponent: RadioComponent; - public criterion: FieldCriterion = undefined; - } - - let testHostComponent: TestHostComponent; - let testHostFixture: ComponentFixture<TestHostComponent>; - let testedComponent: RadioComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [RadioComponent, TestHostComponent], - imports: [FormsModule, ReactiveFormsModule] - }); - testHostFixture = TestBed.createComponent(TestHostComponent); - testHostComponent = testHostFixture.componentInstance; - testHostFixture.detectChanges(); - testedComponent = testHostComponent.testedComponent; - })); - - it('should create the component', () => { - expect(testedComponent).toBeTruthy(); - }); - - it('#getDefault() should enable and not fill form as criterion not defined in host component', () => { - expect(testedComponent.radio.value).toBeNull(); - expect(testedComponent.radio.enabled).toBeTruthy(); - }); - - it('#getDefault() should fill and disable form if criterion is defined', () => { - const operator = '='; - const value = 'test'; - const criterion = { id: 1, type: 'field', operator, value } as FieldCriterion; - testedComponent.getDefault(criterion); - expect(testedComponent.radio.value).toEqual(value); - expect(testedComponent.radio.disabled).toBeTruthy(); - }); - - it('raises the add criterion event when clicked', () => { - testedComponent.id = 1; - const operator = '='; - testedComponent.operator = operator; - const value = 'three'; - testedComponent.radio = new FormControl(value); - testedComponent.options = [ - { label: 'One', value: 'one', display: 1 }, - { label: 'Two', value: 'two', display: 2 }, - { label: 'Three', value: 'three', display: 3 } - ]; - const expectedCriterion = { id: testedComponent.id, type: 'field', operator, value } as FieldCriterion; - testedComponent.addCriterion.subscribe((event: FieldCriterion) => expect(event).toEqual(expectedCriterion)); - testedComponent.emitAdd(); - }); - - it('raises the delete criterion event when clicked', () => { - testedComponent.id = 1; - testedComponent.deleteCriterion.subscribe((event: number) => expect(event).toEqual(1)); - testedComponent.emitDelete(); - }); -}); diff --git a/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.spec.ts deleted file mode 100644 index e6f8ccfd..00000000 --- a/client/src/app/instance/search/components/criteria/search-type/select-multiple.component.spec.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { Component, ViewChild } from '@angular/core'; -import { FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms'; - -import { NgSelectModule } from '@ng-select/ng-select'; - -import { SelectMultipleComponent } from './select-multiple.component'; -import { SelectMultipleCriterion } from '../../../store/model'; - -describe('[Search][Criteria][SearchType] Component: SelectMultipleComponent', () => { - @Component({ - selector: `app-host`, - template: `<app-select-multiple [criterion]='criterion'></app-select-multiple>` - }) - class TestHostComponent { - @ViewChild(SelectMultipleComponent, { static: false }) - public testedComponent: SelectMultipleComponent; - public criterion: SelectMultipleCriterion = undefined; - } - - let testHostComponent: TestHostComponent; - let testHostFixture: ComponentFixture<TestHostComponent>; - let testedComponent: SelectMultipleComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [SelectMultipleComponent, TestHostComponent], - imports: [NgSelectModule, FormsModule, ReactiveFormsModule] - }); - testHostFixture = TestBed.createComponent(TestHostComponent); - testHostComponent = testHostFixture.componentInstance; - testHostFixture.detectChanges(); - testedComponent = testHostComponent.testedComponent; - })); - - it('should create the component', () => { - expect(testedComponent).toBeTruthy(); - }); - - it('#getDefault() should enable and not fill form as criterion not defined in host component', () => { - expect(testedComponent.ms.value).toBeNull(); - expect(testedComponent.ms.enabled).toBeTruthy(); - }); - - it('#getDefault() should fill and disable form if criterion is defined', () => { - const options = [ - { label: 'One', value: 'one', display: 1 }, - { label: 'Two', value: 'two', display: 2 }, - { label: 'Three', value: 'three', display: 3 } - ]; - const criterion = { id: 1, type: 'multiple', options} as SelectMultipleCriterion; - testedComponent.getDefault(criterion); - expect(testedComponent.ms.value).toEqual(['one', 'two', 'three']); - expect(testedComponent.ms.disabled).toBeTruthy(); - }); - - it('raises the add criterion event when clicked', () => { - testedComponent.id = 1; - testedComponent.options = [ - { label: 'One', value: 'one', display: 1 }, - { label: 'Two', value: 'two', display: 2 }, - { label: 'Three', value: 'three', display: 3 } - ]; - const value = ['three']; - testedComponent.ms = new FormControl(value); - const expectedValue = [ - { label: 'Three', value: 'three', display: 3 } - ]; - const expectedCriterion = { id: testedComponent.id, type: 'multiple', options: expectedValue } as SelectMultipleCriterion; - testedComponent.addCriterion.subscribe((event: SelectMultipleCriterion) => expect(event).toEqual(expectedCriterion)); - testedComponent.emitAdd(); - }); - - it('raises the delete criterion event when clicked', () => { - testedComponent.id = 1; - testedComponent.deleteCriterion.subscribe((event: number) => expect(event).toEqual(1)); - testedComponent.emitDelete(); - }); -}); diff --git a/client/src/app/instance/search/components/criteria/search-type/select.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/select.component.spec.ts deleted file mode 100644 index 05f8edff..00000000 --- a/client/src/app/instance/search/components/criteria/search-type/select.component.spec.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core'; -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms'; - -import { NgSelectModule } from '@ng-select/ng-select'; - -import { SelectComponent } from './select.component'; -import { FieldCriterion } from '../../../store/model'; - -describe('[Search][Criteria][SearchType] Component: SelectComponent', () => { - @Component({ - selector: `app-host`, - template: `<app-select [criterion]='criterion'></app-select>` - }) - class TestHostComponent { - @ViewChild(SelectComponent, { static: false }) - public testedComponent: SelectComponent; - public criterion: FieldCriterion = undefined; - } - - @Component({ selector: 'app-operator', template: '' }) - class OperatorStubComponent { - @Input() operator: string; - @Input() searchType: string; - @Input() advancedForm: boolean; - @Input() disabled: boolean; - @Output() changeOperator: EventEmitter<string> = new EventEmitter(); - } - - @Component({ selector: 'app-help-like', template: '' }) - class HelpLikeStubComponent { } - - let testHostComponent: TestHostComponent; - let testHostFixture: ComponentFixture<TestHostComponent>; - let testedComponent: SelectComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [ - SelectComponent, - TestHostComponent, - OperatorStubComponent, - HelpLikeStubComponent - ], - imports: [NgSelectModule, FormsModule, ReactiveFormsModule] - }); - testHostFixture = TestBed.createComponent(TestHostComponent); - testHostComponent = testHostFixture.componentInstance; - testHostFixture.detectChanges(); - testedComponent = testHostComponent.testedComponent; - })); - - it('should create the component', () => { - expect(testedComponent).toBeTruthy(); - }); - - it('#getDefault() should enable and not fill form as criterion not defined in host component', () => { - expect(testedComponent.se.value).toBeNull(); - expect(testedComponent.se.enabled).toBeTruthy(); - }); - - it('#getDefault() should fill and disable form if criterion is defined', () => { - const operator = '='; - const value = 'test'; - const criterion = { id: 1, type: 'field', operator, value } as FieldCriterion; - testedComponent.getDefault(criterion); - expect(testedComponent.se.value).toEqual(value); - expect(testedComponent.se.disabled).toBeTruthy(); - }); - - it('#changeOperator() should change the operator', () => { - expect(testedComponent.operator).toBeUndefined(); - testedComponent.changeOperator('toto'); - expect(testedComponent.operator).toBe('toto'); - }); - - it('raises the add criterion event when clicked', () => { - testedComponent.id = 1; - const operator = '='; - testedComponent.operator = operator; - const value = 'three'; - testedComponent.se = new FormControl(value); - testedComponent.options = [ - { label: 'One', value: 'one', display: 1 }, - { label: 'Two', value: 'two', display: 2 }, - { label: 'Three', value: 'three', display: 3 } - ]; - const expectedCriterion = { id: testedComponent.id, type: 'field', operator, value } as FieldCriterion; - testedComponent.addCriterion.subscribe((event: FieldCriterion) => expect(event).toEqual(expectedCriterion)); - testedComponent.emitAdd(); - }); - - it('raises the delete criterion event when clicked', () => { - testedComponent.id = 1; - testedComponent.deleteCriterion.subscribe((event: number) => expect(event).toEqual(1)); - testedComponent.emitDelete(); - }); -}); diff --git a/client/src/app/instance/search/components/criteria/search-type/time.component.spec.ts b/client/src/app/instance/search/components/criteria/search-type/time.component.spec.ts deleted file mode 100644 index f93f526c..00000000 --- a/client/src/app/instance/search/components/criteria/search-type/time.component.spec.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { Component, Input, Output, EventEmitter, ViewChild } from '@angular/core'; -import { FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms'; - -import { NgSelectModule } from '@ng-select/ng-select'; - -import { TimeComponent } from './time.component'; -import { FieldCriterion } from '../../../store/model'; - -describe('[Search][Criteria][SearchType] Component: TimeComponent', () => { - @Component({ - selector: `app-host`, - template: `<app-time [criterion]='criterion'></app-time>` - }) - class TestHostComponent { - @ViewChild(TimeComponent, { static: false }) - public testedComponent: TimeComponent; - public criterion: FieldCriterion = undefined; - } - - @Component({ selector: 'app-operator', template: '' }) - class OperatorStubComponent { - @Input() operator: string; - @Input() searchType: string; - @Input() advancedForm: boolean; - @Input() disabled: boolean; - @Output() changeOperator: EventEmitter<string> = new EventEmitter(); - } - - let testHostComponent: TestHostComponent; - let testHostFixture: ComponentFixture<TestHostComponent>; - let testedComponent: TimeComponent; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - declarations: [ - TimeComponent, - TestHostComponent, - OperatorStubComponent - ], - imports: [NgSelectModule, FormsModule, ReactiveFormsModule] - }); - testHostFixture = TestBed.createComponent(TestHostComponent); - testHostComponent = testHostFixture.componentInstance; - testHostFixture.detectChanges(); - testedComponent = testHostComponent.testedComponent; - })); - - it('should create the component', () => { - expect(testedComponent).toBeTruthy(); - }); - - it('#getDefault() should enable and not fill form as criterion not defined in host component', () => { - expect(testedComponent.hh.value).toBeNull(); - expect(testedComponent.hh.enabled).toBeTruthy(); - expect(testedComponent.mm.value).toBeNull(); - expect(testedComponent.mm.enabled).toBeTruthy(); - }); - - it('#getDefault() should fill and disable form if criterion is defined', () => { - const criterion = { id: 1, type: 'field', operator: 'eq', value: '15:47' } as FieldCriterion; - const expectedHour = '15'; - const expectedMinute = '47'; - testedComponent.getDefault(criterion); - expect(testedComponent.hh.value).toEqual(expectedHour); - expect(testedComponent.hh.disabled).toBeTruthy(); - expect(testedComponent.mm.value).toEqual(expectedMinute); - expect(testedComponent.mm.disabled).toBeTruthy(); - }); - - it('#initTime(t) should return an array of string with 2 digits from 0 to t', () => { - const n = 10; - expect(testedComponent.initTime(n).length).toEqual(n); - expect(testedComponent.initTime(n)[5]).toEqual('05'); - }); - - it('#changeOperator() should change the operator', () => { - expect(testedComponent.operator).toBeUndefined(); - testedComponent.changeOperator('toto'); - expect(testedComponent.operator).toBe('toto'); - }); - - it('raises the add criterion event when clicked', () => { - testedComponent.id = 1; - const operator = 'eq'; - testedComponent.operator = operator; - testedComponent.hh = new FormControl('15'); - testedComponent.mm = new FormControl('47'); - const expectedCriterion = { id: testedComponent.id, type: 'field', operator, value: '15:47' } as FieldCriterion; - testedComponent.addCriterion.subscribe((event: FieldCriterion) => expect(event).toEqual(expectedCriterion)); - testedComponent.emitAdd(); - }); - - it('raises the delete criterion event when clicked', () => { - testedComponent.id = 1; - testedComponent.deleteCriterion.subscribe((event: number) => expect(event).toEqual(1)); - testedComponent.emitDelete(); - }); -}); diff --git a/client/src/app/instance/search/components/result/download.component.ts b/client/src/app/instance/search/components/result/download.component.ts index aedba808..729dfe59 100644 --- a/client/src/app/instance/search/components/result/download.component.ts +++ b/client/src/app/instance/search/components/result/download.component.ts @@ -13,6 +13,7 @@ import { Criterion, criterionToString } from '../../../store/models'; import { Dataset } from 'src/app/metamodel/models'; import { getHost as host } from 'src/app/shared/utils'; // import { ConeSearch } from '../../../shared/cone-search/store/model'; +import { AppConfigService } from 'src/app/app-config.service'; @Component({ selector: 'app-download', @@ -36,6 +37,8 @@ export class DownloadComponent { @Input() sampRegistered: boolean; @Output() broadcast: EventEmitter<string> = new EventEmitter(); + constructor(private appConfig: AppConfigService) { } + /** * Returns dataset label. * @@ -76,7 +79,7 @@ export class DownloadComponent { * @return string */ getUrl(format: string): string { - let query: string = host() + '/search/' + this.datasetSelected + '?a=' + this.outputList.join(';'); + let query: string = host(this.appConfig.apiUrl) + '/search/' + this.datasetSelected + '?a=' + this.outputList.join(';'); if (this.criteriaList.length > 0) { query += '&c=' + this.criteriaList.map(criterion => criterionToString(criterion)).join(';'); } @@ -88,7 +91,7 @@ export class DownloadComponent { } getUrlArchive(): string { - let query: string = host() + '/archive/' + this.datasetSelected + '?a=' + this.outputList.join(';'); + let query: string = host(this.appConfig.apiUrl) + '/archive/' + this.datasetSelected + '?a=' + this.outputList.join(';'); if (this.criteriaList.length > 0) { query += '&c=' + this.criteriaList.map(criterion => criterionToString(criterion)).join(';'); } diff --git a/client/src/app/instance/search/components/result/url-display.component.ts b/client/src/app/instance/search/components/result/url-display.component.ts index 469bc9b4..1ed461ba 100644 --- a/client/src/app/instance/search/components/result/url-display.component.ts +++ b/client/src/app/instance/search/components/result/url-display.component.ts @@ -14,6 +14,7 @@ import { ToastrService } from 'ngx-toastr'; import { Criterion, ConeSearch, criterionToString } from 'src/app/instance/store/models'; import { Dataset } from 'src/app/metamodel/models'; import { getHost as host } from 'src/app/shared/utils'; +import { AppConfigService } from 'src/app/app-config.service'; @Component({ selector: 'app-url-display', @@ -32,7 +33,7 @@ export class UrlDisplayComponent { @Input() criteriaList: Criterion[]; @Input() outputList: number[]; - constructor(private toastr: ToastrService) { } + constructor(private toastr: ToastrService, private appConfig: AppConfigService) { } /** * Checks if URL display is enabled. @@ -55,7 +56,7 @@ export class UrlDisplayComponent { * @return string */ getUrl(): string { - let query: string = host() + '/search/' + this.datasetSelected + '?a=' + this.outputList.join(';'); + let query: string = host(this.appConfig.apiUrl) + '/search/' + this.datasetSelected + '?a=' + this.outputList.join(';'); if (this.criteriaList.length > 0) { query += '&c=' + this.criteriaList.map(criterion => criterionToString(criterion)).join(';'); } diff --git a/client/src/app/instance/shared-search/components/datatable/renderer/download-renderer.component.ts b/client/src/app/instance/shared-search/components/datatable/renderer/download-renderer.component.ts index 74fc0a7f..19bcc385 100644 --- a/client/src/app/instance/shared-search/components/datatable/renderer/download-renderer.component.ts +++ b/client/src/app/instance/shared-search/components/datatable/renderer/download-renderer.component.ts @@ -11,6 +11,7 @@ import { Component, Input, ChangeDetectionStrategy } from '@angular/core'; import { DownloadRendererConfig } from 'src/app/metamodel/models/renderers/download-renderer-config.model'; import { getHost } from 'src/app/shared/utils'; +import { AppConfigService } from 'src/app/app-config.service'; @Component({ selector: 'app-download-renderer', @@ -26,13 +27,15 @@ export class DownloadRendererComponent { @Input() datasetName: string; @Input() config: DownloadRendererConfig; + constructor(private appConfig: AppConfigService) { } + /** * Returns link href. * * @return string */ getHref(): string { - return getHost() + '/download-file/' + this.datasetName + '/' + this.value; + return getHost(this.appConfig.apiUrl) + '/download-file/' + this.datasetName + '/' + this.value; } /** diff --git a/client/src/app/instance/shared-search/components/datatable/renderer/image-renderer.component.ts b/client/src/app/instance/shared-search/components/datatable/renderer/image-renderer.component.ts index 75521e7d..677dfd73 100644 --- a/client/src/app/instance/shared-search/components/datatable/renderer/image-renderer.component.ts +++ b/client/src/app/instance/shared-search/components/datatable/renderer/image-renderer.component.ts @@ -13,7 +13,7 @@ import { BsModalService } from 'ngx-bootstrap/modal'; import { BsModalRef } from 'ngx-bootstrap/modal/bs-modal-ref.service'; import { ImageRendererConfig } from 'src/app/metamodel/models/renderers'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Component({ selector: 'app-image-renderer', @@ -28,11 +28,10 @@ export class ImageRendererComponent { @Input() value: string | number; @Input() datasetName: string; @Input() config: ImageRendererConfig; - private SERVICES_PATH: string = environment.servicesUrl; modalRef: BsModalRef; - constructor(private modalService: BsModalService) { } + constructor(private modalService: BsModalService, private appConfig: AppConfigService) { } openModal(template: TemplateRef<any>) { this.modalRef = this.modalService.show(template); @@ -45,7 +44,7 @@ export class ImageRendererComponent { */ getValue(): string { if (this.config.type === 'fits') { - return `${this.SERVICES_PATH}/fits-to-png/${this.datasetName}?filename=${this.value}` + return `${this.appConfig.servicesUrl}/fits-to-png/${this.datasetName}?filename=${this.value}` + `&stretch=linear&pmin=0.25&pmax=99.75&axes=true`; } else { return this.value as string; diff --git a/client/src/app/instance/store/services/detail.service.ts b/client/src/app/instance/store/services/detail.service.ts index e1b5db35..3b946c5b 100644 --- a/client/src/app/instance/store/services/detail.service.ts +++ b/client/src/app/instance/store/services/detail.service.ts @@ -12,7 +12,7 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() /** @@ -20,10 +20,7 @@ import { environment } from 'src/environments/environment'; * @classdesc Detail service. */ export class DetailService { - private API_PATH: string = environment.apiUrl + '/search/'; - private SERVICES_PATH: string = environment.servicesUrl; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } /** * Retrieves object details for the given parameters. @@ -37,7 +34,7 @@ export class DetailService { */ retrieveObject(dname: string, criterionId: number, objectSelected: string, outputList: number[]): Observable<any[]> { const query = dname + '?c=' + criterionId + '::eq::' + objectSelected + '&a=' + outputList.join(';'); - return this.http.get<any[]>(this.API_PATH + query); + return this.http.get<any[]>(this.config.apiUrl + '/search/' + query); } /** @@ -48,6 +45,6 @@ export class DetailService { * @return Observable<string> */ retrieveSpectra(dname: string, spectraFile: string): Observable<string> { - return this.http.get(this.SERVICES_PATH + '/spectra-to-csv/' + dname + '?filename=' + spectraFile, { responseType: 'text' }); + return this.http.get(this.config.servicesUrl + '/spectra-to-csv/' + dname + '?filename=' + spectraFile, { responseType: 'text' }); } } diff --git a/client/src/app/instance/store/services/samp.service.ts b/client/src/app/instance/store/services/samp.service.ts index c4a8a9db..1429c9bf 100644 --- a/client/src/app/instance/store/services/samp.service.ts +++ b/client/src/app/instance/store/services/samp.service.ts @@ -11,7 +11,7 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; declare var samp: any; @@ -23,8 +23,8 @@ declare var samp: any; export class SampService { private connector = null; - constructor() { - const baseUrl = window.location.protocol + "//" + window.location.host + environment.baseHref; + constructor(private config: AppConfigService) { + const baseUrl = window.location.protocol + "//" + window.location.host + this.config.baseHref; const meta = { "samp.name": "ANIS", "samp.description.text": "AstroNomical Information System", diff --git a/client/src/app/instance/store/services/search.service.ts b/client/src/app/instance/store/services/search.service.ts index 7f532131..17181432 100644 --- a/client/src/app/instance/store/services/search.service.ts +++ b/client/src/app/instance/store/services/search.service.ts @@ -12,7 +12,7 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() /** @@ -20,9 +20,7 @@ import { environment } from 'src/environments/environment'; * @classdesc Search service. */ export class SearchService { - API_PATH: string = environment.apiUrl; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } /** * Retrieves results for the given parameters. @@ -32,7 +30,7 @@ export class SearchService { * @return Observable<any[]> */ retrieveData(query: string): Observable<any[]> { - return this.http.get<any[]>(this.API_PATH + '/search/' + query); + return this.http.get<any[]>(this.config.apiUrl + '/search/' + query); } /** @@ -43,6 +41,6 @@ export class SearchService { * @return Observable<{ nb: number }[]> */ retrieveDataLength(query: string): Observable<{ nb: number }[]> { - return this.http.get<{ nb: number }[]>(this.API_PATH + '/search/' + query); + return this.http.get<{ nb: number }[]>(this.config.apiUrl + '/search/' + query); } } diff --git a/client/src/app/metamodel/services/attribute-distinct.service.ts b/client/src/app/metamodel/services/attribute-distinct.service.ts index bc89ba7c..e5466159 100644 --- a/client/src/app/metamodel/services/attribute-distinct.service.ts +++ b/client/src/app/metamodel/services/attribute-distinct.service.ts @@ -13,15 +13,13 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { Attribute } from '../models'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() export class AttributeDistinctService { - private API_PATH: string = environment.apiUrl + '/'; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } retrieveAttributeDistinctList(datasetName: string, attribute: Attribute): Observable<string[]> { - return this.http.get<string[]>(this.API_PATH + 'dataset/' + datasetName + '/attribute/' + attribute.id + '/distinct'); + return this.http.get<string[]>(this.config.apiUrl + '/dataset/' + datasetName + '/attribute/' + attribute.id + '/distinct'); } } diff --git a/client/src/app/metamodel/services/attribute.service.ts b/client/src/app/metamodel/services/attribute.service.ts index 08c84d6c..9c2583c7 100644 --- a/client/src/app/metamodel/services/attribute.service.ts +++ b/client/src/app/metamodel/services/attribute.service.ts @@ -13,27 +13,25 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { Attribute } from '../models'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() export class AttributeService { - private API_PATH: string = environment.apiUrl + '/'; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } retrieveAttributeList(datasetName: string): Observable<Attribute[]> { - return this.http.get<Attribute[]>(this.API_PATH + 'dataset/' + datasetName + '/attribute'); + return this.http.get<Attribute[]>(this.config.apiUrl + '/dataset/' + datasetName + '/attribute'); } addAttribute(datasetName: string, attribute: Attribute): Observable<Attribute> { - return this.http.post<Attribute>(this.API_PATH + 'dataset/' + datasetName + '/attribute', attribute); + return this.http.post<Attribute>(this.config.apiUrl + '/dataset/' + datasetName + '/attribute', attribute); } editAttribute(datasetName: string, attribute: Attribute): Observable<Attribute> { - return this.http.put<Attribute>(this.API_PATH + 'dataset/' + datasetName + '/attribute/' + attribute.id, attribute); + return this.http.put<Attribute>(this.config.apiUrl + '/dataset/' + datasetName + '/attribute/' + attribute.id, attribute); } deleteAttribute(datasetName: string, attribute: Attribute) { - return this.http.delete(this.API_PATH + 'dataset/' + datasetName + '/attribute/' + attribute.id); + return this.http.delete(this.config.apiUrl + '/dataset/' + datasetName + '/attribute/' + attribute.id); } } diff --git a/client/src/app/metamodel/services/column.service.ts b/client/src/app/metamodel/services/column.service.ts index 881006be..0da2af53 100644 --- a/client/src/app/metamodel/services/column.service.ts +++ b/client/src/app/metamodel/services/column.service.ts @@ -13,15 +13,13 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { Column } from '../models'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() export class ColumnService { - private API_PATH: string = environment.apiUrl + '/'; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } retrieveColumns(datasetName: string): Observable<Column[]> { - return this.http.get<Column[]>(this.API_PATH + 'dataset/' + datasetName + '/column'); + return this.http.get<Column[]>(this.config.apiUrl + '/dataset/' + datasetName + '/column'); } } diff --git a/client/src/app/metamodel/services/criteria-family.service.ts b/client/src/app/metamodel/services/criteria-family.service.ts index 32e2ecfa..09d6dd21 100644 --- a/client/src/app/metamodel/services/criteria-family.service.ts +++ b/client/src/app/metamodel/services/criteria-family.service.ts @@ -13,27 +13,25 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { CriteriaFamily } from '../models'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() export class CriteriaFamilyService { - private API_PATH: string = environment.apiUrl + '/'; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } retrieveCriteriaFamilyList(datasetName: string): Observable<CriteriaFamily[]> { - return this.http.get<CriteriaFamily[]>(this.API_PATH + 'dataset/' + datasetName + '/criteria-family'); + return this.http.get<CriteriaFamily[]>(this.config.apiUrl + '/dataset/' + datasetName + '/criteria-family'); } addCriteriaFamily(datasetName: string, newCriteriaFamily: CriteriaFamily): Observable<CriteriaFamily> { - return this.http.post<CriteriaFamily>(this.API_PATH + 'dataset/' + datasetName + '/criteria-family', newCriteriaFamily); + return this.http.post<CriteriaFamily>(this.config.apiUrl + '/dataset/' + datasetName + '/criteria-family', newCriteriaFamily); } editCriteriaFamily(criteriaFamily: CriteriaFamily): Observable<CriteriaFamily> { - return this.http.put<CriteriaFamily>(this.API_PATH + 'criteria-family/' + criteriaFamily.id, criteriaFamily); + return this.http.put<CriteriaFamily>(this.config.apiUrl + '/criteria-family/' + criteriaFamily.id, criteriaFamily); } deleteCriteriaFamily(criteriaFamilyId: number) { - return this.http.delete(this.API_PATH + 'criteria-family/' + criteriaFamilyId); + return this.http.delete(this.config.apiUrl + '/criteria-family/' + criteriaFamilyId); } } diff --git a/client/src/app/metamodel/services/database.service.ts b/client/src/app/metamodel/services/database.service.ts index 567254fd..c569d351 100644 --- a/client/src/app/metamodel/services/database.service.ts +++ b/client/src/app/metamodel/services/database.service.ts @@ -13,27 +13,25 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { Database } from '../models'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() export class DatabaseService { - private API_PATH: string = environment.apiUrl + '/'; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } retrieveDatabaseList(): Observable<Database[]> { - return this.http.get<Database[]>(this.API_PATH + 'database'); + return this.http.get<Database[]>(this.config.apiUrl + '/database'); } addDatabase(newDatabase: Database): Observable<Database> { - return this.http.post<Database>(this.API_PATH + 'database', newDatabase); + return this.http.post<Database>(this.config.apiUrl + '/database', newDatabase); } editDatabase(database: Database): Observable<Database> { - return this.http.put<Database>(this.API_PATH + 'database/' + database.id, database); + return this.http.put<Database>(this.config.apiUrl + '/database/' + database.id, database); } deleteDatabase(databaseId: number) { - return this.http.delete(this.API_PATH + 'database/' + databaseId); + return this.http.delete(this.config.apiUrl + '/database/' + databaseId); } } diff --git a/client/src/app/metamodel/services/dataset-family.service.ts b/client/src/app/metamodel/services/dataset-family.service.ts index 490a14af..96fc3446 100644 --- a/client/src/app/metamodel/services/dataset-family.service.ts +++ b/client/src/app/metamodel/services/dataset-family.service.ts @@ -13,27 +13,25 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { DatasetFamily } from '../models'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() export class DatasetFamilyService { - private API_PATH: string = environment.apiUrl + '/'; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } retrieveDatasetFamilyList(instanceName: string): Observable<DatasetFamily[]> { - return this.http.get<DatasetFamily[]>(this.API_PATH + 'instance/' + instanceName + '/dataset-family'); + return this.http.get<DatasetFamily[]>(this.config.apiUrl + '/instance/' + instanceName + '/dataset-family'); } addDatasetFamily(instanceName: string, newDatasetFamily: DatasetFamily): Observable<DatasetFamily> { - return this.http.post<DatasetFamily>(this.API_PATH + 'instance/' + instanceName + '/dataset-family', newDatasetFamily); + return this.http.post<DatasetFamily>(this.config.apiUrl + '/instance/' + instanceName + '/dataset-family', newDatasetFamily); } editDatasetFamily(datasetFamily: DatasetFamily): Observable<DatasetFamily> { - return this.http.put<DatasetFamily>(this.API_PATH + 'dataset-family/' + datasetFamily.id, datasetFamily); + return this.http.put<DatasetFamily>(this.config.apiUrl + '/dataset-family/' + datasetFamily.id, datasetFamily); } deleteDatasetFamily(datasetFamilyId: number) { - return this.http.delete(this.API_PATH + 'dataset-family/' + datasetFamilyId); + return this.http.delete(this.config.apiUrl + '/dataset-family/' + datasetFamilyId); } } diff --git a/client/src/app/metamodel/services/dataset.service.ts b/client/src/app/metamodel/services/dataset.service.ts index 4b7c9b83..e8109448 100644 --- a/client/src/app/metamodel/services/dataset.service.ts +++ b/client/src/app/metamodel/services/dataset.service.ts @@ -13,27 +13,25 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { Dataset } from '../models'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() export class DatasetService { - private API_PATH: string = environment.apiUrl + '/'; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } retrieveDatasetList(instanceName: string): Observable<Dataset[]> { - return this.http.get<Dataset[]>(this.API_PATH + 'instance/' + instanceName + '/dataset'); + return this.http.get<Dataset[]>(this.config.apiUrl + '/instance/' + instanceName + '/dataset'); } addDataset(newDataset: Dataset): Observable<Dataset> { - return this.http.post<Dataset>(this.API_PATH + 'dataset-family/' + newDataset.id_dataset_family + '/dataset', newDataset); + return this.http.post<Dataset>(this.config.apiUrl + '/dataset-family/' + newDataset.id_dataset_family + '/dataset', newDataset); } editDataset(dataset: Dataset): Observable<Dataset> { - return this.http.put<Dataset>(this.API_PATH + 'dataset/' + dataset.name, dataset); + return this.http.put<Dataset>(this.config.apiUrl + '/dataset/' + dataset.name, dataset); } deleteDataset(datasetName: string) { - return this.http.delete(this.API_PATH + 'dataset/' + datasetName); + return this.http.delete(this.config.apiUrl + '/dataset/' + datasetName); } } diff --git a/client/src/app/metamodel/services/group.service.ts b/client/src/app/metamodel/services/group.service.ts index c4cbdde6..b83489be 100644 --- a/client/src/app/metamodel/services/group.service.ts +++ b/client/src/app/metamodel/services/group.service.ts @@ -13,27 +13,25 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { Group } from '../models'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() export class GroupService { - private API_PATH: string = environment.apiUrl + '/'; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } retrieveGroupList(instanceName: string): Observable<Group[]> { - return this.http.get<Group[]>(this.API_PATH + 'instance/' + instanceName + '/group'); + return this.http.get<Group[]>(this.config.apiUrl + '/instance/' + instanceName + '/group'); } addGroup(instanceName: string, newGroup: Group): Observable<Group> { - return this.http.post<Group>(this.API_PATH + 'instance/' + instanceName + '/group', newGroup); + return this.http.post<Group>(this.config.apiUrl + '/instance/' + instanceName + '/group', newGroup); } editGroup(group: Group): Observable<Group> { - return this.http.put<Group>(this.API_PATH + 'group/' + group.id, group); + return this.http.put<Group>(this.config.apiUrl + '/group/' + group.id, group); } deleteGroup(groupId: number) { - return this.http.delete(this.API_PATH + 'group/' + groupId); + return this.http.delete(this.config.apiUrl + '/group/' + groupId); } } diff --git a/client/src/app/metamodel/services/instance.service.ts b/client/src/app/metamodel/services/instance.service.ts index a5f4ab0e..d90f7f15 100644 --- a/client/src/app/metamodel/services/instance.service.ts +++ b/client/src/app/metamodel/services/instance.service.ts @@ -13,27 +13,25 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { Instance } from '../models'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() export class InstanceService { - private API_PATH: string = environment.apiUrl + '/'; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } retrieveInstanceList(): Observable<Instance[]> { - return this.http.get<Instance[]>(this.API_PATH + 'instance'); + return this.http.get<Instance[]>(this.config.apiUrl + '/instance'); } addInstance(newInstance: Instance): Observable<Instance> { - return this.http.post<Instance>(this.API_PATH + 'instance', newInstance); + return this.http.post<Instance>(this.config.apiUrl + '/instance', newInstance); } editInstance(instance: Instance): Observable<Instance> { - return this.http.put<Instance>(this.API_PATH + 'instance/' + instance.name, instance); + return this.http.put<Instance>(this.config.apiUrl + '/instance/' + instance.name, instance); } deleteInstance(instanceName: string) { - return this.http.delete(this.API_PATH + 'instance/' + instanceName); + return this.http.delete(this.config.apiUrl + '/instance/' + instanceName); } } diff --git a/client/src/app/metamodel/services/output-category.service.ts b/client/src/app/metamodel/services/output-category.service.ts index 2d35525d..5cc3e49d 100644 --- a/client/src/app/metamodel/services/output-category.service.ts +++ b/client/src/app/metamodel/services/output-category.service.ts @@ -13,27 +13,25 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { OutputCategory } from '../models'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() export class OutputCategoryService { - private API_PATH: string = environment.apiUrl + '/'; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } retrieveOutputCategoryList(datasetName: string): Observable<OutputCategory[]> { - return this.http.get<OutputCategory[]>(this.API_PATH + 'dataset/' + datasetName + '/output-category'); + return this.http.get<OutputCategory[]>(this.config.apiUrl + '/dataset/' + datasetName + '/output-category'); } addOutputCategory(newOutputCategory: OutputCategory): Observable<OutputCategory> { - return this.http.post<OutputCategory>(this.API_PATH + 'output-family/' + newOutputCategory.id_output_family + '/output-category', newOutputCategory); + return this.http.post<OutputCategory>(this.config.apiUrl + '/output-family/' + newOutputCategory.id_output_family + '/output-category', newOutputCategory); } editOutputCategory(outputCategory: OutputCategory): Observable<OutputCategory> { - return this.http.put<OutputCategory>(this.API_PATH + 'output-category/' + outputCategory.id, outputCategory); + return this.http.put<OutputCategory>(this.config.apiUrl + '/output-category/' + outputCategory.id, outputCategory); } deleteOutputCategory(outputCategoryId: number) { - return this.http.delete(this.API_PATH + 'output-category/' + outputCategoryId); + return this.http.delete(this.config.apiUrl + '/output-category/' + outputCategoryId); } } diff --git a/client/src/app/metamodel/services/output-family.service.ts b/client/src/app/metamodel/services/output-family.service.ts index 61494ed2..825e1919 100644 --- a/client/src/app/metamodel/services/output-family.service.ts +++ b/client/src/app/metamodel/services/output-family.service.ts @@ -13,27 +13,25 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { OutputFamily } from '../models'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() export class OutputFamilyService { - private API_PATH: string = environment.apiUrl + '/'; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } retrieveOutputFamilyList(datasetName: string): Observable<OutputFamily[]> { - return this.http.get<OutputFamily[]>(this.API_PATH + 'dataset/' + datasetName + '/output-family'); + return this.http.get<OutputFamily[]>(this.config.apiUrl + '/dataset/' + datasetName + '/output-family'); } addOutputFamily(datasetName: string, newOutputFamily: OutputFamily): Observable<OutputFamily> { - return this.http.post<OutputFamily>(this.API_PATH + 'dataset/' + datasetName + '/output-family', newOutputFamily); + return this.http.post<OutputFamily>(this.config.apiUrl + '/dataset/' + datasetName + '/output-family', newOutputFamily); } editOutputFamily(criteriaFamily: OutputFamily): Observable<OutputFamily> { - return this.http.put<OutputFamily>(this.API_PATH + 'output-family/' + criteriaFamily.id, criteriaFamily); + return this.http.put<OutputFamily>(this.config.apiUrl + '/output-family/' + criteriaFamily.id, criteriaFamily); } deleteOutputFamily(outputFamilyId: number) { - return this.http.delete(this.API_PATH + 'output-family/' + outputFamilyId); + return this.http.delete(this.config.apiUrl + '/output-family/' + outputFamilyId); } } diff --git a/client/src/app/metamodel/services/root-directory.service.ts b/client/src/app/metamodel/services/root-directory.service.ts index c34f2c41..d173f00d 100644 --- a/client/src/app/metamodel/services/root-directory.service.ts +++ b/client/src/app/metamodel/services/root-directory.service.ts @@ -13,15 +13,13 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { FileInfo } from '../models'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() export class RootDirectoryService { - private API_PATH: string = environment.apiUrl + '/'; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } retrieveRootDirectory(path: string): Observable<FileInfo[]> { - return this.http.get<FileInfo[]>(this.API_PATH + 'file-explorer/' + path); + return this.http.get<FileInfo[]>(this.config.apiUrl + '/file-explorer/' + path); } } diff --git a/client/src/app/metamodel/services/select-option.service.ts b/client/src/app/metamodel/services/select-option.service.ts index 07012cfa..e18a0dd3 100644 --- a/client/src/app/metamodel/services/select-option.service.ts +++ b/client/src/app/metamodel/services/select-option.service.ts @@ -13,27 +13,25 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { SelectOption } from '../models'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() export class SelectOptionService { - private API_PATH: string = environment.apiUrl + '/'; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } retrieveSelectOptionList(): Observable<SelectOption[]> { - return this.http.get<SelectOption[]>(this.API_PATH + 'option'); + return this.http.get<SelectOption[]>(this.config.apiUrl + '/option'); } addSelectOption(settingsSelectOption: SelectOption): Observable<SelectOption> { - return this.http.post<SelectOption>(this.API_PATH + 'option', settingsSelectOption); + return this.http.post<SelectOption>(this.config.apiUrl + '/option', settingsSelectOption); } editSelectOption(settingsSelectOption: SelectOption): Observable<SelectOption> { - return this.http.put<SelectOption>(this.API_PATH + 'option/' + settingsSelectOption.id, settingsSelectOption); + return this.http.put<SelectOption>(this.config.apiUrl + '/option/' + settingsSelectOption.id, settingsSelectOption); } deleteSelectOption(id: number) { - return this.http.delete(this.API_PATH + 'option/' + id); + return this.http.delete(this.config.apiUrl + '/option/' + id); } } diff --git a/client/src/app/metamodel/services/select.service.ts b/client/src/app/metamodel/services/select.service.ts index e88b7289..b146a874 100644 --- a/client/src/app/metamodel/services/select.service.ts +++ b/client/src/app/metamodel/services/select.service.ts @@ -13,27 +13,25 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { Select } from '../models'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() export class SelectService { - private API_PATH: string = environment.apiUrl + '/'; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } retrieveSelectList(): Observable<Select[]> { - return this.http.get<Select[]>(this.API_PATH + 'select'); + return this.http.get<Select[]>(this.config.apiUrl + '/select'); } addSelect(select: Select): Observable<Select> { - return this.http.post<Select>(this.API_PATH + 'select', select); + return this.http.post<Select>(this.config.apiUrl + '/select', select); } editSelect(select: Select): Observable<Select> { - return this.http.put<Select>(this.API_PATH + 'select/' + select.name, select); + return this.http.put<Select>(this.config.apiUrl + '/select/' + select.name, select); } deleteSelect(name: string) { - return this.http.delete(this.API_PATH + 'select/' + name); + return this.http.delete(this.config.apiUrl + '/select/' + name); } } diff --git a/client/src/app/metamodel/services/survey.service.ts b/client/src/app/metamodel/services/survey.service.ts index 6f482874..faf0c1ea 100644 --- a/client/src/app/metamodel/services/survey.service.ts +++ b/client/src/app/metamodel/services/survey.service.ts @@ -13,27 +13,25 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { Survey } from '../models'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() export class SurveyService { - private API_PATH: string = environment.apiUrl + '/'; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } retrieveSurveyList(): Observable<Survey[]> { - return this.http.get<Survey[]>(this.API_PATH + 'survey'); + return this.http.get<Survey[]>(this.config.apiUrl + '/survey'); } addSurvey(newSurvey: Survey): Observable<Survey> { - return this.http.post<Survey>(this.API_PATH + 'survey', newSurvey); + return this.http.post<Survey>(this.config.apiUrl + '/survey', newSurvey); } editSurvey(survey: Survey): Observable<Survey> { - return this.http.put<Survey>(this.API_PATH + 'survey/' + survey.name, survey); + return this.http.put<Survey>(this.config.apiUrl + '/survey/' + survey.name, survey); } deleteSurvey(surveyName: string) { - return this.http.delete(this.API_PATH + 'survey/' + surveyName); + return this.http.delete(this.config.apiUrl + '/survey/' + surveyName); } } diff --git a/client/src/app/metamodel/services/table.service.ts b/client/src/app/metamodel/services/table.service.ts index 96625dfd..3a3722b7 100644 --- a/client/src/app/metamodel/services/table.service.ts +++ b/client/src/app/metamodel/services/table.service.ts @@ -12,15 +12,13 @@ import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Injectable() export class TableService { - private API_PATH: string = environment.apiUrl + '/'; - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient, private config: AppConfigService) { } retrieveTableList(idDatabase: number): Observable<string[]> { - return this.http.get<string[]>(this.API_PATH + 'database/' + idDatabase + '/table'); + return this.http.get<string[]>(this.config.apiUrl + '/database/' + idDatabase + '/table'); } } diff --git a/client/src/app/portal/containers/portal-home.component.html b/client/src/app/portal/containers/portal-home.component.html index 16f93da0..7fab8209 100644 --- a/client/src/app/portal/containers/portal-home.component.html +++ b/client/src/app/portal/containers/portal-home.component.html @@ -3,6 +3,8 @@ [links]="links" [isAuthenticated]="isAuthenticated | async" [userProfile]="userProfile | async" + [baseHref]="getBaseHref()" + [authenticationEnabled]="getAuthenticationEnabled()" (login)="login()" (logout)="logout()" (openEditProfile)="openEditProfile()"> diff --git a/client/src/app/portal/containers/portal-home.component.ts b/client/src/app/portal/containers/portal-home.component.ts index 49c13a47..4405a972 100644 --- a/client/src/app/portal/containers/portal-home.component.ts +++ b/client/src/app/portal/containers/portal-home.component.ts @@ -17,7 +17,7 @@ import * as authActions from 'src/app/auth/auth.actions'; import * as authSelector from 'src/app/auth/auth.selector'; import * as instanceActions from 'src/app/metamodel/actions/instance.actions'; import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector'; -import { environment } from 'src/environments/environment'; +import { AppConfigService } from 'src/app/app-config.service'; @Component({ selector: 'app-portal-home', @@ -42,7 +42,7 @@ export class PortalHomeComponent implements OnInit, OnDestroy { public userRolesSubscription: Subscription; - constructor(private store: Store<{ }>) { + constructor(private store: Store<{ }>, private config: AppConfigService) { this.isAuthenticated = store.select(authSelector.selectIsAuthenticated); this.userProfile = store.select(authSelector.selectUserProfile); this.userRoles = store.select(authSelector.selectUserRoles); @@ -54,17 +54,25 @@ export class PortalHomeComponent implements OnInit, OnDestroy { ngOnInit() { this.store.dispatch(instanceActions.loadInstanceList()); const adminLink = { label: 'Admin', icon: 'fas fa-tools', routerLink: '/admin' }; - if (!environment.authenticationEnabled) { + if (!this.config.authenticationEnabled) { this.links.push(adminLink); } else { this.userRolesSubscription = this.userRoles.subscribe(userRoles => { - if (userRoles.includes(environment.adminRole)) { + if (userRoles.includes(this.config.adminRole)) { this.links.push(adminLink); } }); } } + getBaseHref() { + return this.config.baseHref; + } + + getAuthenticationEnabled() { + return this.config.authenticationEnabled; + } + login(): void { this.store.dispatch(authActions.login()); } diff --git a/client/src/app/shared/components/navbar.component.ts b/client/src/app/shared/components/navbar.component.ts index c88f7420..733e5578 100644 --- a/client/src/app/shared/components/navbar.component.ts +++ b/client/src/app/shared/components/navbar.component.ts @@ -10,7 +10,6 @@ import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core'; import { UserProfile } from 'src/app/auth/user-profile.model'; -import { environment } from 'src/environments/environment' @Component({ selector: 'app-navbar', @@ -22,10 +21,9 @@ export class NavbarComponent { @Input() links: {label: string, icon: string, routerLink: string}[]; @Input() isAuthenticated: boolean; @Input() userProfile: UserProfile = null; + @Input() baseHref: string; + @Input() authenticationEnabled: boolean; @Output() login: EventEmitter<any> = new EventEmitter(); @Output() logout: EventEmitter<any> = new EventEmitter(); @Output() openEditProfile: EventEmitter<any> = new EventEmitter(); - - baseHref: string = environment.baseHref; - authenticationEnabled: boolean = environment.authenticationEnabled; } diff --git a/client/src/app/shared/utils.ts b/client/src/app/shared/utils.ts index d5250e7a..b43ae07d 100644 --- a/client/src/app/shared/utils.ts +++ b/client/src/app/shared/utils.ts @@ -1,5 +1,3 @@ -import { environment } from 'src/environments/environment'; - /** * Returns strict url address. * @@ -8,12 +6,12 @@ import { environment } from 'src/environments/environment'; * @example * const url: string = getHost() + '/following-url/'; */ -export const getHost = (): string => { - if (!environment.apiUrl.startsWith('http')) { +export const getHost = (apiUrl: string): string => { + if (!apiUrl.startsWith('http')) { const url = window.location; - return url.protocol + '//' + url.host + environment.apiUrl; + return url.protocol + '//' + url.host + apiUrl; } - return environment.apiUrl; + return apiUrl; } /** diff --git a/client/src/assets/app.config.json b/client/src/assets/app.config.json new file mode 100644 index 00000000..0270c50c --- /dev/null +++ b/client/src/assets/app.config.json @@ -0,0 +1,10 @@ +{ + "apiUrl": "http://localhost:8080", + "servicesUrl": "http://localhost:5000", + "baseHref": "/", + "authenticationEnabled": true, + "ssoAuthUrl": "http://localhost:8180/auth", + "ssoRealm": "anis", + "ssoClientId": "anis-client", + "adminRole": "anis_admin" +} \ No newline at end of file diff --git a/client/src/environments/environment.prod.ts b/client/src/environments/environment.prod.ts index e1cbd3d4..5d083316 100644 --- a/client/src/environments/environment.prod.ts +++ b/client/src/environments/environment.prod.ts @@ -1,11 +1,3 @@ export const environment = { - production: true, - apiUrl: '/server', - servicesUrl: '/services', - baseHref: '/', - authenticationEnabled: true, - ssoAuthUrl: 'https://keycloak.lam.fr/auth/', - ssoRealm: 'anis', - ssoClientId: 'anis-dev', - adminRole: 'anis_admin' + production: true }; diff --git a/client/src/environments/environment.ts b/client/src/environments/environment.ts index 2a90c74f..458476a4 100644 --- a/client/src/environments/environment.ts +++ b/client/src/environments/environment.ts @@ -3,15 +3,7 @@ // The list of file replacements can be found in `angular.json`. export const environment = { - production: false, - apiUrl: 'http://localhost:8080', - servicesUrl: 'http://localhost:5000', - baseHref: '/', - authenticationEnabled: true, - ssoAuthUrl: 'http://localhost:8180/auth', - ssoRealm: 'anis', - ssoClientId: 'anis-client', - adminRole: 'anis_admin' + production: false }; /* -- GitLab