diff --git a/client/src/app/admin/admin-auth.guard.ts b/client/src/app/admin/admin-auth.guard.ts index fb9fab7fcd5c49127b00f022523f59ee4baf891b..02ac7a5e6dea1d5f36f8abb33b1a912d2c75d9e5 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 7fc65a514fb2586831625291e2eefc1804921970..d3aef6a6b6acd59c9bd6da9d15e7d601e3b34eeb 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 979df50e47db62138793be21dff9adf7df5e4cf1..61101934f1e33d3d27823eb8998cedcf423d891b 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 18364e145b246373d137a3a0d84bcfa84ec667d7..93e97de10f1e36607d482147e840a4567f1e5e4c 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 f7934d61f05212f998fcdcf66c10556de52e0046..fc050468a347ea1eb1ded1d298b01fdcbb1fd24b 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 1b6905a2bbcd1f55707332bf561aa085ea78005d..cc0899ce9fea358fc0b06e4a8fc576a06518e951 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 5e2a620d0a6985db4690cf84108b4e59b85d2ee2..cff2bdcdf35a3401fad6adf163e80240c75cdd84 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 492bac069a3bfccdd9e8a9f3846a168651c1281b..c3e643a5a7c5cf9b145970aeb5853227a86f1139 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 fe5c7db6f47a4db658929ac124354620ee5286f4..9cf5e6dea58fc2c086408e5bbba425aea966a31b 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 87109e23f306817016211fcf8c23f33ee25ba656..9c1f559f4c038fd74a28174071260afdd97c489d 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 97b51ae6380e1ab54108323c607878012b8500c0..e2a18cde45ee5821f4cbbdff63ac2ebf00d12480 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 ece9403ec5149fcac9cddc7211434f8cbbb49ee1..4ca4666de803c2c57e84ff169e20140aad1b5861 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 72d1dcedc79ed6c4bde11309d5be0cb3db93df8e..f9a42f6fac4e54b93513e28e5a1365d3747cea2c 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 41a27ae41042126954ad127f19255e1f7f4428ea..d1581ea5b138546e26d7eba21a7cd6d624ce1612 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 5ff070ee6bd57d8971192ca8ec16a1ac16f62e7e..f13fc516276e4de6ed864b1473db48c86d11ced8 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 2f268277c8ef10cca4a9d1e89afc7871c9fe552b..d485de9dbcd7c5aa3a5b15fa4b3a46824ee3a114 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 4d35bcb434eb4bca8dce8b0d06c48966cb889285..fc2f19be83072e0b31e0947c6cacdeeca9ceb864 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 b5f11cda5869b5136f7e7f02e13f851565f60ef0..1c915eff1cc2d578dd535dd7e6ee51451e80c72b 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 30c36b2babb7851963e557fd76ec19233995529b..a2aefb31b4810d8402e43fdbc87c8f3e4ad21037 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 a2a7afc994a2711a2acfe186f08b95cb49a85545..f75c845210810abaeaac0395598cb18f9aa2d784 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 4b25f427fd813bfca6ca81a5bf44c4188f42b4e7..3517973ab6dd103644a98387970d4f37872b6c94 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 2939aecf082237ddfa821aaa4f28b3b85a09d858..4dfc1917776660fa01cef50275fcd0a25e960abd 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 ef1fc0d8dca863f65ac15a0e18d0a87784ea26a6..f3ccfee56acdfe319c922b94a050dc2016f4dbf9 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 8706711543b54f65eeb80158f5869d8bc2df6fcb..1441a6a8d02d150de426e338c213f575f906b44e 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 bf18afa1c74e0390e22d1d91b826378f7b7fcda2..89c8ed9df366bfeacc2b2d3d5c79a16bb6602c32 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 a67b880373e3a77de5b3dc03415a095110cd315d..d8d136372b8eaec7e50143324d0f0102ffdeb749 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 8a6e7ef3472d123076d87e9fbe2dde4610e75dd0..22c2f5e30eb422a5fbfc7857615f03988ec254cb 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 d4aa11035eae37eba4bfe62451039fb2175a79b0..86ce85cb110aea655b48802702f6fa3e1b6cff98 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 38ae002881cd5b1acc23d3e380b1febeca96df19..fe0aa76ee37d653c1ac16cfb3137b0a3cd59d67b 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 8b6aa3b64ad95dba7b0ad4323b6f7af7583ad06e..80eb8323179ac219829e543e6319e9c06d040240 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 ba4352e033e9f7ef300d331b041dd005dafd6b51..57df81c8f7f727ff283bd08e1732d19948e55a4b 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 521725061e70a4774a6f9658eac64c8787f127f1..e0dd9bb2fa25492df131aed1335612316a594ec8 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 0000000000000000000000000000000000000000..5944e78a5bc3b8821afd91d1a3b8bc431d643157 --- /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 0000000000000000000000000000000000000000..b3dc042681bc40d7d903a4e8585e2349fdff7613 --- /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 981c03d269210f348d0572550d13dc939092073a..cca4aece56fc59af597c3db12456c7952748f33d 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 0f7c6b9cc8c1e02bdc8b7e01c0b4124d900b9e7d..69cefb0e2b4f468564a02cdcbafb631a22113e7f 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 1c04b526d5fa4866c40d04c2ecc6ccaae2284cfb..5f92830201a13e8f8b84300b2cab0cd4cd0989cb 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 f0509a317a70c330bc5a31107aa51cc3c2f404cd..de6c1bc3a350aa3656e1986be4a10874269d4b44 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 c265196bb2531b78a0262cc364ced47b63bd68f7..0de038c07d634c0c15eb078183af7b47c4706122 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 d834874bede64081c6f7b45b6c5f4f0e5b9a1ad9..16de054ffd8348a0701382356e74f9412523540e 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 df397e7ea50f131d916162665963e277f9401229..9c7095f2860c9712915d6dc5c61e0676fe7fc73d 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 7a41485040b072354f6df74b0becf5ed80104106..ef1e591e1cf2cc8e9387046451201a2352d697d0 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 979df50e47db62138793be21dff9adf7df5e4cf1..61101934f1e33d3d27823eb8998cedcf423d891b 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 6d2d31467394751078d5b9c14dd36ac4b0fee2bd..53fc798c6a9f63911e6127d4a58bec1aad4b4607 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 72ebd410aa82ef81bf7c10fd618ab211ad3c581d..0000000000000000000000000000000000000000 --- 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 80df0b7b01ffcf564995ab3e582e1cadc754b4b0..0000000000000000000000000000000000000000 --- 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 0c10c5ec9edd0c2d1e345cc00cb52b6b65a4efe8..0000000000000000000000000000000000000000 --- 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 588ac8c5304030b4386af241390533238f912512..0000000000000000000000000000000000000000 --- 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 a67b65f674076ee75448da86877a1bdc093317f2..0000000000000000000000000000000000000000 --- 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 045aeeeeee9bdf4ea743d8308504869ba35e73b3..0000000000000000000000000000000000000000 --- 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 4c7d55122bb30cd3b326b0de96acaf49da61cc6a..0000000000000000000000000000000000000000 --- 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 62a5a61175432e293174d02ce10b91c589b5a62f..0000000000000000000000000000000000000000 --- 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 29767ff55c53ba7454cfa1e90a38f401fc4ba24b..0000000000000000000000000000000000000000 --- 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 d08f64b79485959e4474efe49f989faad0b23ca3..0000000000000000000000000000000000000000 --- 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 cec4db0981a0806e7dd6112bea0e1c8e75cc3b7b..0000000000000000000000000000000000000000 --- 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 e6b5658f4821e904e6942dd10bbc921450524d73..0000000000000000000000000000000000000000 --- 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 e6f8ccfd504802a0a1b8031e59e4dc4a86326dc1..0000000000000000000000000000000000000000 --- 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 05f8edff0f509d817f66706bf62fe2fa7ae28bc7..0000000000000000000000000000000000000000 --- 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 f93f526c832f091e3df4eed6eb2300a585751186..0000000000000000000000000000000000000000 --- 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 aedba8081c7c8c2412e7a397ddf8a12c0a0cc8c0..729dfe595cc1f1e8d5484bf2d91b84311d35ca44 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 469bc9b420a9710c4a959a99c088dbf01d572822..1ed461ba64d2d44b402b2cf8eaedf98d59e5024d 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 74fc0a7f9a9f67367faeae9ea88d2bd404a25a12..19bcc38572ede27f043ee814f2f330d76eabeb25 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 75521e7d2816346299a40bebc41cee587f5a0e40..677dfd73c7e0f8baf9cd8bd11e1a74015f49c42a 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 e1b5db35066ac3cdcf46e331755d201835014ab4..3b946c5b17a2e9c649be86c4fa267ebe32f4907d 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 c4a8a9dbb612ac46a8690fe0d70826875aade414..1429c9bf7394825137519be7bf9830021822d274 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 7f5321317525144fe8d1e7da4670f892d5ac6d7c..171814321dc1e71d546be92e53c614ccd4d36410 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 bc89ba7c5f2127f4eda6d7fb5b24e91b66eb42f7..e5466159309a507362dfe260e8f33073516a4fd5 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 08c84d6cfbc6ac70cfa3c755d00c82d4bce46860..9c2583c71f1c1af80bda0ad53daa8c9402ff11fc 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 881006be1a815b3960e5be1d012e1dce0a25d97d..0da2af5345283d3374916e1fc40b4bc4cd9ef2cd 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 32e2ecfabedacdf8282e5e97626e35d25ec6d5a3..09d6dd21a477f150f8de5f5fe0a6796e0860966f 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 567254fd3a852f25994ffc31b4264168bd092164..c569d351670179e73ccf3067dafa12bfdd6628e3 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 490a14af0b92afe8c121d4d54938b489826e51c6..96fc34460b1c5520a754f5f1afb9edafcde8d821 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 4b7c9b8369c11e0f9d2682ea36bd2f16f6a11d05..e8109448278f7e10f9e0f486eb25513c988c3265 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 c4cbdde647f2b446576a48834e6de42d2913995b..b83489bebbbc04d63fcbfb237ef359266bd27348 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 a5f4ab0e57f7dbdd4db7cebf56ff7ae8179e472a..d90f7f157acc9051687bd93469a49c46f9aa6e7f 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 2d35525d6071b2c049dba7025a8b42f943e0005f..5cc3e49dbd165c348df8dc60b7389b4592ff4e45 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 61494ed2cbcf8b2da2959c40290073c97cd55763..825e191902bac95960727424fdbe483c9f9d1a5a 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 c34f2c41a9f92d24917e928aca14e97b4f135610..d173f00d10b99e3872109fac4823c225a2a5a674 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 07012cfab5b1126b321c6bc5970229b24af65e7c..e18a0dd35e8b55fce4006525e6705909ec208881 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 e88b7289c73060638d29462bc0fa79c5ea3d18fe..b146a874930054099765f9939310be7be1ab7c6b 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 6f482874f18e4d0eb4a8bdd64d89f9d93359604a..faf0c1ea4d6eff2c1d72c60f2fcf551b81f843bd 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 96625dfd1e4221867c42c946a1ee262397c7aacf..3a3722b7f515825255cc08de75447101e4f65e5a 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 16f93da003ef45253778b21864f45a82588fee1a..7fab8209cb2ce3ec74a2982dbfec41e47c310268 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 49c13a4734815c54578f74766dfbe4eb44c5226a..4405a97255d7be0a78375e525c845e425bf657c0 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 c88f742045052debb35000bb6da163ff9f150e2f..733e55789e7d5b65bea006491b717cfdd758574f 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 d5250e7ad656835ccfe3b3e758efbe9b0614cca0..b43ae07dacaf2fa56684636c8b8478909c2ff2e2 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 0000000000000000000000000000000000000000..0270c50c94d4db9f30d2c118f369f75b0c01884f --- /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 e1cbd3d486ba86dd86d83f1fc989cc180d440b3d..5d0833162027e2147e99e72a1a94bb7d3cb62843 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 2a90c74fbae956590cdf6dc57fbe0e5beb69f079..458476a4df52c64d1a2abee43c6cb91d87abad77 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 }; /*