diff --git a/client/src/app/admin/components/instance/design-form-group.component.html b/client/src/app/admin/components/instance/design-form-group.component.html new file mode 100644 index 0000000000000000000000000000000000000000..be9ed62b499b9719d3d299e38ec3f022c400efa8 --- /dev/null +++ b/client/src/app/admin/components/instance/design-form-group.component.html @@ -0,0 +1,16 @@ +<form [formGroup]="form" novalidate> + <accordion-group heading="Design"> + + <div class="form-row"> + <div class="form-group col-md-6"> + <label for="design_color_picker">Color picker</label> + <input class="form-control" type="color" id="design_color_picker" [value]="form.value.design_color" formControlName="design_color"> + </div> + <div class="form-group col-md-6"> + <label for="design_color_input">Color value</label> + <input type="text" class="form-control" id="design_color_input" [value]="form.value.design_color" formControlName="design_color"> + </div> + </div> + + </accordion-group> +</form> diff --git a/client/src/app/admin/components/instance/design-form-group.component.ts b/client/src/app/admin/components/instance/design-form-group.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..2c84d3c1c0e368851efaa05701fbfee90e03b1f9 --- /dev/null +++ b/client/src/app/admin/components/instance/design-form-group.component.ts @@ -0,0 +1,19 @@ +/** + * 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 } from '@angular/core'; +import { FormGroup } from '@angular/forms'; + +@Component({ + selector: 'app-design-form-group', + templateUrl: 'design-form-group.component.html' +}) +export class DesignFormGroupComponent { + @Input() form: FormGroup; +} diff --git a/client/src/app/admin/components/instance/index.ts b/client/src/app/admin/components/instance/index.ts index 826d3727e78d69a0dba05ba06f159be14301a1ab..47997603644fc0f5c165dc8aad02983b360ae23d 100644 --- a/client/src/app/admin/components/instance/index.ts +++ b/client/src/app/admin/components/instance/index.ts @@ -10,6 +10,7 @@ import { InstanceCardComponent } from './instance-card.component'; import { InstanceButtonsComponent } from './instance-buttons.component'; import { InstanceFormComponent } from './instance-form.component'; +import { DesignFormGroupComponent } from './design-form-group.component'; import { SearchFormGroupComponent } from './search-form-group.component'; import { DocumentationFormGroupComponent } from './documentation-form-group.component'; @@ -17,6 +18,7 @@ export const instanceComponents = [ InstanceCardComponent, InstanceButtonsComponent, InstanceFormComponent, + DesignFormGroupComponent, SearchFormGroupComponent, DocumentationFormGroupComponent ]; diff --git a/client/src/app/admin/components/instance/instance-form.component.html b/client/src/app/admin/components/instance/instance-form.component.html index ee839607e117fd8e3dd4b700b1d5c476de620060..abf027b3ad2fc6e116075cf6d9897837fa4a37bc 100644 --- a/client/src/app/admin/components/instance/instance-form.component.html +++ b/client/src/app/admin/components/instance/instance-form.component.html @@ -14,6 +14,7 @@ <input id="client_url" type="text" class="form-control" id="client_url" name="client_url" formControlName="client_url"> </div> </accordion-group> + <app-design-form-group [form]="designFormGroup"></app-design-form-group> <app-search-form-group [form]="searchFormGroup"></app-search-form-group> <app-documentation-form-group [form]="documentationFormGroup"></app-documentation-form-group> </accordion> diff --git a/client/src/app/admin/components/instance/instance-form.component.ts b/client/src/app/admin/components/instance/instance-form.component.ts index 2514e806be619581ae4688aae927a8f4843e57d2..1463bfa2ef850b440bc79fc8d76c7a515bb94242 100644 --- a/client/src/app/admin/components/instance/instance-form.component.ts +++ b/client/src/app/admin/components/instance/instance-form.component.ts @@ -20,6 +20,10 @@ export class InstanceFormComponent implements OnInit { @Input() instance: Instance; @Output() onSubmit: EventEmitter<Instance> = new EventEmitter(); + public designFormGroup = new FormGroup({ + design_color: new FormControl('', [Validators.required]) + }); + public searchFormGroup = new FormGroup({ search_by_criteria_allowed: new FormControl(true), search_multiple_allowed: new FormControl(false), @@ -35,6 +39,7 @@ export class InstanceFormComponent implements OnInit { label: new FormControl('', [Validators.required]), client_url: new FormControl('', [Validators.required]), config: new FormGroup({ + design: this.designFormGroup, search: this.searchFormGroup, documentation: this.documentationFormGroup }) diff --git a/client/src/app/instance/instance.component.html b/client/src/app/instance/instance.component.html index 61101934f1e33d3d27823eb8998cedcf423d891b..b064125644f533d94356d14a5aecd44c4f986d2f 100644 --- a/client/src/app/instance/instance.component.html +++ b/client/src/app/instance/instance.component.html @@ -5,6 +5,7 @@ [userProfile]="userProfile | async" [baseHref]="getBaseHref()" [authenticationEnabled]="getAuthenticationEnabled()" + [designColor]="(instance | async).config.design.design_color" (login)="login()" (logout)="logout()" (openEditProfile)="openEditProfile()"> diff --git a/client/src/app/instance/search/components/output/output-by-category.component.html b/client/src/app/instance/search/components/output/output-by-category.component.html index 9774bd950c34cb5a6bf7d6debee9b6faa23fb4e1..7888b9a0acb076a724a631a25a3ef7095f667414 100644 --- a/client/src/app/instance/search/components/output/output-by-category.component.html +++ b/client/src/app/instance/search/components/output/output-by-category.component.html @@ -17,7 +17,7 @@ <div *ngFor="let attribute of getAttributeListSortedByDisplay()"> <div *ngIf="isSelected(attribute.id)"> <button class="btn btn-block text-left py-1 m-0 rounded-0" (click)="toggleSelection(attribute.id)"> - <span class="fas fa-fw fa-check-square theme-color"></span> {{ attribute.form_label }} + <span class="fas fa-fw fa-check-square" [ngStyle]="{ 'color': designColor }"></span> {{ attribute.form_label }} </button> </div> <div *ngIf="!isSelected(attribute.id)"> diff --git a/client/src/app/instance/search/components/output/output-by-category.component.ts b/client/src/app/instance/search/components/output/output-by-category.component.ts index b65113b6bf8ba3fe9b73a17d261bba956c99c434..3cfd66d0ad7da4de3456540fb4f15bf210fad09a 100644 --- a/client/src/app/instance/search/components/output/output-by-category.component.ts +++ b/client/src/app/instance/search/components/output/output-by-category.component.ts @@ -25,6 +25,7 @@ export class OutputByCategoryComponent { @Input() categoryLabel: string; @Input() attributeList: Attribute[]; @Input() outputList: number[]; + @Input() designColor: string; @Input() isAllSelected: boolean; @Input() isAllUnselected: boolean; @Output() change: EventEmitter<number[]> = new EventEmitter(); diff --git a/client/src/app/instance/search/components/output/output-by-family.component.html b/client/src/app/instance/search/components/output/output-by-family.component.html index c281d8698e7e63131e141a846214feaf98995ef4..e4acc92e4ef7ec35c395e3475237bd9f03edd687 100644 --- a/client/src/app/instance/search/components/output/output-by-family.component.html +++ b/client/src/app/instance/search/components/output/output-by-family.component.html @@ -5,6 +5,7 @@ [categoryLabel]="category.label" [attributeList]="getAttributeByCategory(category.id)" [outputList]="outputList" + [designColor]="designColor" [isAllSelected]="getIsAllSelected(category.id)" [isAllUnselected]="getIsAllUnselected(category.id)" (change)="emitChange($event)"> diff --git a/client/src/app/instance/search/components/output/output-by-family.component.ts b/client/src/app/instance/search/components/output/output-by-family.component.ts index 8ef26caf006d04a81acdd4b7231edc31ecb00ef6..23ff1ee0def5dc3eab3841d656115303b1e3f9c5 100644 --- a/client/src/app/instance/search/components/output/output-by-family.component.ts +++ b/client/src/app/instance/search/components/output/output-by-family.component.ts @@ -25,6 +25,7 @@ export class OutputByFamilyComponent { @Input() outputCategoryList: OutputCategory[]; @Input() attributeList: Attribute[]; @Input() outputList: number[]; + @Input() designColor: string; @Output() change: EventEmitter<number[]> = new EventEmitter(); /** diff --git a/client/src/app/instance/search/components/output/output-tabs.component.html b/client/src/app/instance/search/components/output/output-tabs.component.html index d8ca9de4d061a38222c209ede10de79fb8d6a88e..f8bc426ab79aa87ed0cab768dde80db7e4c44047 100644 --- a/client/src/app/instance/search/components/output/output-tabs.component.html +++ b/client/src/app/instance/search/components/output/output-tabs.component.html @@ -7,6 +7,7 @@ [attributeList]="attributeList" [outputCategoryList]="outputCategoryList" [outputList]="outputList" + [designColor]="designColor" (change)="change.emit($event)"> </app-output-by-family> </div> @@ -29,6 +30,7 @@ [attributeList]="attributeList" [outputCategoryList]="outputCategoryList" [outputList]="outputList" + [designColor]="designColor" (change)="change.emit($event)"> </app-output-by-family> </accordion-group> diff --git a/client/src/app/instance/search/components/output/output-tabs.component.ts b/client/src/app/instance/search/components/output/output-tabs.component.ts index c3ec91115a3e2d3c969bc19cb85dbe415a117d49..6bf1afefdd5168956fdf19f7833a206f92706464 100644 --- a/client/src/app/instance/search/components/output/output-tabs.component.ts +++ b/client/src/app/instance/search/components/output/output-tabs.component.ts @@ -27,6 +27,7 @@ export class OutputTabsComponent { @Input() outputCategoryList: OutputCategory[]; @Input() attributeList: Attribute[]; @Input() outputList: number[]; + @Input() designColor: string; @Output() change: EventEmitter<number[]> = new EventEmitter(); constructor(private toastr: ToastrService) { } diff --git a/client/src/app/instance/search/components/progress-bar.component.html b/client/src/app/instance/search/components/progress-bar.component.html index 4575d0e828006126fa66fc9ef2c97bd458aee00a..b248b98ca39a6d168c490a0d93ee6e375aa01b19 100644 --- a/client/src/app/instance/search/components/progress-bar.component.html +++ b/client/src/app/instance/search/components/progress-bar.component.html @@ -6,58 +6,67 @@ </div> <div class="progress-navigation"> <div class="progress progress-with-circle"> - <div class="progress-bar" role="progressbar" aria-valuenow="1" aria-valuemin="1" aria-valuemax="4" - [ngClass]="getStepClass()"></div> + <div class="progress-bar" + [ngClass]="getStepClass()" + [ngStyle]="{'background-color': instance.config.design.design_color }" + role="progressbar" + aria-valuenow="1" + aria-valuemin="1" + aria-valuemax="4"> + </div> </div> <ul class="nav nav-pills"> <li class="nav-item checked" [ngClass]="{'active': currentStep === 'dataset'}"> - <a class="nav-link" routerLink="/instance/{{ instanceSelected }}/search/dataset/{{ datasetSelected }}" [queryParams]="queryParams" data-toggle="tab"> - <div class="icon-circle"> + <a class="nav-link" [ngStyle]="getNavItemAStyle('dataset', true)" routerLink="/instance/{{ instance.name }}/search/dataset/{{ datasetSelected }}" [queryParams]="queryParams" data-toggle="tab"> + <div class="icon-circle" [ngStyle]="getNavItemIconCircleStyle('dataset', true)"> <span class="fas fa-book"></span> </div> Dataset </a> </li> <li id="criteriaStep" class="nav-item" [ngClass]="{'active': currentStep === 'criteria', 'checked': criteriaStepChecked}"> - <a *ngIf="datasetSelected" class="nav-link" [ngClass]="{'disabled': !datasetSelected}" - routerLink="/instance/{{ instanceSelected }}/search/criteria/{{ datasetSelected }}" [queryParams]="queryParams" data-toggle="tab"> - <div class="icon-circle"> + <a *ngIf="datasetSelected" + class="nav-link" + [ngClass]="{'disabled': !datasetSelected}" + [ngStyle]="getNavItemAStyle('criteria', criteriaStepChecked)" + routerLink="/instance/{{ instance.name }}/search/criteria/{{ datasetSelected }}" [queryParams]="queryParams" data-toggle="tab"> + <div class="icon-circle" [ngStyle]="getNavItemIconCircleStyle('criteria', criteriaStepChecked)"> <span class="fas fa-filter"></span> </div> Criteria </a> - <a *ngIf="!datasetSelected" class="nav-link" [ngClass]="{'disabled': !datasetSelected}" data-toggle="tab"> - <div class="icon-circle"> + <a *ngIf="!datasetSelected" class="nav-link" [ngClass]="{'disabled': !datasetSelected}" [ngStyle]="getNavItemAStyle('criteria', criteriaStepChecked)" data-toggle="tab"> + <div class="icon-circle" [ngStyle]="getNavItemIconCircleStyle('criteria', criteriaStepChecked)"> <span class="fas fa-filter"></span> </div> Criteria </a> </li> <li class="nav-item" [ngClass]="{'active': currentStep === 'output', 'checked': outputStepChecked}"> - <a *ngIf="datasetSelected" class="nav-link" [ngClass]="{'disabled': !datasetSelected}" - routerLink="/instance/{{ instanceSelected }}/search/output/{{ datasetSelected }}" [queryParams]="queryParams" data-toggle="tab"> - <div class="icon-circle"> + <a *ngIf="datasetSelected" class="nav-link" [ngClass]="{'disabled': !datasetSelected}" [ngStyle]="getNavItemAStyle('output', outputStepChecked)" + routerLink="/instance/{{ instance.name }}/search/output/{{ datasetSelected }}" [queryParams]="queryParams" data-toggle="tab"> + <div class="icon-circle" [ngStyle]="getNavItemIconCircleStyle('output', outputStepChecked)"> <span class="fas fa-eye"></span> </div> Output </a> - <a *ngIf="!datasetSelected" class="nav-link" [ngClass]="{'disabled': !datasetSelected}" data-toggle="tab"> - <div class="icon-circle"> + <a *ngIf="!datasetSelected" class="nav-link" [ngClass]="{'disabled': !datasetSelected}" [ngStyle]="getNavItemAStyle('output', outputStepChecked)" data-toggle="tab"> + <div class="icon-circle" [ngStyle]="getNavItemIconCircleStyle('output', outputStepChecked)"> <span class="fas fa-eye"></span> </div> Output </a> </li> <li class="nav-item" [ngClass]="{'active': currentStep === 'result', 'checked': resultStepChecked}"> - <a *ngIf="datasetSelected" class="nav-link" [ngClass]="{'disabled': outputList.length < 1}" - routerLink="/instance/{{ instanceSelected }}/search/result/{{ datasetSelected }}" [queryParams]="queryParams" data-toggle="tab"> - <div class="icon-circle"> + <a *ngIf="datasetSelected" class="nav-link" [ngClass]="{'disabled': outputList.length < 1}" [ngStyle]="getNavItemAStyle('result', resultStepChecked)" + routerLink="/instance/{{ instance.name }}/search/result/{{ datasetSelected }}" [queryParams]="queryParams" data-toggle="tab"> + <div class="icon-circle" [ngStyle]="getNavItemIconCircleStyle('result', resultStepChecked)"> <span class="fas fa-table"></span> </div> Result </a> - <a *ngIf="!datasetSelected" class="nav-link" [ngClass]="{'disabled': !datasetSelected}" data-toggle="tab"> - <div class="icon-circle"> + <a *ngIf="!datasetSelected" class="nav-link" [ngClass]="{'disabled': !datasetSelected}" [ngStyle]="getNavItemAStyle('result', resultStepChecked)" data-toggle="tab"> + <div class="icon-circle" [ngStyle]="getNavItemIconCircleStyle('result', resultStepChecked)"> <span class="fas fa-table"></span> </div> Result diff --git a/client/src/app/instance/search/components/progress-bar.component.scss b/client/src/app/instance/search/components/progress-bar.component.scss index 3537e02786c7efcc15bcf896c97a865bac216b5d..4b28b03c366bfd662ed7f907f98e3138b691dbc8 100644 --- a/client/src/app/instance/search/components/progress-bar.component.scss +++ b/client/src/app/instance/search/components/progress-bar.component.scss @@ -7,7 +7,7 @@ * file that was distributed with this source code. */ - .progress-navigation { +.progress-navigation { position: relative; height: 125px; margin-top: 15px; @@ -25,7 +25,6 @@ -webkit-transition: width .3s ease; -o-transition: width .3s ease; transition: width .3s ease; - background-color: #7AC29A; } .nav-pills { @@ -67,24 +66,12 @@ width: 25%; } -.nav-item.checked .icon-circle { - border-color: #7AC29A; - color: #7AC29A; -} - -.nav-item.checked a { - color: #7AC29A !important; -} - .nav-item.active a { - color: #7AC29A !important; background-color: transparent; } .nav-item.active .icon-circle { color: white !important; - border-color: #7AC29A; - background-color: #7AC29A; } .nav-link.disabled { diff --git a/client/src/app/instance/search/components/progress-bar.component.ts b/client/src/app/instance/search/components/progress-bar.component.ts index c70e73968a36a25064c75487e1d3a4451b861624..de9abad0eaa41190f28662e6515dba35ddff7ae1 100644 --- a/client/src/app/instance/search/components/progress-bar.component.ts +++ b/client/src/app/instance/search/components/progress-bar.component.ts @@ -10,6 +10,7 @@ import { Component, Input, ChangeDetectionStrategy } from '@angular/core'; import { SearchQueryParams } from '../../store/models'; +import { Instance } from 'src/app/metamodel/models'; @Component({ selector: 'app-progress-bar', @@ -23,7 +24,7 @@ import { SearchQueryParams } from '../../store/models'; */ export class ProgressBarComponent { @Input() currentStep: string; - @Input() instanceSelected: string; + @Input() instance: Instance; @Input() datasetSelected: string; @Input() criteriaStepChecked: boolean; @Input() outputStepChecked: boolean; @@ -50,4 +51,27 @@ export class ProgressBarComponent { return 'datasetStep'; } } + + getNavItemAStyle(currentStep: string, checked: boolean) { + if (this.currentStep === currentStep || checked) { + return { + 'color': this.instance.config.design.design_color + } + } else { + return null; + } + } + + getNavItemIconCircleStyle(currentStep: string, checked: boolean) { + let style = {}; + if (this.currentStep === currentStep) { + style['border-color'] = this.instance.config.design.design_color; + style['background-color'] = this.instance.config.design.design_color; + } + if (checked) { + style['border-color'] = this.instance.config.design.design_color; + style['color'] = this.instance.config.design.design_color; + } + return style; + } } diff --git a/client/src/app/instance/search/components/result/datatable-tab.component.html b/client/src/app/instance/search/components/result/datatable-tab.component.html index 26dd36d1be6a174d083b150ebb580194511e8e9c..335af332a2aa3007611cbaf8a6f02c00674835a2 100644 --- a/client/src/app/instance/search/components/result/datatable-tab.component.html +++ b/client/src/app/instance/search/components/result/datatable-tab.component.html @@ -10,7 +10,7 @@ </button> <app-datatable [dataset]="datasetList | datasetByName:datasetSelected" - [instanceSelected]="instanceSelected" + [instance]="instance" [attributeList]="attributeList" [outputList]="outputList" [dataLength]="dataLength" diff --git a/client/src/app/instance/search/components/result/datatable-tab.component.ts b/client/src/app/instance/search/components/result/datatable-tab.component.ts index c24e1979d36d8710d5efe016bd9ba69a5e4c35d2..57333dc2b9edc832fc56504aee3bce6018dfc697 100644 --- a/client/src/app/instance/search/components/result/datatable-tab.component.ts +++ b/client/src/app/instance/search/components/result/datatable-tab.component.ts @@ -9,7 +9,7 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; -import { Attribute, Dataset } from 'src/app/metamodel/models'; +import { Instance, Attribute, Dataset } from 'src/app/metamodel/models'; import { Pagination } from 'src/app/instance/store/models'; @Component({ @@ -23,7 +23,7 @@ import { Pagination } from 'src/app/instance/store/models'; */ export class DatatableTabComponent { @Input() datasetSelected: string; - @Input() instanceSelected: string; + @Input() instance: Instance; @Input() datasetList: Dataset[]; @Input() attributeList: Attribute[]; @Input() outputList: number[]; diff --git a/client/src/app/instance/search/containers/output.component.html b/client/src/app/instance/search/containers/output.component.html index 12d7f60558376fa5c8b4a679cc8fa1a2b4eafce0..db66948c6961e8d968487796e09c4723027f6337 100644 --- a/client/src/app/instance/search/containers/output.component.html +++ b/client/src/app/instance/search/containers/output.component.html @@ -12,6 +12,7 @@ [outputFamilyList]="outputFamilyList | async" [outputCategoryList]="outputCategoryList | async" [outputList]="outputList | async" + [designColor]="(instance | async).config.design.design_color" (change)="updateOutputList($event)"> </app-output-tabs> </div> diff --git a/client/src/app/instance/search/containers/output.component.ts b/client/src/app/instance/search/containers/output.component.ts index 2a8962bc5c4cc6368d2cf1621ffe32a334efa560..16a29fa14700cb69e4aa67e4a780273ba4d2d1c1 100644 --- a/client/src/app/instance/search/containers/output.component.ts +++ b/client/src/app/instance/search/containers/output.component.ts @@ -9,7 +9,12 @@ import { Component } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; + +import { Instance } from 'src/app/metamodel/models'; import { AbstractSearchComponent } from './abstract-search.component'; +import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector'; import * as searchActions from '../../store/actions/search.actions'; @Component({ @@ -21,6 +26,13 @@ import * as searchActions from '../../store/actions/search.actions'; * @classdesc Search output container. */ export class OutputComponent extends AbstractSearchComponent { + public instance: Observable<Instance>; + + constructor(protected store: Store<{ }>) { + super(store); + this.instance = store.select(instanceSelector.selectInstanceByRouteName); + } + ngOnInit() { Promise.resolve(null).then(() => this.store.dispatch(searchActions.changeStep({ step: 'output' }))); Promise.resolve(null).then(() => this.store.dispatch(searchActions.checkOutput())); diff --git a/client/src/app/instance/search/containers/result.component.html b/client/src/app/instance/search/containers/result.component.html index 2680522f4b7983aee51d2ff7146fdc5ab790db9f..f5ede714fb8653399c9cb75611dfd5d35eb5573e 100644 --- a/client/src/app/instance/search/containers/result.component.html +++ b/client/src/app/instance/search/containers/result.component.html @@ -72,7 +72,7 @@ </app-cone-search-plot-tab> --> <app-datatable-tab [datasetSelected]="datasetSelected | async" - [instanceSelected]="instanceSelected | async" + [instance]="instance | async" [datasetList]="datasetList | async" [attributeList]="attributeList | async" [outputList]="outputList | async" diff --git a/client/src/app/instance/search/containers/result.component.ts b/client/src/app/instance/search/containers/result.component.ts index 1e1c3359b8c7a5fafe764ade7c1c49eef4107a20..82f65348ed3b1cd56878cb116aa9eaae9053fec9 100644 --- a/client/src/app/instance/search/containers/result.component.ts +++ b/client/src/app/instance/search/containers/result.component.ts @@ -14,6 +14,8 @@ import { Observable, Subscription } from 'rxjs'; import { AbstractSearchComponent } from './abstract-search.component'; import { Pagination } from '../../store/models'; +import { Instance } from 'src/app/metamodel/models'; +import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector'; import * as searchActions from '../../store/actions/search.actions'; import * as searchSelector from '../../store/selectors/search.selector'; import * as sampActions from '../../store/actions/samp.actions'; @@ -31,6 +33,7 @@ import * as sampSelector from '../../store/selectors/samp.selector'; * @implements OnDestroy */ export class ResultComponent extends AbstractSearchComponent { + public instance: Observable<Instance>; public dataLength: Observable<number>; public dataLengthIsLoading: Observable<boolean>; public dataLengthIsLoaded: Observable<boolean>; @@ -44,6 +47,7 @@ export class ResultComponent extends AbstractSearchComponent { constructor(protected store: Store<{ }>) { super(store); + this.instance = store.select(instanceSelector.selectInstanceByRouteName); this.dataLength = this.store.select(searchSelector.selectDataLength); this.dataLengthIsLoading = this.store.select(searchSelector.selectDataLengthIsLoading); this.dataLengthIsLoaded = this.store.select(searchSelector.selectDataLengthIsLoaded); diff --git a/client/src/app/instance/search/search.component.html b/client/src/app/instance/search/search.component.html index 4ae64be7957f290d83d86b5379f504eaf9b74a0c..a4b16e3bdb1354feee9d04902c3b20af6a7e25c1 100644 --- a/client/src/app/instance/search/search.component.html +++ b/client/src/app/instance/search/search.component.html @@ -1,7 +1,7 @@ <div class="mx-1 mx-sm-5 px-1 px-sm-5"> <app-progress-bar [currentStep]="currentStep | async" - [instanceSelected]="instanceSelected | async" + [instance]="instance | async" [datasetSelected]="datasetSelected | async" [criteriaStepChecked]="criteriaStepChecked | async" [outputStepChecked]="outputStepChecked | async" diff --git a/client/src/app/instance/search/search.component.ts b/client/src/app/instance/search/search.component.ts index 175c4e9bd1d0e714fabdfeff01e4f4491ac3beac..d4e0fa2063ed3ebd044912154697a857bda395c9 100644 --- a/client/src/app/instance/search/search.component.ts +++ b/client/src/app/instance/search/search.component.ts @@ -13,6 +13,7 @@ import { Store } from '@ngrx/store'; import { Observable } from 'rxjs'; import { SearchQueryParams } from '../store/models'; +import { Instance } from 'src/app/metamodel/models'; import * as instanceSelector from 'src/app/metamodel/selectors/instance.selector'; import * as datasetSelector from 'src/app/metamodel/selectors/dataset.selector'; import * as searchSelector from '../store/selectors/search.selector'; @@ -26,7 +27,7 @@ import * as searchSelector from '../store/selectors/search.selector'; * @classdesc Search container. */ export class SearchComponent { - public instanceSelected: Observable<string>; + public instance: Observable<Instance>; public datasetSelected: Observable<string>; public currentStep: Observable<string>; public criteriaStepChecked: Observable<boolean>; @@ -36,7 +37,7 @@ export class SearchComponent { public outputList: Observable<number[]>; constructor(private store: Store<{ }>) { - this.instanceSelected = store.select(instanceSelector.selectInstanceNameByRoute); + this.instance = store.select(instanceSelector.selectInstanceByRouteName); this.datasetSelected = store.select(datasetSelector.selectDatasetNameByRoute); this.currentStep = store.select(searchSelector.selectCurrentStep); this.criteriaStepChecked = store.select(searchSelector.selectCriteriaStepChecked); diff --git a/client/src/app/instance/shared-search/components/datatable/datatable.component.html b/client/src/app/instance/shared-search/components/datatable/datatable.component.html index 881f79065975906242993d75e2239f945bd4ff4c..cd7506a1bf9504e609bfcbbbd21ec076f73f6bca 100644 --- a/client/src/app/instance/shared-search/components/datatable/datatable.component.html +++ b/client/src/app/instance/shared-search/components/datatable/datatable.component.html @@ -35,7 +35,7 @@ <span class="far fa-square fa-lg text-secondary"></span> </span> <span *ngIf="isSelected(datum)"> - <span class="fas fa-check-square fa-lg theme-color"></span> + <span class="fas fa-check-square fa-lg" [ngStyle]="{ 'color': instance.config.design.design_color }"></span> </span> </button> </td> @@ -45,7 +45,7 @@ <app-detail-renderer [value]="datum[attribute.label]" [datasetName]="dataset.name" - [instanceSelected]="instanceSelected" + [instanceSelected]="instance.name" [config]="getRendererConfig(attribute)"> </app-detail-renderer> </div> diff --git a/client/src/app/instance/shared-search/components/datatable/datatable.component.ts b/client/src/app/instance/shared-search/components/datatable/datatable.component.ts index 698cf0403bf1ea003acb77f3b9da144bb38132db..9df8e30a8489d7087e508f683e91917fa40dc3ae 100644 --- a/client/src/app/instance/shared-search/components/datatable/datatable.component.ts +++ b/client/src/app/instance/shared-search/components/datatable/datatable.component.ts @@ -9,10 +9,9 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { Attribute, Dataset, DetailRendererConfig, DownloadRendererConfig, ImageRendererConfig, LinkRendererConfig, RendererConfig } from 'src/app/metamodel/models'; +import { Instance, Attribute, Dataset, DetailRendererConfig, DownloadRendererConfig, ImageRendererConfig, LinkRendererConfig, RendererConfig } from 'src/app/metamodel/models'; import { Pagination, PaginationOrder } from 'src/app/instance/store/models'; - @Component({ selector: 'app-datatable', templateUrl: 'datatable.component.html', @@ -26,7 +25,7 @@ import { Pagination, PaginationOrder } from 'src/app/instance/store/models'; */ export class DatatableComponent implements OnInit { @Input() dataset: Dataset; - @Input() instanceSelected: string; + @Input() instance: Instance; @Input() attributeList: Attribute[]; @Input() outputList: number[]; @Input() dataLength: number; diff --git a/client/src/app/metamodel/models/instance.model.ts b/client/src/app/metamodel/models/instance.model.ts index 716b7ac45030dc43845aa2435a1f7754fe6983ea..006bdc1d3d058f9280a3dff2af46f549d3ce2515 100644 --- a/client/src/app/metamodel/models/instance.model.ts +++ b/client/src/app/metamodel/models/instance.model.ts @@ -12,6 +12,9 @@ export interface Instance { label: string; client_url: string; config: { + design: { + design_color: string + }; search: { search_by_criteria_allowed: boolean; search_multiple_allowed: boolean; diff --git a/client/src/app/shared/components/navbar.component.html b/client/src/app/shared/components/navbar.component.html index 2c8295162061fc29f04bce23a4c0541146b2ee41..754e05fffc0080504b7d54f4541e1b9297c0351f 100644 --- a/client/src/app/shared/components/navbar.component.html +++ b/client/src/app/shared/components/navbar.component.html @@ -21,7 +21,7 @@ </button> <span *ngIf="isAuthenticated" id="dropdown-menu" dropdown> <button id="button-basic" dropdownToggle type="button" class="btn btn-light" aria-controls="dropdown-basic"> - <span class="fa-stack theme-color"> + <span class="fa-stack" [ngStyle]="{ color: designColor ? designColor : '#7AC29A' }"> <span class="fas fa-circle fa-2x"></span> <span class="fas fa-user fa-stack-1x fa-inverse"></span> </span> diff --git a/client/src/app/shared/components/navbar.component.ts b/client/src/app/shared/components/navbar.component.ts index 733e55789e7d5b65bea006491b717cfdd758574f..f7ba795a0839d065d0893e1faf1ad5c61ec59abc 100644 --- a/client/src/app/shared/components/navbar.component.ts +++ b/client/src/app/shared/components/navbar.component.ts @@ -23,6 +23,7 @@ export class NavbarComponent { @Input() userProfile: UserProfile = null; @Input() baseHref: string; @Input() authenticationEnabled: boolean; + @Input() designColor: string; @Output() login: EventEmitter<any> = new EventEmitter(); @Output() logout: EventEmitter<any> = new EventEmitter(); @Output() openEditProfile: EventEmitter<any> = new EventEmitter(); diff --git a/client/src/app/shared/pipes/index.ts b/client/src/app/shared/pipes/index.ts index 85f656d958fead98c129a416d03a08b3fccbc83a..b8263c6a6051a3543d00b84d9b29b2e6a4469823 100644 --- a/client/src/app/shared/pipes/index.ts +++ b/client/src/app/shared/pipes/index.ts @@ -13,6 +13,7 @@ import { SurveyByNamePipe } from './survey-by-name.pipe'; import { OptionListBySelectPipe } from './option-list-by-select.pipe'; import { OutputFamilyById } from './output-family-by-id.pipe'; import { DatasetByNamePipe } from './dataset-by-name.pipe'; +import { InstanceByNamePipe } from './instance-by-name.pipe'; export const sharedPipes = [ DatasetListByFamilyPipe, @@ -20,5 +21,6 @@ export const sharedPipes = [ SurveyByNamePipe, OptionListBySelectPipe, OutputFamilyById, - DatasetByNamePipe + DatasetByNamePipe, + InstanceByNamePipe ]; diff --git a/client/src/app/shared/pipes/instance-by-name.pipe.ts b/client/src/app/shared/pipes/instance-by-name.pipe.ts new file mode 100644 index 0000000000000000000000000000000000000000..ffb56e0da45a96079c17000b3bc33fad332f82a1 --- /dev/null +++ b/client/src/app/shared/pipes/instance-by-name.pipe.ts @@ -0,0 +1,19 @@ +/** + * 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 { Pipe, PipeTransform } from '@angular/core'; + +import { Instance } from 'src/app/metamodel/models'; + +@Pipe({name: 'instanceByName'}) +export class InstanceByNamePipe implements PipeTransform { + transform(instanceList: Instance[], instanceName: string): Instance { + return instanceList.find(instance => instance.name === instanceName); + } +} diff --git a/client/src/styles.scss b/client/src/styles.scss index 388dc72eda0e8cd56595c80bfcc8c8b5650ec62e..db95f8b3e83d57b52cc97d8b8c0f4bb9a6f0a8b4 100644 --- a/client/src/styles.scss +++ b/client/src/styles.scss @@ -40,11 +40,6 @@ @import '~ngx-bootstrap/datepicker/bs-datepicker.css'; /* Global styles */ - -.theme-color { - color: #7AC29A; -} - main { margin-top: 100px; } @@ -85,7 +80,6 @@ input.ng-invalid, select.ng-invalid, ng-select.ng-invalid div.ng-select-containe } /* Utilities */ - .pointer { cursor: pointer; } diff --git a/conf-dev/create-db.sh b/conf-dev/create-db.sh index 692077d4a2f12f146d6a77495e522d2aa20e6c53..3f1568ea4ace7b969114abae30ede37e03192add 100644 --- a/conf-dev/create-db.sh +++ b/conf-dev/create-db.sh @@ -59,7 +59,7 @@ curl -d '{"label":"Spectra graph","value":"spectra_graph","display":20,"select_n curl -d '{"label":"Test","dbname":"anis_test","dbtype":"pdo_pgsql","dbhost":"db","dbport":5432,"dblogin":"anis","dbpassword":"anis"}' --header 'Content-Type: application/json' -X POST http://localhost/database # Add default instance -curl -d '{"name":"default","label":"Default instance","client_url":"http://localhost:4200","config":{"search":{"search_by_criteria_allowed":true,"search_multiple_allowed":false,"search_multiple_all_datasets_selected":false},"documentation":{"documentation_allowed":false}}}' --header 'Content-Type: application/json' -X POST http://localhost/instance +curl -d '{"name":"default","label":"Default instance","client_url":"http://localhost:4200","config":{"design":{"design_color":"#7AC29A"},"search":{"search_by_criteria_allowed":true,"search_multiple_allowed":false,"search_multiple_all_datasets_selected":false},"documentation":{"documentation_allowed":false}}}' --header 'Content-Type: application/json' -X POST http://localhost/instance # Add ANIS, SVOM and IRIS surveys curl -d '{"name":"anis_survey","label":"ANIS survey","description":"Survey used for testing","link":"https://anis.lam.fr","manager":"F. Agneray","id_database":1}' --header 'Content-Type: application/json' -X POST http://localhost/survey